/* Copyright (C) 2023-2025, The AROS Development Team. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log_intern.h" #include LC_LIBDEFS_FILE extern BOOL GM_UNIQUENAME(HaveDOS)(LIBBASETYPEPTR LIBBASE); extern BOOL GM_UNIQUENAME(OpenUtility)(LIBBASETYPEPTR LIBBASE); extern BOOL GM_UNIQUENAME(HaveTimer)(LIBBASETYPEPTR LIBBASE); #define DOSBase LIBBASE->lrb_DosBase #define TimerBase LIBBASE->lrb_TimerIOReq.tr_node.io_Device #define UtilityBase LIBBASE->lrb_UtilityBase #define KernelBase LIBBASE->lrb_KernelBase AROS_LH1(VOID, logLockEntries, AROS_LHA(ULONG, flags, D0), LIBBASETYPEPTR, LIBBASE, 13, log) { AROS_LIBFUNC_INIT struct ExecBase *SysBase = GM_SYSBASE_FIELD(LIBBASE); ObtainSemaphore(&LIBBASE->lrb_ReentrantLock); AROS_LIBFUNC_EXIT } AROS_LH1(VOID, logUnlockEntries, AROS_LHA(ULONG, flags, D0), LIBBASETYPEPTR, LIBBASE, 15, log) { AROS_LIBFUNC_INIT struct ExecBase *SysBase = GM_SYSBASE_FIELD(LIBBASE); ReleaseSemaphore(&LIBBASE->lrb_ReentrantLock); AROS_LIBFUNC_EXIT } AROS_LH1(APTR, logNextEntry, AROS_LHA(APTR *, entryHandle, A0), LIBBASETYPEPTR, LIBBASE, 14, log) { AROS_LIBFUNC_INIT struct logEntryPrivate *leP; struct logEntry *le; if (entryHandle) { if (*entryHandle == (APTR)LOGEntry_First) { leP = (struct logEntryPrivate *)GetHead(&LIBBASE->lrb_LRProvider.lrh_Entries); if (leP) *entryHandle = &leP->le_Node; else *entryHandle = (APTR)LOGEntry_Last; } else if (*entryHandle != (APTR)LOGEntry_Last) { le = *entryHandle; if (le->le_Node.ln_Type == NT_LOGENTRY) { leP = (struct logEntryPrivate *)((IPTR)le - offsetof(struct logEntryPrivate, le_Node)); leP = (struct logEntryPrivate *)GetSucc(leP); if (leP) *entryHandle = &leP->le_Node; else *entryHandle = (APTR)LOGEntry_Last; } else *entryHandle = (APTR)LOGEntry_Last; } else { // Return the last entry if called with LOGEntry_Last } return *entryHandle; } return NULL; AROS_LIBFUNC_EXIT } AROS_LH2(IPTR, logGetEntryAttrs, AROS_LHA(APTR, entryHandle, A0), AROS_LHA(struct TagItem *, tags, A1), LIBBASETYPEPTR, LIBBASE, 9, log) { AROS_LIBFUNC_INIT struct logEntry *le = (struct logEntry *)entryHandle; IPTR count = 0; if (le && (le->le_Node.ln_Type == NT_LOGENTRY) && (GM_UNIQUENAME(OpenUtility)(LIBBASE))) { struct logEntryPrivate *leP; struct TagItem *ti; leP = (struct logEntryPrivate *)((IPTR)le - offsetof(struct logEntryPrivate, le_Node)); if((ti = FindTagItem(LOGMA_Flags, tags))) { *((ULONG *) ti->ti_Data) = (leP->lectx_Flags & ~LOGM_Flag_PrivateMask); count++; } if((ti = FindTagItem(LOGMA_DateStamp, tags))) { *((struct DateStamp **) ti->ti_Data) = &leP->le_DateStamp; count++; } if((ti = FindTagItem(LOGMA_EventID, tags))) { *((ULONG *) ti->ti_Data) = leP->le_eid; count++; } if((ti = FindTagItem(LOGMA_Origin, tags))) { *((char**) ti->ti_Data) = leP->lectx_Originator; count++; } if((ti = FindTagItem(LOGMA_Component, tags))) { if (leP->lep_Producer) { struct LogResHandle *lrHandle = (struct LogResHandle *)leP->lep_Producer; *((char**) ti->ti_Data) = lrHandle->lrh_Node.ln_Name; count++; } } if((ti = FindTagItem(LOGMA_SubComponent, tags))) { *((char**) ti->ti_Data) = leP->lep_Node.ln_Name; count++; } if((ti = FindTagItem(LOGMA_LogTag, tags))) { *((char**) ti->ti_Data) = leP->le_Node.ln_Name; count++; } if((ti = FindTagItem(LOGMA_Entry, tags))) { *((char**) ti->ti_Data) = leP->le_Entry; count++; } } return count; AROS_LIBFUNC_EXIT } /***************************************************************************** NAME */ AROS_LH7(struct logEntry *, logAddEntryA, /* SYNOPSIS */ AROS_LHA(ULONG, flags, D0), AROS_LHA(APTR, loghandle, A0), AROS_LHA(STRPTR, sub, A1), AROS_LHA(STRPTR, src, A2), AROS_LHA(ULONG, eventid, D1), AROS_LHA(STRPTR, fmtstr, A3), AROS_LHA(RAWARG, fmtdata, A4), /* LOCATION */ LIBBASETYPEPTR, LIBBASE, 10, log) /* FUNCTION Creates and queues a new log entry associated with the given logging handle. The entry includes timestamp, event ID, optional subsystem/source strings, originator information, and a formatted message string built from 'fmtstr' and 'fmtdata'. INPUTS flags - Logging flags and priority level (LOGM_*). loghandle - Handle to an open log resource (struct LogResHandle *). sub - Optional subsystem string, may be NULL. src - Optional source string, may be NULL. eventid - User-supplied event identifier. fmtstr - Format string for the log message. fmtdata - Argument data matching the format string. RESULT Pointer to a logEntry structure if successful, or NULL if the entry could not be created. NOTES The returned logEntry is owned by log.resource and should not be modified or freed by the caller. The timestamp source depends on availability of DOS, timer.device, or kernel facilities. EXAMPLE struct logEntry *e = logAddEntryA(LOGM_Flag_Info, myLogHandle, "filesystem", "disk.device", 42, "Mounted volume %s", (RAWARG)"DH0:"); BUGS Kernel timestamp support is incomplete (marked TODO in source). SEE ALSO INTERNALS Allocates a logEntryPrivate from the handle’s pool. Uses logCopyStrFmtA() to duplicate the formatted message. Links the entry into the handle’s list unless producer is provider. Posts an EHMB_ADDENTRY message to the log resource service port. ******************************************************************************/ { AROS_LIBFUNC_INIT struct LogResHandle *lrHandle = (struct LogResHandle *)loghandle; if ((LIBBASE->lrb_Task) && (lrHandle)) { struct ExecBase *SysBase = GM_SYSBASE_FIELD(LIBBASE); struct logEntryPrivate *leP; if ((leP = AllocVecPooled(lrHandle->lrh_Pool, sizeof(struct logEntryPrivate)))) { memset(leP, 0, sizeof(struct logEntryPrivate)); leP->lep_Node.ln_Pri = (flags & LOGM_Flag_LevelMask); leP->lectx_Level = flags; leP->lep_Producer = loghandle; if((leP->le_Entry = logCopyStrFmtA(fmtstr, fmtdata))) { struct Task *thisTask = FindTask(NULL); if (sub) leP->lep_Node.ln_Name = logCopyStr(sub); if (src) leP->le_Node.ln_Name = logCopyStr(src); leP->lectx_Originator = logCopyStrFmt("0x%p %s", thisTask, ((struct Node *)thisTask)->ln_Name); leP->le_eid = eventid; if(GM_UNIQUENAME(HaveDOS)(LIBBASE)) { DateStamp(&leP->le_DateStamp); leP->lectx_Flags &= ~(LOGF_Flag_Private_STMPTimer|LOGF_Flag_Private_STMPKrn); } else if (GM_UNIQUENAME(HaveTimer)(LIBBASE)) { struct timerequest tr; CopyMem(&LIBBASE->lrb_TimerIOReq, &tr, sizeof(struct timerequest)); tr.tr_node.io_Command = TR_GETSYSTIME; DoIO((struct IORequest *) &tr); leP->le_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60); leP->le_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60; leP->le_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50; leP->lectx_Flags |= LOGF_Flag_Private_STMPTimer; } else { leP->lectx_Flags |= LOGF_Flag_Private_STMPKrn; if (KernelBase) { UQUAD stamp = KrnTimeStamp(); if (stamp != 0) { // TODO: } } } Forbid(); if (leP->lep_Producer != &LIBBASE->lrb_LRProvider) AddTail(&lrHandle->lrh_Entries, &leP->le_Node); Permit(); leP->le_Node.ln_Type = EHMB_ADDENTRY; PutMsg(LIBBASE->lrb_ServicePort, (struct Message *)leP); return((struct logEntry *)&leP->le_Node); } FreeVecPooled(lrHandle->lrh_Pool, leP); } } return(NULL); AROS_LIBFUNC_EXIT } AROS_LH1(void, logRemEntry, AROS_LHA(struct logEntry *, le, A0), LIBBASETYPEPTR, LIBBASE, 11, log) { AROS_LIBFUNC_INIT if (le) { struct ExecBase *SysBase = GM_SYSBASE_FIELD(LIBBASE); struct logEntryPrivate *leP; leP = (struct logEntryPrivate *)((IPTR)le - offsetof(struct logEntryPrivate, le_Node)); Forbid(); Remove(&leP->lep_Node); if (leP->lep_Producer != &LIBBASE->lrb_LRProvider) Remove(&leP->le_Node); Permit(); if (LIBBASE->lrb_Task) { leP->le_Node.ln_Type = EHMB_REMENTRY; PutMsg(LIBBASE->lrb_ServicePort, (struct Message *)leP); } } AROS_LIBFUNC_EXIT }