37 #define BUFFER_SIZE 1280 38 #define MAX_MESSAGE_SIZE 256 43 static void errlogExitHandler(
void *);
44 static void errlogThread(
void);
46 static char *msgbufGetFree(
int noConsoleMessage);
47 static void msgbufSetSize(
int size);
48 static char *msgbufGetSend(
int *noConsoleMessage);
49 static void msgbufFreeSend(
void);
92 static int tvsnPrint(
char *
str,
size_t size,
const char *format, va_list ap)
94 static const char tmsg[] =
"<<TRUNCATED>>\n";
98 if (size >
sizeof tmsg)
99 strcpy(str + size -
sizeof tmsg, tmsg);
114 (
"errlogPrintf called from interrupt level\n");
121 if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
124 va_start(pvar, pFormat);
125 nchar = vfprintf(console, pFormat, pvar);
133 pbuffer = msgbufGetFree(isOkToBlock);
137 va_start(pvar, pFormat);
138 nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:
"", pvar);
140 msgbufSetSize(nchar);
153 (
"errlogVprintf called from interrupt level\n");
162 pbuffer = msgbufGetFree(isOkToBlock);
164 console = pvtData.console ? pvtData.console :
stderr;
165 vfprintf(console, pFormat, pvar);
170 nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:
"", pvar);
171 if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
172 console = pvtData.console ? pvtData.console :
stderr;
173 fprintf(console,
"%s", pbuffer);
176 msgbufSetSize(nchar);
193 (
"errlogPrintfNoConsole called from interrupt level\n");
198 va_start(pvar, pFormat);
211 (
"errlogVprintfNoConsole called from interrupt level\n");
219 pbuffer = msgbufGetFree(1);
223 nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:
"", pvar);
224 msgbufSetSize(nchar);
237 (
"errlogSevPrintf called from interrupt level\n");
242 if (pvtData.sevToLog > severity)
246 if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
250 va_start(pvar, pFormat);
251 vfprintf(console, pFormat, pvar);
256 va_start(pvar, pFormat);
271 (
"errlogSevVprintf called from interrupt level\n");
280 pnext = msgbufGetFree(isOkToBlock);
285 pnext += nchar; totalChar += nchar;
286 nchar = tvsnPrint(pnext, pvtData.maxMsgSize - totalChar - 1, pFormat, pvar);
287 pnext += nchar; totalChar += nchar;
288 if (pnext[-1] !=
'\n') {
292 msgbufSetSize(totalChar);
308 pvtData.sevToLog = severity;
314 return pvtData.sevToLog;
326 "errlogAddListener");
330 ellAdd(&pvtData.listenerList,&plistenerNode->
node);
344 while (plistenerNode) {
347 if (plistenerNode->
listener == listener &&
348 plistenerNode->
pPrivate == pPrivate) {
353 plistenerNode = pnext;
363 "errlogRemoveListeners: No listeners found\n");
372 pvtData.toConsole = yesno;
379 pvtData.console = stream;
384 const char *pformat, ...)
407 if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
411 fprintf(console,
"filename=\"%s\" line number=%d\n",
414 fprintf(console,
"%s ", name);
416 va_start(pvar, pformat);
417 vfprintf(console, pformat, pvar);
419 fputc(
'\n', console);
426 pnext = msgbufGetFree(isOkToBlock);
431 nchar = sprintf(pnext,
"filename=\"%s\" line number=%d\n",
433 pnext += nchar; totalChar += nchar;
437 nchar = sprintf(pnext,
"%s ",name);
438 pnext += nchar; totalChar += nchar;
440 va_start(pvar, pformat);
441 nchar = tvsnPrint(pnext, pvtData.maxMsgSize - totalChar - 1, pformat, pvar);
449 msgbufSetSize(totalChar);
453 static void errlogExitHandler(
void *pvt)
465 static void errlogInitPvt(
void *arg)
470 pvtData.errlogInitFailed =
TRUE;
471 pvtData.buffersize = pconfig->
bufsize;
475 ellInit(&pvtData.listenerList);
477 pvtData.toConsole =
TRUE;
478 pvtData.console =
NULL;
495 pvtData.errlogInitFailed =
FALSE;
517 if (pvtData.errlogInitFailed) {
518 fprintf(
stderr,
"errlogInit failed\n");
539 count =
ellCount(&pvtData.msgQueue);
552 static void errlogThread(
void)
555 int noConsoleMessage;
561 while ((pmessage = msgbufGetSend(&noConsoleMessage))) {
563 if (pvtData.toConsole && !noConsoleMessage) {
566 fprintf(console,
"%s", pmessage);
571 while (plistenerNode) {
592 static msgNode * msgbufGetNode(
void)
594 char *
pbuffer = pvtData.pbuffer;
598 if (
ellCount(&pvtData.msgQueue) == 0 ) {
604 char *plimit = pbuffer + pvtData.buffersize;
607 if (pfirst > plast) {
608 plimit = (
char *)pfirst;
610 else if (pnextFree + pvtData.msgNeeded > plimit) {
612 plimit = (
char *)pfirst;
614 if (pnextFree + pvtData.msgNeeded > plimit) {
619 pnextSend = (
msgNode *)pnextFree;
625 static char * msgbufGetFree(
int noConsoleMessage)
632 if ((
ellCount(&pvtData.msgQueue) == 0) && pvtData.missedMessages) {
635 pnextSend = msgbufGetNode();
636 nchar = sprintf(pnextSend->
message,
637 "errlog: %d messages were discarded\n", pvtData.missedMessages);
638 pnextSend->
length = nchar + 1;
639 pvtData.missedMessages = 0;
643 pvtData.pnextSend = pnextSend = msgbufGetNode();
650 ++pvtData.missedMessages;
655 static void msgbufSetSize(
int size)
659 pnextSend->
length = size+1;
666 static char * msgbufGetSend(
int *noConsoleMessage)
680 static void msgbufFreeSend(
void)
689 fprintf(console,
"errlog: msgbufFreeSend logic error\n");
#define ellCount(PLIST)
Report the number of nodes in a list.
int errlogInit2(int bufsize, int maxMsgSize)
LIBCOM_API int epicsStdCall LIBCOM_API int epicsStdCall epicsVsnprintf(char *str, size_t size, const char *format, va_list ap)
int errlogVprintf(const char *pFormat, va_list pvar)
LIBCOM_API size_t adjustToWorstCaseAlignment(size_t size)
epicsMutexId listenerLock
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
void(* errlogListener)(void *pPrivate, const char *message)
int errlogSetConsole(FILE *stream)
LIBCOM_API epicsEventId epicsEventMustCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code.
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Miscellaneous macro definitions.
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
LIBCOM_API void epicsEventMustWait(epicsEventId id)
Wait for an event (see epicsEventWait()).
errlogSevEnum errlogGetSevToLog(void)
int errlogInit(int bufsize)
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
LIBCOM_API int epicsInterruptIsInterruptContext(void)
void errlogAddListener(errlogListener listener, void *pPrivate)
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
#define ellNext(PNODE)
Find the next node in list.
#define EPICS_THREAD_ONCE_INIT
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
int errlogSevVprintf(errlogSevEnum severity, const char *pFormat, va_list pvar)
void errPrintf(long status, const char *pFileName, int lineno, const char *pformat,...)
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
epicsMutexId msgQueueLock
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength)
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
int errlogPrintfNoConsole(const char *pFormat,...)
Declare function adjustToWorstCaseAlignment
int errlogVprintfNoConsole(const char *pFormat, va_list pvar)
#define epicsThreadPriorityLow
Extended replacement for the Posix exit and atexit routines.
LIBCOM_API void epicsInterruptContextMessage(const char *message)
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
#define ellLast(PLIST)
Find the last node in list.
int errlogPrintf(const char *pFormat,...)
APIs for the epicsEvent binary semaphore.
epicsMutexLockStatus epicsStdCall epicsMutexLock(epicsMutexId pmutexNode)
Claim the semaphore, waiting until it's free if currently owned owned by a different thread...
int errlogMessage(const char *message)
struct listenerNode listenerNode
void errlogSetSevToLog(errlogSevEnum severity)
LIBCOM_API epicsEventStatus epicsEventTryWait(epicsEventId id)
Similar to wait() except that if the event is currenly empty the call will return immediately with st...
int epicsStdCall epicsThreadIsOkToBlock(void)
#define ellInit(PLIST)
Initialize a list type.
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
#define epicsEventWaitOK
Old name provided for backwards compatibility.
epicsEventId waitForFlush
Routines for code that can't continue or return after an error.
#define epicsAtExit(F, A)
Convenience macro to register a function and context value to be run when the process exits...
int errlogRemoveListeners(errlogListener listener, void *pPrivate)
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
const char * errlogGetSevEnumString(errlogSevEnum severity)
void(* EPICSTHREADFUNC)(void *parm)
LIBCOM_API const char * errlogSevEnumString[]
int errlogSevPrintf(errlogSevEnum severity, const char *pFormat,...)
#define ellFirst(PLIST)
Find the first node in list.