This is Unofficial EPICS BASE Doxygen Site
errlog.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * Original Author: Marty Kraimer
11  * Date: 07JAN1998
12  */
13 
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <errno.h>
20 
21 #define ERRLOG_INIT
22 #include "adjustment.h"
23 #include "dbDefs.h"
24 #include "epicsThread.h"
25 #include "cantProceed.h"
26 #include "epicsMutex.h"
27 #include "epicsEvent.h"
28 #include "epicsInterrupt.h"
29 #include "errMdef.h"
30 #include "errSymTbl.h"
31 #include "ellLib.h"
32 #include "errlog.h"
33 #include "epicsStdio.h"
34 #include "epicsExit.h"
35 
36 
37 #define BUFFER_SIZE 1280
38 #define MAX_MESSAGE_SIZE 256
39 
40 /*Declare storage for errVerbose */
41 int errVerbose = 0;
42 
43 static void errlogExitHandler(void *);
44 static void errlogThread(void);
45 
46 static char *msgbufGetFree(int noConsoleMessage);
47 static void msgbufSetSize(int size); /* Send 'size' chars plus trailing '\0' */
48 static char *msgbufGetSend(int *noConsoleMessage);
49 static void msgbufFreeSend(void);
50 
51 typedef struct listenerNode{
54  void *pPrivate;
55 } listenerNode;
56 
57 /*each message consists of a msgNode immediately followed by the message */
58 typedef struct msgNode {
60  char *message;
61  int length;
63 } msgNode;
64 
65 static struct {
66  epicsEventId waitForWork; /*errlogThread waits for this*/
69  epicsEventId waitForFlush; /*errlogFlush waits for this*/
70  epicsEventId flush; /*errlogFlush sets errlogThread does a Try*/
72  epicsEventId waitForExit; /*errlogExitHandler waits for this*/
73  int atExit; /*TRUE when errlogExitHandler is active*/
80  int msgNeeded;
81  int sevToLog;
82  int toConsole;
83  FILE *console;
85  char *pbuffer;
86 } pvtData;
87 
88 
89 /*
90  * vsnprintf with truncation message
91  */
92 static int tvsnPrint(char *str, size_t size, const char *format, va_list ap)
93 {
94  static const char tmsg[] = "<<TRUNCATED>>\n";
95  int nchar = epicsVsnprintf(str, size, format ? format : "", ap);
96 
97  if (nchar >= size) {
98  if (size > sizeof tmsg)
99  strcpy(str + size - sizeof tmsg, tmsg);
100  nchar = size - 1;
101  }
102  return nchar;
103 }
104 
105 int errlogPrintf(const char *pFormat, ...)
106 {
107  va_list pvar;
108  char *pbuffer;
109  int nchar;
110  int isOkToBlock;
111 
114  ("errlogPrintf called from interrupt level\n");
115  return 0;
116  }
117 
118  errlogInit(0);
119  isOkToBlock = epicsThreadIsOkToBlock();
120 
121  if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
122  FILE *console = pvtData.console ? pvtData.console : stderr;
123 
124  va_start(pvar, pFormat);
125  nchar = vfprintf(console, pFormat, pvar);
126  va_end (pvar);
127  fflush(console);
128  }
129 
130  if (pvtData.atExit)
131  return nchar;
132 
133  pbuffer = msgbufGetFree(isOkToBlock);
134  if (!pbuffer)
135  return 0;
136 
137  va_start(pvar, pFormat);
138  nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
139  va_end(pvar);
140  msgbufSetSize(nchar);
141  return nchar;
142 }
143 
144 int errlogVprintf(const char *pFormat,va_list pvar)
145 {
146  int nchar;
147  char *pbuffer;
148  int isOkToBlock;
149  FILE *console;
150 
153  ("errlogVprintf called from interrupt level\n");
154  return 0;
155  }
156 
157  errlogInit(0);
158  if (pvtData.atExit)
159  return 0;
160  isOkToBlock = epicsThreadIsOkToBlock();
161 
162  pbuffer = msgbufGetFree(isOkToBlock);
163  if (!pbuffer) {
164  console = pvtData.console ? pvtData.console : stderr;
165  vfprintf(console, pFormat, pvar);
166  fflush(console);
167  return 0;
168  }
169 
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);
174  fflush(console);
175  }
176  msgbufSetSize(nchar);
177  return nchar;
178 }
179 
180 int errlogMessage(const char *message)
181 {
182  errlogPrintf("%s", message);
183  return 0;
184 }
185 
186 int errlogPrintfNoConsole(const char *pFormat, ...)
187 {
188  va_list pvar;
189  int nchar;
190 
193  ("errlogPrintfNoConsole called from interrupt level\n");
194  return 0;
195  }
196 
197  errlogInit(0);
198  va_start(pvar, pFormat);
199  nchar = errlogVprintfNoConsole(pFormat, pvar);
200  va_end(pvar);
201  return nchar;
202 }
203 
204 int errlogVprintfNoConsole(const char *pFormat, va_list pvar)
205 {
206  int nchar;
207  char *pbuffer;
208 
211  ("errlogVprintfNoConsole called from interrupt level\n");
212  return 0;
213  }
214 
215  errlogInit(0);
216  if (pvtData.atExit)
217  return 0;
218 
219  pbuffer = msgbufGetFree(1);
220  if (!pbuffer)
221  return 0;
222 
223  nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
224  msgbufSetSize(nchar);
225  return nchar;
226 }
227 
228 
229 int errlogSevPrintf(errlogSevEnum severity, const char *pFormat, ...)
230 {
231  va_list pvar;
232  int nchar;
233  int isOkToBlock;
234 
237  ("errlogSevPrintf called from interrupt level\n");
238  return 0;
239  }
240 
241  errlogInit(0);
242  if (pvtData.sevToLog > severity)
243  return 0;
244 
245  isOkToBlock = epicsThreadIsOkToBlock();
246  if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
247  FILE *console = pvtData.console ? pvtData.console : stderr;
248 
249  fprintf(console, "sevr=%s ", errlogGetSevEnumString(severity));
250  va_start(pvar, pFormat);
251  vfprintf(console, pFormat, pvar);
252  va_end(pvar);
253  fflush(console);
254  }
255 
256  va_start(pvar, pFormat);
257  nchar = errlogSevVprintf(severity, pFormat, pvar);
258  va_end(pvar);
259  return nchar;
260 }
261 
262 int errlogSevVprintf(errlogSevEnum severity, const char *pFormat, va_list pvar)
263 {
264  char *pnext;
265  int nchar;
266  int totalChar = 0;
267  int isOkToBlock;
268 
271  ("errlogSevVprintf called from interrupt level\n");
272  return 0;
273  }
274 
275  errlogInit(0);
276  if (pvtData.atExit)
277  return 0;
278 
279  isOkToBlock = epicsThreadIsOkToBlock();
280  pnext = msgbufGetFree(isOkToBlock);
281  if (!pnext)
282  return 0;
283 
284  nchar = sprintf(pnext, "sevr=%s ", errlogGetSevEnumString(severity));
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') {
289  strcpy(pnext,"\n");
290  totalChar++;
291  }
292  msgbufSetSize(totalChar);
293  return nchar;
294 }
295 
296 
297 const char * errlogGetSevEnumString(errlogSevEnum severity)
298 {
299  errlogInit(0);
300  if (severity > 3)
301  return "unknown";
302  return errlogSevEnumString[severity];
303 }
304 
306 {
307  errlogInit(0);
308  pvtData.sevToLog = severity;
309 }
310 
312 {
313  errlogInit(0);
314  return pvtData.sevToLog;
315 }
316 
318 {
319  listenerNode *plistenerNode;
320 
321  errlogInit(0);
322  if (pvtData.atExit)
323  return;
324 
325  plistenerNode = callocMustSucceed(1,sizeof(listenerNode),
326  "errlogAddListener");
327  epicsMutexMustLock(pvtData.listenerLock);
328  plistenerNode->listener = listener;
329  plistenerNode->pPrivate = pPrivate;
330  ellAdd(&pvtData.listenerList,&plistenerNode->node);
331  epicsMutexUnlock(pvtData.listenerLock);
332 }
333 
335 {
336  listenerNode *plistenerNode;
337  int count = 0;
338 
339  errlogInit(0);
340  if (!pvtData.atExit)
341  epicsMutexMustLock(pvtData.listenerLock);
342 
343  plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
344  while (plistenerNode) {
345  listenerNode *pnext = (listenerNode *)ellNext(&plistenerNode->node);
346 
347  if (plistenerNode->listener == listener &&
348  plistenerNode->pPrivate == pPrivate) {
349  ellDelete(&pvtData.listenerList, &plistenerNode->node);
350  free(plistenerNode);
351  ++count;
352  }
353  plistenerNode = pnext;
354  }
355 
356  if (!pvtData.atExit)
357  epicsMutexUnlock(pvtData.listenerLock);
358 
359  if (count == 0) {
360  FILE *console = pvtData.console ? pvtData.console : stderr;
361 
362  fprintf(console,
363  "errlogRemoveListeners: No listeners found\n");
364  }
365  return count;
366 }
367 
368 int eltc(int yesno)
369 {
370  errlogInit(0);
371  errlogFlush();
372  pvtData.toConsole = yesno;
373  return 0;
374 }
375 
376 int errlogSetConsole(FILE *stream)
377 {
378  errlogInit(0);
379  pvtData.console = stream;
380  return 0;
381 }
382 
383 void errPrintf(long status, const char *pFileName, int lineno,
384  const char *pformat, ...)
385 {
386  va_list pvar;
387  char *pnext;
388  int nchar;
389  int totalChar=0;
390  int isOkToBlock;
391  char name[256];
392 
394  epicsInterruptContextMessage("errPrintf called from interrupt level\n");
395  return;
396  }
397 
398  errlogInit(0);
399  isOkToBlock = epicsThreadIsOkToBlock();
400  if (status == 0)
401  status = errno;
402 
403  if (status > 0) {
404  errSymLookup(status, name, sizeof(name));
405  }
406 
407  if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
408  FILE *console = pvtData.console ? pvtData.console : stderr;
409 
410  if (pFileName)
411  fprintf(console, "filename=\"%s\" line number=%d\n",
412  pFileName, lineno);
413  if (status > 0)
414  fprintf(console, "%s ", name);
415 
416  va_start(pvar, pformat);
417  vfprintf(console, pformat, pvar);
418  va_end(pvar);
419  fputc('\n', console);
420  fflush(console);
421  }
422 
423  if (pvtData.atExit)
424  return;
425 
426  pnext = msgbufGetFree(isOkToBlock);
427  if (!pnext)
428  return;
429 
430  if (pFileName) {
431  nchar = sprintf(pnext,"filename=\"%s\" line number=%d\n",
432  pFileName, lineno);
433  pnext += nchar; totalChar += nchar;
434  }
435 
436  if (status > 0) {
437  nchar = sprintf(pnext,"%s ",name);
438  pnext += nchar; totalChar += nchar;
439  }
440  va_start(pvar, pformat);
441  nchar = tvsnPrint(pnext, pvtData.maxMsgSize - totalChar - 1, pformat, pvar);
442  va_end(pvar);
443  if (nchar>0) {
444  pnext += nchar;
445  totalChar += nchar;
446  }
447  strcpy(pnext, "\n");
448  totalChar++ ; /*include the \n */
449  msgbufSetSize(totalChar);
450 }
451 
452 
453 static void errlogExitHandler(void *pvt)
454 {
455  pvtData.atExit = 1;
456  epicsEventSignal(pvtData.waitForWork);
457  epicsEventMustWait(pvtData.waitForExit);
458 }
459 
460 struct initArgs {
461  int bufsize;
463 };
464 
465 static void errlogInitPvt(void *arg)
466 {
467  struct initArgs *pconfig = (struct initArgs *) arg;
468  epicsThreadId tid;
469 
470  pvtData.errlogInitFailed = TRUE;
471  pvtData.buffersize = pconfig->bufsize;
472  pvtData.maxMsgSize = pconfig->maxMsgSize;
473  pvtData.msgNeeded = adjustToWorstCaseAlignment(pvtData.maxMsgSize +
474  sizeof(msgNode));
475  ellInit(&pvtData.listenerList);
476  ellInit(&pvtData.msgQueue);
477  pvtData.toConsole = TRUE;
478  pvtData.console = NULL;
479  pvtData.waitForWork = epicsEventMustCreate(epicsEventEmpty);
480  pvtData.listenerLock = epicsMutexMustCreate();
481  pvtData.msgQueueLock = epicsMutexMustCreate();
482  pvtData.waitForFlush = epicsEventMustCreate(epicsEventEmpty);
483  pvtData.flush = epicsEventMustCreate(epicsEventEmpty);
484  pvtData.flushLock = epicsMutexMustCreate();
485  pvtData.waitForExit = epicsEventMustCreate(epicsEventEmpty);
486  pvtData.pbuffer = callocMustSucceed(1, pvtData.buffersize,
487  "errlogInitPvt");
488 
489  errSymBld(); /* Better not to do this lazily... */
490 
493  (EPICSTHREADFUNC)errlogThread, 0);
494  if (tid) {
495  pvtData.errlogInitFailed = FALSE;
496  }
497 }
498 
499 
501 {
502  static epicsThreadOnceId errlogOnceFlag = EPICS_THREAD_ONCE_INIT;
503  struct initArgs config;
504 
505  if (pvtData.atExit)
506  return 0;
507 
508  if (bufsize < BUFFER_SIZE)
509  bufsize = BUFFER_SIZE;
510  config.bufsize = bufsize;
511 
512  if (maxMsgSize < MAX_MESSAGE_SIZE)
513  maxMsgSize = MAX_MESSAGE_SIZE;
514  config.maxMsgSize = maxMsgSize;
515 
516  epicsThreadOnce(&errlogOnceFlag, errlogInitPvt, &config);
517  if (pvtData.errlogInitFailed) {
518  fprintf(stderr,"errlogInit failed\n");
519  exit(1);
520  }
521  return 0;
522 }
523 
525 {
526  return errlogInit2(bufsize, MAX_MESSAGE_SIZE);
527 }
528 
529 void errlogFlush(void)
530 {
531  int count;
532 
533  errlogInit(0);
534  if (pvtData.atExit)
535  return;
536 
537  /*If nothing in queue dont wake up errlogThread*/
538  epicsMutexMustLock(pvtData.msgQueueLock);
539  count = ellCount(&pvtData.msgQueue);
540  epicsMutexUnlock(pvtData.msgQueueLock);
541  if (count <= 0)
542  return;
543 
544  /*must let errlogThread empty queue*/
545  epicsMutexMustLock(pvtData.flushLock);
546  epicsEventSignal(pvtData.flush);
547  epicsEventSignal(pvtData.waitForWork);
548  epicsEventMustWait(pvtData.waitForFlush);
549  epicsMutexUnlock(pvtData.flushLock);
550 }
551 
552 static void errlogThread(void)
553 {
554  listenerNode *plistenerNode;
555  int noConsoleMessage;
556  char *pmessage;
557 
558  epicsAtExit(errlogExitHandler,0);
559  while (TRUE) {
560  epicsEventMustWait(pvtData.waitForWork);
561  while ((pmessage = msgbufGetSend(&noConsoleMessage))) {
562  epicsMutexMustLock(pvtData.listenerLock);
563  if (pvtData.toConsole && !noConsoleMessage) {
564  FILE *console = pvtData.console ? pvtData.console : stderr;
565 
566  fprintf(console, "%s", pmessage);
567  fflush(console);
568  }
569 
570  plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
571  while (plistenerNode) {
572  (*plistenerNode->listener)(plistenerNode->pPrivate, pmessage);
573  plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
574  }
575 
576  epicsMutexUnlock(pvtData.listenerLock);
577  msgbufFreeSend();
578  }
579 
580  if (pvtData.atExit)
581  break;
582  if (epicsEventTryWait(pvtData.flush) != epicsEventWaitOK)
583  continue;
584 
585  epicsThreadSleep(.2); /*just wait an extra .2 seconds*/
586  epicsEventSignal(pvtData.waitForFlush);
587  }
588  epicsEventSignal(pvtData.waitForExit);
589 }
590 
591 
592 static msgNode * msgbufGetNode(void)
593 {
594  char *pbuffer = pvtData.pbuffer;
595  char *pnextFree;
597 
598  if (ellCount(&pvtData.msgQueue) == 0 ) {
599  pnextFree = pbuffer; /* Reset if empty */
600  }
601  else {
602  msgNode *pfirst = (msgNode *)ellFirst(&pvtData.msgQueue);
603  msgNode *plast = (msgNode *)ellLast(&pvtData.msgQueue);
604  char *plimit = pbuffer + pvtData.buffersize;
605 
606  pnextFree = plast->message + adjustToWorstCaseAlignment(plast->length);
607  if (pfirst > plast) {
608  plimit = (char *)pfirst;
609  }
610  else if (pnextFree + pvtData.msgNeeded > plimit) {
611  pnextFree = pbuffer; /* Hit end, wrap to start */
612  plimit = (char *)pfirst;
613  }
614  if (pnextFree + pvtData.msgNeeded > plimit) {
615  return 0; /* No room */
616  }
617  }
618 
619  pnextSend = (msgNode *)pnextFree;
620  pnextSend->message = pnextFree + sizeof(msgNode);
621  pnextSend->length = 0;
622  return pnextSend;
623 }
624 
625 static char * msgbufGetFree(int noConsoleMessage)
626 {
628 
629  if (epicsMutexLock(pvtData.msgQueueLock) != epicsMutexLockOK)
630  return 0;
631 
632  if ((ellCount(&pvtData.msgQueue) == 0) && pvtData.missedMessages) {
633  int nchar;
634 
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;
640  ellAdd(&pvtData.msgQueue, &pnextSend->node);
641  }
642 
643  pvtData.pnextSend = pnextSend = msgbufGetNode();
644  if (pnextSend) {
645  pnextSend->noConsoleMessage = noConsoleMessage;
646  pnextSend->length = 0;
647  return pnextSend->message; /* NB: msgQueueLock is still locked */
648  }
649 
650  ++pvtData.missedMessages;
651  epicsMutexUnlock(pvtData.msgQueueLock);
652  return 0;
653 }
654 
655 static void msgbufSetSize(int size)
656 {
657  msgNode *pnextSend = pvtData.pnextSend;
658 
659  pnextSend->length = size+1;
660  ellAdd(&pvtData.msgQueue, &pnextSend->node);
661  epicsMutexUnlock(pvtData.msgQueueLock);
662  epicsEventSignal(pvtData.waitForWork);
663 }
664 
665 
666 static char * msgbufGetSend(int *noConsoleMessage)
667 {
669 
670  epicsMutexMustLock(pvtData.msgQueueLock);
671  pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
672  epicsMutexUnlock(pvtData.msgQueueLock);
673  if (!pnextSend)
674  return 0;
675 
676  *noConsoleMessage = pnextSend->noConsoleMessage;
677  return pnextSend->message;
678 }
679 
680 static void msgbufFreeSend(void)
681 {
683 
684  epicsMutexMustLock(pvtData.msgQueueLock);
685  pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
686  if (!pnextSend) {
687  FILE *console = pvtData.console ? pvtData.console : stderr;
688 
689  fprintf(console, "errlog: msgbufFreeSend logic error\n");
691  }
692  ellDelete(&pvtData.msgQueue, &pnextSend->node);
693  epicsMutexUnlock(pvtData.msgQueueLock);
694 }
void errlogFlush(void)
Definition: errlog.c:529
int sevToLog
Definition: errlog.c:81
#define FALSE
Definition: dbDefs.h:32
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
int errlogInit2(int bufsize, int maxMsgSize)
Definition: errlog.c:500
msgNode * pnextSend
Definition: errlog.c:76
pvd::Status status
int lineno
Definition: antelope.c:33
LIBCOM_API int epicsStdCall LIBCOM_API int epicsStdCall epicsVsnprintf(char *str, size_t size, const char *format, va_list ap)
Definition: osdStdio.c:26
int errlogVprintf(const char *pFormat, va_list pvar)
Definition: errlog.c:144
ELLNODE node
Definition: errlog.c:52
errlogSevEnum
Definition: errlog.h:26
LIBCOM_API size_t adjustToWorstCaseAlignment(size_t size)
Definition: adjustment.c:25
int maxMsgSize
Definition: errlog.c:462
epicsMutexId listenerLock
Definition: errlog.c:68
int errlogInitFailed
Definition: errlog.c:77
epicsMutexId flushLock
Definition: errlog.c:71
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
#define NULL
Definition: catime.c:38
void * pPrivate
Definition: errlog.c:54
int bufsize
Definition: errlog.c:461
void(* errlogListener)(void *pPrivate, const char *message)
Definition: errlog.h:24
int toConsole
Definition: errlog.c:82
int errlogSetConsole(FILE *stream)
Definition: errlog.c:376
#define str(v)
#define MAX_MESSAGE_SIZE
Definition: errlog.c:38
LIBCOM_API epicsEventId epicsEventMustCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code.
Definition: epicsEvent.cpp:106
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
Miscellaneous macro definitions.
#define BUFFER_SIZE
Definition: errlog.c:37
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
LIBCOM_API void epicsEventMustWait(epicsEventId id)
Wait for an event (see epicsEventWait()).
Definition: epicsEvent.cpp:123
errlogSevEnum errlogGetSevToLog(void)
Definition: errlog.c:311
int errlogInit(int bufsize)
Definition: errlog.c:524
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
int missedMessages
Definition: errlog.c:84
LIBCOM_API int epicsInterruptIsInterruptContext(void)
Definition: osdInterrupt.c:48
void errlogAddListener(errlogListener listener, void *pPrivate)
Definition: errlog.c:317
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
int length
Definition: errlog.c:61
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
int maxMsgSize
Definition: errlog.c:79
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Definition: osdThread.c:664
int errlogSevVprintf(errlogSevEnum severity, const char *pFormat, va_list pvar)
Definition: errlog.c:262
void errPrintf(long status, const char *pFileName, int lineno, const char *pformat,...)
Definition: errlog.c:383
char * message
Definition: errlog.c:60
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
epicsMutexId msgQueueLock
Definition: errlog.c:67
ELLLIST msgQueue
Definition: errlog.c:75
int errVerbose
Definition: errlog.c:41
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength)
Definition: errSymLib.c:190
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
int errlogPrintfNoConsole(const char *pFormat,...)
Definition: errlog.c:186
FILE * console
Definition: errlog.c:83
Declare function adjustToWorstCaseAlignment
int errlogVprintfNoConsole(const char *pFormat, va_list pvar)
Definition: errlog.c:204
#define epicsThreadPriorityLow
Definition: epicsThread.h:75
Extended replacement for the Posix exit and atexit routines.
ELLLIST listenerList
Definition: errlog.c:74
ELLNODE node
Definition: errlog.c:59
int eltc(int yesno)
Definition: errlog.c:368
LIBCOM_API void epicsInterruptContextMessage(const char *message)
Definition: osdInterrupt.c:53
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
#define ellLast(PLIST)
Find the last node in list.
Definition: ellLib.h:94
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
errlogListener listener
Definition: errlog.c:53
List node type.
Definition: ellLib.h:45
APIs for the epicsEvent binary semaphore.
char * pbuffer
Definition: errlog.c:85
int errSymBld(void)
Definition: errSymLib.c:55
epicsEventId waitForExit
Definition: errlog.c:72
epicsMutexLockStatus epicsStdCall epicsMutexLock(epicsMutexId pmutexNode)
Claim the semaphore, waiting until it&#39;s free if currently owned owned by a different thread...
Definition: epicsMutex.cpp:145
int errlogMessage(const char *message)
Definition: errlog.c:180
struct listenerNode listenerNode
void errlogSetSevToLog(errlogSevEnum severity)
Definition: errlog.c:305
LIBCOM_API epicsEventStatus epicsEventTryWait(epicsEventId id)
Similar to wait() except that if the event is currenly empty the call will return immediately with st...
Definition: osdEvent.c:145
epicsEventId waitForWork
Definition: errlog.c:66
int epicsStdCall epicsThreadIsOkToBlock(void)
int buffersize
Definition: errlog.c:78
#define TRUE
Definition: dbDefs.h:27
epicsEventId flush
Definition: errlog.c:70
Definition: errlog.c:58
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
int atExit
Definition: errlog.c:73
#define epicsEventWaitOK
Old name provided for backwards compatibility.
Definition: epicsEvent.h:58
epicsEventId waitForFlush
Definition: errlog.c:69
struct msgNode msgNode
Routines for code that can&#39;t continue or return after an error.
#define stderr
Definition: epicsStdio.h:32
#define epicsAtExit(F, A)
Convenience macro to register a function and context value to be run when the process exits...
Definition: epicsExit.h:70
List header type.
Definition: ellLib.h:56
int errlogRemoveListeners(errlogListener listener, void *pPrivate)
Definition: errlog.c:334
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
const char * errlogGetSevEnumString(errlogSevEnum severity)
Definition: errlog.c:297
void(* EPICSTHREADFUNC)(void *parm)
Definition: epicsThread.h:66
int msgNeeded
Definition: errlog.c:80
int noConsoleMessage
Definition: errlog.c:62
LIBCOM_API const char * errlogSevEnumString[]
int errlogSevPrintf(errlogSevEnum severity, const char *pFormat,...)
Definition: errlog.c:229
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89