New errlog facility. Replaces old epicsPrintf stuff

This commit is contained in:
Marty Kraimer
1998-01-20 21:42:46 +00:00
parent 30d8a2d528
commit 5415d39249
12 changed files with 1502 additions and 92 deletions

View File

@@ -14,6 +14,7 @@ INC += cvtFast.h
INC += ellLib.h
INC += envDefs.h
INC += epicsAssert.h
INC += errlog.h
INC += epicsPrint.h
INC += errMdef.h
INC += error.h
@@ -28,12 +29,12 @@ INC += fdManager.h
INC += osiTime.h
INC += osiTimer.h
INC += macLib.h
INC += impLib.h
INC += sigPipeIgnore.h
INC += dbmf.h
INC += ipAddrToA.h
INC += epicsString.h
INC += truncateFile.h
INC += adjustment.h
# For WIN32 we supply getopt as part of libCom:
INC_WIN32 := getopt.h
@@ -50,7 +51,7 @@ LIBSRCS += cvtFast.c
LIBSRCS += ellLib.c
LIBSRCS += envSubr.c
LIBSRCS += envData.c
LIBSRCS += errPrintfUNIX.c
LIBSRCS += errlogUNIX.c
LIBSRCS += errSymLib.c
LIBSRCS += errSymTbl.c
LIBSRCS += fdmgr.c
@@ -62,7 +63,6 @@ LIBSRCS += postfix.c
LIBSRCS += realpath.c
LIBSRCS += tsSubr.c
LIBSRCS += assertUNIX.c
LIBSRCS += impLib.c
LIBSRCS += macCore.c
LIBSRCS += macUtil.c
LIBSRCS += sigPipeIgnore.c
@@ -71,6 +71,7 @@ LIBSRCS += ipAddrToA.c
LIBSRCS += epicsString.c
LIBSRCS += truncateFile.c
LIBSRCS += aToIPAddr.c
LIBSRCS += adjustment.c
#
# if CPLUSPLUS isnt empty then include C++ src codes
@@ -103,7 +104,6 @@ PROD_LIBS = Com
#TESTPROD=tsTest
#TESTPROD=envtest
#TESTPROD=osiTimeTest fdManagerTest
PROD = impExpand
MAN3 = gpHash.3 freeList.3

View File

@@ -21,7 +21,7 @@ SRCS.c += ../tsSubr.c
SRCS.c += ../pal.c
SRCS.c += ../paldef.c
SRCS.c += errSymTbl.c
SRCS.c += ../errPrintfVX.c
SRCS.c += ../errlogVX.c
SRCS.c += ../assertVX.c
SRCS.c += ../macCore.c
SRCS.c += ../macUtil.c
@@ -29,10 +29,10 @@ SRCS.c += ../macUtil.c
#SRCS.c += ../os/vxWorks/osdTime.cc
SRCS.c += ../os/vxWorks/ipAddrToA.c
SRCS.c += ../os/vxWorks/sigPipeIgnore.c
SRCS.c += ../impLib.c
SRCS.c += ../dbmf.c
SRCS.c += ../epicsString.c
SRCS.c += ../aToIPAddr.c
SRCS.c += ../adjustment.c
LIBOBJS += calcPerform.o
LIBOBJS += cvtFast.o
@@ -49,7 +49,7 @@ LIBOBJS += gpHashLib.o
LIBOBJS += freeListLib.o
LIBOBJS += pal.o
LIBOBJS += paldef.o
LIBOBJS += errPrintfVX.o
LIBOBJS += errlogVX.o
LIBOBJS += assertVX.o
LIBOBJS += macCore.o
LIBOBJS += macUtil.o
@@ -57,10 +57,10 @@ LIBOBJS += macUtil.o
#LIBOBJS += osdTime.o
LIBOBJS += ipAddrToA.o
LIBOBJS += sigPipeIgnore.o
LIBOBJS += impLib.o
LIBOBJS += dbmf.o
LIBOBJS += epicsString.o
LIBOBJS += aToIPAddr.o
LIBOBJS += adjustment.o
LIBNAME = libCom

View File

@@ -1,34 +1,9 @@
/*epicsPrint.h */
#ifdef __cplusplus
extern "C" {
#define epicsPrintUseProtoANSI
#endif
/*This is now obsolete. Remlaced by errlog.h */
#ifndef INCepicsPrintH
#define INCepicsPrintH
#ifdef __STDC__
#ifndef epicsPrintUseProtoANSI
#define epicsPrintUseProtoANSI
#endif
#endif
#ifdef vxWorks
# ifdef epicsPrintUseProtoANSI
# include <stdarg.h>
int epicsPrintf(const char *pFormat, ...);
int epicsVprintf (const char *pFormat, va_list pvar);
int iocLogVPrintf(const char *pFormat, va_list pvar);
int iocLogPrintf(const char *pFormat, ...);
# else /* not epicsPrintUseProtoANSI */
int epicsPrintf();
int epicsVprintf ();
int iocLogVPrintf();
int iocLogPrintf();
# endif /* ifdef epicsPrintUseProtoANSI */
#else /* not vxWorks */
# define epicsPrintf printf
# define epicsVprintf vprintf
#endif /* ifdef vxWorks */
#ifdef __cplusplus
}
#endif
#include "errlog.h"
#endif /*INCepicsPrintH*/

View File

@@ -61,6 +61,10 @@ extern "C" {
#include "ellLib.h"
#include "shareLib.h"
/*The following is only included because before 3.13.0beta12 errMessage */
/*and errPrintf were defined here */
#include "errlog.h"
#define RTN_SUCCESS(STATUS) ((STATUS)==0)
#define M_dbAccess (501 <<16) /*Database Access Routines */
@@ -88,13 +92,6 @@ extern "C" {
#define M_bucket (525 <<16) /*Bucket Hash*/
#define M_gddFuncTbl (526 <<16) /*gdd jump table*/
/*
* redefine errMessage with a macro so we can print
* the file and line number
*/
#define errMessage(S, PM) \
errPrintf(S, __FILE__, __LINE__, PM)
#ifdef errMDefUseProtoANSI
epicsShareFunc int epicsShareAPI errSymFind(long status, char *name);
epicsShareFunc int epicsShareAPI UnixSymFind(long status, char *name, long *value);
@@ -103,11 +100,8 @@ epicsShareFunc void epicsShareAPI errSymTest(unsigned short modnum, unsigned sho
epicsShareFunc void epicsShareAPI errSymTestPrint(long errNum);
epicsShareFunc int epicsShareAPI errSymBld();
epicsShareFunc int epicsShareAPI errSymbolAdd (long errNum,char *name);
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...);
epicsShareFunc void epicsShareAPI errSymDump();
epicsShareFunc void epicsShareAPI tstErrSymFind();
epicsShareFunc void epicsShareAPI errInit(void);
#else /* errMDefUseProtoANSI */
@@ -118,7 +112,6 @@ epicsShareFunc int epicsShareAPI ModSymFind();
epicsShareFunc void epicsShareAPI errSymTestPrint();
epicsShareFunc int epicsShareAPI errSymBld();
epicsShareFunc int epicsShareAPI errSymbolAdd();
epicsShareFunc void epicsShareAPI errPrintf();
epicsShareFunc void epicsShareAPI errSymDump();
epicsShareFunc void epicsShareAPI tstErrSymFind();
#endif /* errMDefUseProtoANSI */

95
src/libCom/errlog.h Normal file
View File

@@ -0,0 +1,95 @@
/* src/libCom/errlog.h */
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
This software was developed under a United States Government license
described on the COPYRIGHT_UniversityOfChicago file included as part
of this distribution.
**********************************************************************/
#ifndef INCerrlogh
#define INCerrlogh
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#define epicsPrintUseProtoANSI
#endif
#ifdef __STDC__
#ifndef epicsPrintUseProtoANSI
#define epicsPrintUseProtoANSI
#endif
#endif
/* define errMessage with a macro so we can print the file and line number*/
#define errMessage(S, PM) \
errPrintf(S, __FILE__, __LINE__, PM)
/* epicsPrintf and epicsVprintf old versions of errlog routines*/
#define epicsPrintf errlogPrintf
#define epicsVprintf errlogVprintf
typedef void(*errlogListener) (const char *message);
typedef enum {errlogInfo,errlogMinor,errlogMajor,errlogFatal} errlogSevEnum;
extern char * errlogSevEnumString[];
#ifdef ERRLOG_INIT
char * errlogSevEnumString[] = {"info","minor","major","fatal"};
#endif
#ifdef epicsPrintUseProtoANSI
epicsShareFunc int epicsShareAPI errlogPrintf(
const char *pformat, ...);
epicsShareFunc int epicsShareAPI errlogVprintf(
const char *pformat,va_list pvar);
epicsShareFunc int epicsShareAPI errlogSevPrintf(
const errlogSevEnum severity,const char *pformat, ...);
epicsShareFunc int epicsShareAPI errlogSevVprintf(
const errlogSevEnum severity,const char *pformat,va_list pvar);
epicsShareFunc int epicsShareAPI errlogMessage(
const char *message);
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString(
const errlogSevEnum severity);
epicsShareFunc void epicsShareAPI errlogSetSevToLog(
const errlogSevEnum severity );
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog(void);
epicsShareFunc void epicsShareAPI errlogAddListener(
errlogListener listener);
epicsShareFunc void epicsShareAPI errlogRemoveListener(
errlogListener listener);
epicsShareFunc void epicsShareAPI eltc(int yesno);
epicsShareFunc void epicsShareAPI errlogInit(int bufsize);
/*other routines that write to log file*/
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...);
#else /* not epicsPrintUseProtoANSI */
epicsShareFunc int epicsShareAPI errlogPrintf();
epicsShareFunc int epicsShareAPI errlogVprintf();
epicsShareFunc int epicsShareAPI errlogSevPrintf();
epicsShareFunc int epicsShareAPI errlogSevVprintf();
epicsShareFunc int epicsShareAPI errlogMessage();
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString();
epicsShareFunc void epicsShareAPI errlogSetSevToLog();
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog();
epicsShareFunc void epicsShareAPI errlogAddListener();
epicsShareFunc void epicsShareAPI errlogRemoveListener();
epicsShareFunc void epicsShareAPI eltc();
epicsShareFunc void epicsShareAPI errlogInit();
epicsShareFunc void epicsShareAPI errPrintf();
#endif /* ifdef epicsPrintUseProtoANSI */
#ifdef __cplusplus
}
#endif
#endif /*INCerrlogh*/

152
src/libCom/errlog.html Normal file
View File

@@ -0,0 +1,152 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="GENERATOR" CONTENT="Mozilla/4.03 [en] (X11; U; SunOS 5.5.1 sun4u) [Netscape]">
</HEAD>
<BODY>
<H1>
Error Logging System</H1>
The error logging system provides:
<UL>
<LI>
Error message routines that can be called by&nbsp; ioc code.</LI>
<LI>
Provision for multiple system wide error loggers..</LI>
<LI>
A task (errlog) that handles the messages generated by the client routines.
It displays messages on the target console and also gives them to any registered
system wide error loggers.</LI>
<LI>
iocLog: A system wide error logger that writes all error message to a file.</LI>
</UL>
<H2>
Overview</H2>
<UL>
<LI>
The error message routines can be called by any non-interrupt level code.</LI>
<LI>
Task errlog manages the messages. Messages are placed in a message queue,
which is read by the errlog task. The message queue uses a fixed block
of memory to hold all messages. When the message queue is full additional
messages are rejected but a count of missed messages is kept. The next
time the message queue empties an extra message about the missed messages
is generated.</LI>
<LI>
The maximum message size&nbsp; is 256&nbsp; characters. If a message is
longer, the message is truncated and a message explaining that it was truncated
is appended. There is a chance that long messages corrupt memory. This&nbsp;
only happens if client code is defective. Long messages most likely result
from "%s" formats with a bad string argument.</LI>
<LI>
The error message routines are partially implemented on the host. The host
version just calls fprintf or vfprintf instead of using a separate task
and a message queue. Thus host messages are NOT sent to a system wide error
logger.</LI>
</UL>
<H2>
Client Routines</H2>
<I>Basic Routines</I>
<UL>
<PRE>typedef enum {
&nbsp;&nbsp;&nbsp; errlogInfo,errlogMinor,errlogMajor,errlogFatal
}errlogSevEnum;
int errlogPrintf(const char *pformat, ...);
int errlogVprintf(const char *pformat,va_list pvar);
int errlogSevPrintf(const errlogSevEnum severity,
&nbsp;&nbsp;&nbsp; const char *pformat, ...);
int errlogSevVprintf(const errlogSevEnum severity,
&nbsp;&nbsp;&nbsp; const char *pformat,va_list pvar);
int errlogMessage( const char *message);
char * errlogGetSevEnumString(const errlogSevEnum severity);
void errlogSetSevToLog(const errlogSevEnum severity );
errlogSevEnum errlogGetSevToLog(void);</PRE>
These are the basic client routines.
<P>errlogPrintf and errlogVprintf act just like printf and vprintf.
<P>errlogSevPrintf and errlogSevVprintf are similar except that they also
add the severity to the beginning of the message in the form "sevr=&lt;value>"
where value is on of "info, minor, major, fatal". Also the message is suppressed
if&nbsp; severity is less than the current severity to suppress.
<P>errlogMessage just logs message.
<P>errlogGetSevEnumString gets the string value of severity.
<P>errlogSetSevToLog sets the severity to log. errlogGetSevToLog gets the
current severity to log.</UL>
<I>Status Routines</I>
<BR>&nbsp;
<UL>
<PRE>void errMessage(long status, char *message);</PRE>
<PRE>void errPrintf(long status, const char *pFileName,
&nbsp;&nbsp;&nbsp; int lineno, const char *pformat, ...);</PRE>
errMessage is just a macro that calls errPrintf. errPrintf is meant to
be called as follows:
<PRE>&nbsp;errPrintf(status,__FILE__, __LINE__,"&lt;format>",...)</PRE>
&nbsp;The argument status is described in the Application Developer's guide.
The arguments __FILE__ and&nbsp; __LINE__ are standard C preprocessor variables.
<BR>&nbsp;</UL>
<I>Obsolete Routines</I>
<UL>
<PRE>int epicsPrintf(const char *pformat, ...);
int epicsVprintf(const char *pformat,va_list pvar);</PRE>
These are exactly like errlogPrintf and errlogVprintf. They are provided
because a lot of existing code calls them,.&nbsp;</UL>
<I>Add and Remove Log Listener</I>
<UL>
<PRE>typedef void(*errlogListener) (const char *message);
void errlogAddListener(errlogListener listener);
void errlogRemoveListener(errlogListener listener);</PRE>
These routines add/remove a callback that receives each error message.
<BR>&nbsp;</UL>
<I>target console routines</I>
<UL>
<PRE>void eltc(int yesno); /* error log to console (0 or 1) */
void errlogInit(int bufsize);</PRE>
</UL>
eltc determines if errlog task writes message to the console. If error
messages storms are occuring the command can be used to suppress the messages.
A argument of 0 suppresses the messages and any other value lets the message
go to the console.
<P>errlogInit can be used to initialize the error logging system with a
larger buffer. The default is 1280 bytes. An extra MAX_MESSAGE_SIZE (currently
256) bytes are allocated but never used. This is a small extra protection
against long error messages.
<H1>
iocLog</H1>
This consists of two modules: iocLogServer and iocLogClient. The client
code runs on each ioc and listens for the messages generated by the errlog
system. It also reports the messages from&nbsp; vxWorks logMsg.
<H3>
iocLogServer</H3>
This runs on a host. It receives messages for all enabled iocLogClients
in the local area network. The messages are written to a file. Epics base
provides a startup file "base/src/util/rc2.logServer", which is a shell
script to start the server. Consult this script for details.
<H3>
iocLogClient</H3>
This runs on each ioc. It is started by default when iocInit runs. The
global variable iocLogDisable can be used to enable/disable the messages
from being sent to the server. Setting this variable to (0,1) (enables,disables)
the messages generation. If iocLogDisable<TT> </TT>is set to 1 immediately
after iocCore is loaded then iocLogClient will not even initialize itself.
</BODY>
</HTML>

174
src/libCom/errlogUNIX.c Normal file
View File

@@ -0,0 +1,174 @@
/* $Id$
* errPrintfUNIX.c
* Author: Marty Kraimer
* Date: 02-16-95
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log: errPrintfUNIX.c
* -----------------
* .01 02-16-95 mrk Extracted from errSymLib.c
***************************************************************************
* This must ultimately be replaced by a facility that allows remote
* nodes access to the error messages. A message handling communication
* task should be written that allows multiple remote nodes to request
* notification of all error messages.
* For now lets just call fprintf and vfprintf
***************************************************************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "epicsAssert.h"
#define epicsExportSharedSymbols
#define ERRLOG_INIT
#include "errlog.h"
#undef ERRLOG_INIT
#undef epicsExportSharedSymbols
#include "errMdef.h"
#include "error.h"
static int sevToLog=0;
epicsShareFunc int epicsShareAPI errlogPrintf(const char *pformat, ...)
{
va_list pvar;
int nchar;
va_start(pvar,pformat);
nchar = errlogVprintf(pformat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogVprintf(
const char *pformat, va_list pvar)
{
return(vfprintf(stderr,pformat,pvar));
}
epicsShareFunc int epicsShareAPI errlogMessage(const char *message)
{
fprintf(stderr,"%s\n",message);
return(0);
}
epicsShareFunc int epicsShareAPI errlogSevPrintf(
const errlogSevEnum severity,const char *pformat, ...)
{
va_list pvar;
int nchar;
if(sevToLog>severity) return(0);
va_start(pvar, pformat);
nchar = errlogSevVprintf(severity,pformat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogSevVprintf(
const errlogSevEnum severity,const char *pformat,va_list pvar)
{
char *pnext;
int nchar;
int totalChar=0;
if(sevToLog>severity) return(0);
fprintf(stderr,"sevr=%s ",errlogGetSevEnumString(severity));
nchar = vfprintf(stderr,pformat,pvar);
fprintf(stderr,"\n");
return(nchar+1);
}
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString(
const errlogSevEnum severity)
{
static char unknown[] = "unknown";
if(severity<0 || severity>3) return(unknown);
return(errlogSevEnumString[severity]);
}
epicsShareFunc void epicsShareAPI errlogSetSevToLog(
const errlogSevEnum severity )
{
sevToLog = severity;
}
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog()
{
return(sevToLog);
}
epicsShareFunc void epicsShareAPI errlogAddListener(
errlogListener listener)
{
fprintf(stderr,"errlogAddListener not implemented\n");
return;
}
epicsShareFunc void epicsShareAPI errlogRemoveListener(
errlogListener listener)
{
fprintf(stderr,"errlogRemoveListener not implemented\n");
return;
}
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...)
{
va_list pvar;
va_start(pvar, pformat);
if(pFileName && errVerbose){
fprintf(stderr,"filename=\"%s\" line number=%d\n", pFileName, lineno);
}
if(status==0) status = errno;
if(status>0) {
int rtnval;
char name[256];
rtnval = errSymFind(status,name);
if(rtnval) {
unsigned short modnum,errnum;
modnum = (unsigned short) (status >> 16);
errnum = (unsigned short) (status & 0xffff);
fprintf(stderr, "status (%hu,%hu) not in symbol table",
modnum, errnum);
} else {
fprintf(stderr,"%s ",name);
}
}
if (pformat) {
vfprintf(stderr,pformat,pvar);
}
fprintf(stderr,"\n");
}

479
src/libCom/errlogVX.c Normal file
View File

@@ -0,0 +1,479 @@
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
This software was developed under a United States Government license
described on the COPYRIGHT_UniversityOfChicago file included as part
of this distribution.
**********************************************************************/
/*
* Author: Marty Kraimer and Jeff Hill
* Date: 07JAN1998
* NOTE: Original version is adaptation of old version of errPrintfVX.c
*/
#include <vxWorks.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <taskLib.h>
#include <intLib.h>
#include <semLib.h>
#include <vxLib.h>
#include <errnoLib.h>
#include <logLib.h>
#include "epicsAssert.h"
#define epicsExportSharedSymbols
#define ERRLOG_INIT
#include "errlog.h"
#undef ERRLOG_INIT
#undef epicsExportSharedSymbols
#include "errMdef.h"
#include "ellLib.h"
#include "error.h"
#include "task_params.h"
#ifndef LOCAL
#define LOCAL static
#endif /* LOCAL */
#define BUFFER_SIZE 1280
#define MAX_MESSAGE_SIZE 256
#define TRUNCATE_SIZE 80
#define MAX_ALIGNMENT 8
LOCAL void errlogTask(void);
LOCAL char *msgbufGetFree(void);
LOCAL void msgbufSetSize(int size);
LOCAL char * msgbufGetSend(void);
LOCAL void msgbufFreeSend(void);
LOCAL void *pvtCalloc(size_t count,size_t size);
LOCAL void pvtSemTake(SEM_ID semid);
typedef struct listenerNode{
ELLNODE node;
errlogListener listener;
}listenerNode;
/*each message consists of a msgNode immediately followed by the message */
typedef struct msgNode {
ELLNODE node;
char *message;
int length;
} msgNode;
LOCAL struct {
SEM_ID errlogTaskWaitForWork;
SEM_ID msgQueueLock;
SEM_ID listenerLock;
ELLLIST listenerList;
ELLLIST msgQueue;
msgNode *pnextSend;
int buffersize;
int sevToLog;
int toConsole;
int missedMessages;
void *pbuffer;
}pvtData;
epicsShareFunc int epicsShareAPI errlogPrintf( const char *pFormat, ...)
{
va_list pvar;
int nchar;
if(INT_CONTEXT()) {
logMsg("errlogPrintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
va_start(pvar, pFormat);
nchar = errlogVprintf(pFormat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogVprintf(
const char *pFormat,va_list pvar)
{
int nchar;
char *pbuffer;
if(INT_CONTEXT()) {
logMsg("errlogVprintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
pbuffer = msgbufGetFree();
if(!pbuffer) return(0);
nchar = vsprintf(pbuffer,pFormat,pvar);
msgbufSetSize(nchar+1);/*include the \0*/
return nchar;
}
epicsShareFunc int epicsShareAPI errlogMessage(const char *message)
{
int status;
char *pbuffer;
if(INT_CONTEXT()) {
status = logMsg ("errlogMessage called from interrupt level %s",
message,0,0,0,0,0);
return 0;
}
errlogInit(0);
pbuffer = msgbufGetFree();
if(!pbuffer) return(0);
strcpy(pbuffer,message);
msgbufSetSize(strlen(message) +1);
return 0;
}
epicsShareFunc int epicsShareAPI errlogSevPrintf(
const errlogSevEnum severity,const char *pFormat, ...)
{
va_list pvar;
int nchar;
if(INT_CONTEXT()) {
logMsg("errlogSevPrintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
if(pvtData.sevToLog>severity) return(0);
va_start(pvar, pFormat);
nchar = errlogSevVprintf(severity,pFormat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogSevVprintf(
const errlogSevEnum severity,const char *pFormat,va_list pvar)
{
char *pnext;
int nchar;
int totalChar=0;
if(pvtData.sevToLog>severity) return(0);
if(INT_CONTEXT()) {
logMsg("errlogSevVprintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
pnext = msgbufGetFree();
if(!pnext) return(0);
nchar = sprintf(pnext,"sevr=%s ",errlogGetSevEnumString(severity));
pnext += nchar; totalChar += nchar;
nchar = vsprintf(pnext,pFormat,pvar);
pnext += nchar; totalChar += nchar;
sprintf(pnext,"\n");
totalChar += 2; /*include \n and \0*/
msgbufSetSize(totalChar);
return(nchar);
}
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString(
const errlogSevEnum severity)
{
static char unknown[] = "unknown";
errlogInit(0);
if(severity<0 || severity>3) return(unknown);
return(errlogSevEnumString[severity]);
}
epicsShareFunc void epicsShareAPI errlogSetSevToLog(
const errlogSevEnum severity )
{
errlogInit(0);
pvtData.sevToLog = severity;
}
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog()
{
errlogInit(0);
return(pvtData.sevToLog);
}
epicsShareFunc void epicsShareAPI errlogAddListener(
errlogListener listener)
{
listenerNode *plistenerNode;
errlogInit(0);
plistenerNode = pvtCalloc(1,sizeof(listenerNode));
pvtSemTake(pvtData.listenerLock);
plistenerNode->listener = listener;
ellAdd(&pvtData.listenerList,&plistenerNode->node);
semGive(pvtData.listenerLock);
}
epicsShareFunc void epicsShareAPI errlogRemoveListener(
errlogListener listener)
{
listenerNode *plistenerNode;
errlogInit(0);
pvtSemTake(pvtData.listenerLock);
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
while(plistenerNode) {
if(plistenerNode->listener==listener) {
ellDelete(&pvtData.listenerList,&plistenerNode->node);
free((void *)plistenerNode);
break;
}
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
}
semGive(pvtData.listenerLock);
if(!plistenerNode) printf("errlogRemoveListener did not find listener\n");
}
epicsShareFunc void epicsShareAPI eltc(int yesno)
{
errlogInit(0);
pvtData.toConsole = yesno;
}
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...)
{
va_list pvar;
char *pnext;
int nchar;
int totalChar=0;
if(INT_CONTEXT()) {
logMsg("errPrintf called from interrupt level\n",0,0,0,0,0,0);
return;
}
errlogInit(0);
pnext = msgbufGetFree();
if(!pnext) return;
if(pFileName){
nchar = sprintf(pnext,"filename=\"%s\" line number=%d\n",
pFileName, lineno);
pnext += nchar; totalChar += nchar;
}
if(status==0) status = MYERRNO;
if(status>0) {
int rtnval;
char name[256];
rtnval = errSymFind(status,name);
if(rtnval) {
unsigned short modnum,errnum;
modnum = status >> 16; errnum = status & 0xffff;
nchar = sprintf(pnext, "status (%hu,%hu) not in symbol table ",
modnum, errnum);
} else {
nchar = sprintf(pnext,"%s ",name);
}
pnext += nchar; totalChar += nchar;
}
va_start (pvar, pformat);
nchar = vsprintf(pnext,pformat,pvar);
va_end (pvar);
if(nchar>0) {
pnext += nchar;
totalChar += nchar;
}
sprintf(pnext,"\n");
totalChar += 2; /*include the \n and the \0*/
msgbufSetSize(totalChar);
}
#define optionsSemM SEM_Q_PRIORITY|SEM_DELETE_SAFE|SEM_INVERSION_SAFE
epicsShareFunc void epicsShareAPI errlogInit(int bufsize)
{
static int errlogInitFlag=0;
void *pbuffer;;
if(!vxTas(&errlogInitFlag)) return;
if(bufsize<BUFFER_SIZE) bufsize = BUFFER_SIZE;
pvtData.buffersize = bufsize;
ellInit(&pvtData.listenerList);
ellInit(&pvtData.msgQueue);
pvtData.toConsole = TRUE;
if((pvtData.errlogTaskWaitForWork=semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL) {
logMsg("semBCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
if((pvtData.listenerLock=semMCreate(optionsSemM))==NULL) {
logMsg("semMCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
if((pvtData.msgQueueLock=semMCreate(optionsSemM))==NULL) {
logMsg("semMCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
/*Allow an extra MAX_MESSAGE_SIZE for extra margain of safety*/
pbuffer = pvtCalloc(pvtData.buffersize+MAX_MESSAGE_SIZE,sizeof(char));
pvtData.pbuffer = pbuffer;
taskSpawn(ERRLOG_NAME,ERRLOG_PRI,ERRLOG_OPT,
ERRLOG_STACK,(FUNCPTR)errlogTask,
0,0,0,0,0,0,0,0,0,0);
}
LOCAL void errlogTask(void)
{
listenerNode *plistenerNode;
while(TRUE) {
char *pmessage;
pvtSemTake(pvtData.errlogTaskWaitForWork);
while((pmessage = msgbufGetSend())) {
pvtSemTake(pvtData.listenerLock);
if(pvtData.toConsole) printf("%s",pmessage);
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
while(plistenerNode) {
(*plistenerNode->listener)(pmessage);
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
}
semGive(pvtData.listenerLock);
msgbufFreeSend();
}
}
}
LOCAL msgNode *msgbufGetNode()
{
char *pbuffer = (char *)pvtData.pbuffer;
msgNode *pnextSend = 0;
if(ellCount(&pvtData.msgQueue) == 0 ) {
pnextSend = (msgNode *)pbuffer;
} else {
int needed;
int remaining;
msgNode *plast;
plast = (msgNode *)ellLast(&pvtData.msgQueue);
needed = MAX_MESSAGE_SIZE + sizeof(msgNode) + MAX_ALIGNMENT;
remaining = pvtData.buffersize
- ((plast->message - pbuffer) + plast->length);
if(needed < remaining) {
int length,adjust;
length = plast->length;
/*Make length a multiple of MAX_ALIGNMENT*/
adjust = length%MAX_ALIGNMENT;
if(adjust) length += (MAX_ALIGNMENT-adjust);
pnextSend = (msgNode *)(plast->message + length);
}
}
if(!pnextSend) return(0);
pnextSend->message = (char *)pnextSend + sizeof(msgNode);
pnextSend->length = 0;
return(pnextSend);
}
LOCAL char *msgbufGetFree()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
if((ellCount(&pvtData.msgQueue) == 0) && pvtData.missedMessages) {
int nchar;
pnextSend = msgbufGetNode();
nchar = sprintf(pnextSend->message,"errlog = %d messages were discarded\n",
pvtData.missedMessages);
pnextSend->length = nchar + 1;
pvtData.missedMessages = 0;
ellAdd(&pvtData.msgQueue,&pnextSend->node);
}
pvtData.pnextSend = pnextSend = msgbufGetNode();
if(pnextSend) return(pnextSend->message);
++pvtData.missedMessages;
semGive(pvtData.msgQueueLock);
return(0);
}
LOCAL void msgbufSetSize(int size)
{
char *pbuffer = (char *)pvtData.pbuffer;
msgNode *pnextSend = pvtData.pnextSend;
char *message = pnextSend->message;
if(size>MAX_MESSAGE_SIZE) {
int excess;
int nchar;
excess = size - (pvtData.buffersize -(message - pbuffer));
message[TRUNCATE_SIZE] = 0;
if(excess> 0) {
printf("errlog: A message overran buffer by %d. This is VERY bad\n",
excess);
nchar = sprintf(&message[TRUNCATE_SIZE],
"\nerrlog = previous message overran buffer. It was truncated."
" size = %d excess = %d\n", size,excess);
} else {
nchar = sprintf(&message[TRUNCATE_SIZE],
"\nerrlog = previous message too long. It was truncated."
" size=%d It was truncated\n",size);
}
pnextSend->length = TRUNCATE_SIZE + nchar +1;
} else {
pnextSend->length = size+1;
}
ellAdd(&pvtData.msgQueue,&pnextSend->node);
semGive(pvtData.msgQueueLock);
semGive(pvtData.errlogTaskWaitForWork);
}
/*errlogTask is the only task that calls msgbufGetSend and msgbufFreeSend*/
/*Thus errlogTask is the ONLY task that removes messages from msgQueue */
/*This is why each can lock and unlock msgQueue */
/*This is necessary to prevent other tasks from waiting for errlogTask */
LOCAL char * msgbufGetSend()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
semGive(pvtData.msgQueueLock);
if(!pnextSend) return(0);
return(pnextSend->message);
}
LOCAL void msgbufFreeSend()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
if(!pnextSend) {
printf("errlog: msgbufFreeSend logic error\n");
taskSuspend(0);
}
ellDelete(&pvtData.msgQueue,&pnextSend->node);
semGive(pvtData.msgQueueLock);
}
LOCAL void *pvtCalloc(size_t count,size_t size)
{
size_t *pmem;
pmem = calloc(count,size);
if(!pmem) {
printf("calloc failed in errlog\n");
taskSuspend(0);
}
return(pmem);
}
LOCAL void pvtSemTake(SEM_ID semid)
{
if(semTake(semid,WAIT_FOREVER)!=OK) {
logMsg("epicsPrint: semTake returned error\n",0,0,0,0,0,0);
taskSuspend(0);
}
}

View File

@@ -1,34 +1,9 @@
/*epicsPrint.h */
#ifdef __cplusplus
extern "C" {
#define epicsPrintUseProtoANSI
#endif
/*This is now obsolete. Remlaced by errlog.h */
#ifndef INCepicsPrintH
#define INCepicsPrintH
#ifdef __STDC__
#ifndef epicsPrintUseProtoANSI
#define epicsPrintUseProtoANSI
#endif
#endif
#ifdef vxWorks
# ifdef epicsPrintUseProtoANSI
# include <stdarg.h>
int epicsPrintf(const char *pFormat, ...);
int epicsVprintf (const char *pFormat, va_list pvar);
int iocLogVPrintf(const char *pFormat, va_list pvar);
int iocLogPrintf(const char *pFormat, ...);
# else /* not epicsPrintUseProtoANSI */
int epicsPrintf();
int epicsVprintf ();
int iocLogVPrintf();
int iocLogPrintf();
# endif /* ifdef epicsPrintUseProtoANSI */
#else /* not vxWorks */
# define epicsPrintf printf
# define epicsVprintf vprintf
#endif /* ifdef vxWorks */
#ifdef __cplusplus
}
#endif
#include "errlog.h"
#endif /*INCepicsPrintH*/

View File

@@ -61,6 +61,10 @@ extern "C" {
#include "ellLib.h"
#include "shareLib.h"
/*The following is only included because before 3.13.0beta12 errMessage */
/*and errPrintf were defined here */
#include "errlog.h"
#define RTN_SUCCESS(STATUS) ((STATUS)==0)
#define M_dbAccess (501 <<16) /*Database Access Routines */
@@ -88,13 +92,6 @@ extern "C" {
#define M_bucket (525 <<16) /*Bucket Hash*/
#define M_gddFuncTbl (526 <<16) /*gdd jump table*/
/*
* redefine errMessage with a macro so we can print
* the file and line number
*/
#define errMessage(S, PM) \
errPrintf(S, __FILE__, __LINE__, PM)
#ifdef errMDefUseProtoANSI
epicsShareFunc int epicsShareAPI errSymFind(long status, char *name);
epicsShareFunc int epicsShareAPI UnixSymFind(long status, char *name, long *value);
@@ -103,11 +100,8 @@ epicsShareFunc void epicsShareAPI errSymTest(unsigned short modnum, unsigned sho
epicsShareFunc void epicsShareAPI errSymTestPrint(long errNum);
epicsShareFunc int epicsShareAPI errSymBld();
epicsShareFunc int epicsShareAPI errSymbolAdd (long errNum,char *name);
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...);
epicsShareFunc void epicsShareAPI errSymDump();
epicsShareFunc void epicsShareAPI tstErrSymFind();
epicsShareFunc void epicsShareAPI errInit(void);
#else /* errMDefUseProtoANSI */
@@ -118,7 +112,6 @@ epicsShareFunc int epicsShareAPI ModSymFind();
epicsShareFunc void epicsShareAPI errSymTestPrint();
epicsShareFunc int epicsShareAPI errSymBld();
epicsShareFunc int epicsShareAPI errSymbolAdd();
epicsShareFunc void epicsShareAPI errPrintf();
epicsShareFunc void epicsShareAPI errSymDump();
epicsShareFunc void epicsShareAPI tstErrSymFind();
#endif /* errMDefUseProtoANSI */

479
src/libCom/error/errlog.c Normal file
View File

@@ -0,0 +1,479 @@
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
This software was developed under a United States Government license
described on the COPYRIGHT_UniversityOfChicago file included as part
of this distribution.
**********************************************************************/
/*
* Author: Marty Kraimer and Jeff Hill
* Date: 07JAN1998
* NOTE: Original version is adaptation of old version of errPrintfVX.c
*/
#include <vxWorks.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <taskLib.h>
#include <intLib.h>
#include <semLib.h>
#include <vxLib.h>
#include <errnoLib.h>
#include <logLib.h>
#include "epicsAssert.h"
#define epicsExportSharedSymbols
#define ERRLOG_INIT
#include "errlog.h"
#undef ERRLOG_INIT
#undef epicsExportSharedSymbols
#include "errMdef.h"
#include "ellLib.h"
#include "error.h"
#include "task_params.h"
#ifndef LOCAL
#define LOCAL static
#endif /* LOCAL */
#define BUFFER_SIZE 1280
#define MAX_MESSAGE_SIZE 256
#define TRUNCATE_SIZE 80
#define MAX_ALIGNMENT 8
LOCAL void errlogTask(void);
LOCAL char *msgbufGetFree(void);
LOCAL void msgbufSetSize(int size);
LOCAL char * msgbufGetSend(void);
LOCAL void msgbufFreeSend(void);
LOCAL void *pvtCalloc(size_t count,size_t size);
LOCAL void pvtSemTake(SEM_ID semid);
typedef struct listenerNode{
ELLNODE node;
errlogListener listener;
}listenerNode;
/*each message consists of a msgNode immediately followed by the message */
typedef struct msgNode {
ELLNODE node;
char *message;
int length;
} msgNode;
LOCAL struct {
SEM_ID errlogTaskWaitForWork;
SEM_ID msgQueueLock;
SEM_ID listenerLock;
ELLLIST listenerList;
ELLLIST msgQueue;
msgNode *pnextSend;
int buffersize;
int sevToLog;
int toConsole;
int missedMessages;
void *pbuffer;
}pvtData;
epicsShareFunc int epicsShareAPI errlogPrintf( const char *pFormat, ...)
{
va_list pvar;
int nchar;
if(INT_CONTEXT()) {
logMsg("errlogPrintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
va_start(pvar, pFormat);
nchar = errlogVprintf(pFormat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogVprintf(
const char *pFormat,va_list pvar)
{
int nchar;
char *pbuffer;
if(INT_CONTEXT()) {
logMsg("errlogVprintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
pbuffer = msgbufGetFree();
if(!pbuffer) return(0);
nchar = vsprintf(pbuffer,pFormat,pvar);
msgbufSetSize(nchar+1);/*include the \0*/
return nchar;
}
epicsShareFunc int epicsShareAPI errlogMessage(const char *message)
{
int status;
char *pbuffer;
if(INT_CONTEXT()) {
status = logMsg ("errlogMessage called from interrupt level %s",
message,0,0,0,0,0);
return 0;
}
errlogInit(0);
pbuffer = msgbufGetFree();
if(!pbuffer) return(0);
strcpy(pbuffer,message);
msgbufSetSize(strlen(message) +1);
return 0;
}
epicsShareFunc int epicsShareAPI errlogSevPrintf(
const errlogSevEnum severity,const char *pFormat, ...)
{
va_list pvar;
int nchar;
if(INT_CONTEXT()) {
logMsg("errlogSevPrintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
if(pvtData.sevToLog>severity) return(0);
va_start(pvar, pFormat);
nchar = errlogSevVprintf(severity,pFormat,pvar);
va_end (pvar);
return(nchar);
}
epicsShareFunc int epicsShareAPI errlogSevVprintf(
const errlogSevEnum severity,const char *pFormat,va_list pvar)
{
char *pnext;
int nchar;
int totalChar=0;
if(pvtData.sevToLog>severity) return(0);
if(INT_CONTEXT()) {
logMsg("errlogSevVprintf called from interrupt level\n",0,0,0,0,0,0);
return 0;
}
errlogInit(0);
pnext = msgbufGetFree();
if(!pnext) return(0);
nchar = sprintf(pnext,"sevr=%s ",errlogGetSevEnumString(severity));
pnext += nchar; totalChar += nchar;
nchar = vsprintf(pnext,pFormat,pvar);
pnext += nchar; totalChar += nchar;
sprintf(pnext,"\n");
totalChar += 2; /*include \n and \0*/
msgbufSetSize(totalChar);
return(nchar);
}
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString(
const errlogSevEnum severity)
{
static char unknown[] = "unknown";
errlogInit(0);
if(severity<0 || severity>3) return(unknown);
return(errlogSevEnumString[severity]);
}
epicsShareFunc void epicsShareAPI errlogSetSevToLog(
const errlogSevEnum severity )
{
errlogInit(0);
pvtData.sevToLog = severity;
}
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog()
{
errlogInit(0);
return(pvtData.sevToLog);
}
epicsShareFunc void epicsShareAPI errlogAddListener(
errlogListener listener)
{
listenerNode *plistenerNode;
errlogInit(0);
plistenerNode = pvtCalloc(1,sizeof(listenerNode));
pvtSemTake(pvtData.listenerLock);
plistenerNode->listener = listener;
ellAdd(&pvtData.listenerList,&plistenerNode->node);
semGive(pvtData.listenerLock);
}
epicsShareFunc void epicsShareAPI errlogRemoveListener(
errlogListener listener)
{
listenerNode *plistenerNode;
errlogInit(0);
pvtSemTake(pvtData.listenerLock);
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
while(plistenerNode) {
if(plistenerNode->listener==listener) {
ellDelete(&pvtData.listenerList,&plistenerNode->node);
free((void *)plistenerNode);
break;
}
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
}
semGive(pvtData.listenerLock);
if(!plistenerNode) printf("errlogRemoveListener did not find listener\n");
}
epicsShareFunc void epicsShareAPI eltc(int yesno)
{
errlogInit(0);
pvtData.toConsole = yesno;
}
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...)
{
va_list pvar;
char *pnext;
int nchar;
int totalChar=0;
if(INT_CONTEXT()) {
logMsg("errPrintf called from interrupt level\n",0,0,0,0,0,0);
return;
}
errlogInit(0);
pnext = msgbufGetFree();
if(!pnext) return;
if(pFileName){
nchar = sprintf(pnext,"filename=\"%s\" line number=%d\n",
pFileName, lineno);
pnext += nchar; totalChar += nchar;
}
if(status==0) status = MYERRNO;
if(status>0) {
int rtnval;
char name[256];
rtnval = errSymFind(status,name);
if(rtnval) {
unsigned short modnum,errnum;
modnum = status >> 16; errnum = status & 0xffff;
nchar = sprintf(pnext, "status (%hu,%hu) not in symbol table ",
modnum, errnum);
} else {
nchar = sprintf(pnext,"%s ",name);
}
pnext += nchar; totalChar += nchar;
}
va_start (pvar, pformat);
nchar = vsprintf(pnext,pformat,pvar);
va_end (pvar);
if(nchar>0) {
pnext += nchar;
totalChar += nchar;
}
sprintf(pnext,"\n");
totalChar += 2; /*include the \n and the \0*/
msgbufSetSize(totalChar);
}
#define optionsSemM SEM_Q_PRIORITY|SEM_DELETE_SAFE|SEM_INVERSION_SAFE
epicsShareFunc void epicsShareAPI errlogInit(int bufsize)
{
static int errlogInitFlag=0;
void *pbuffer;;
if(!vxTas(&errlogInitFlag)) return;
if(bufsize<BUFFER_SIZE) bufsize = BUFFER_SIZE;
pvtData.buffersize = bufsize;
ellInit(&pvtData.listenerList);
ellInit(&pvtData.msgQueue);
pvtData.toConsole = TRUE;
if((pvtData.errlogTaskWaitForWork=semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL) {
logMsg("semBCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
if((pvtData.listenerLock=semMCreate(optionsSemM))==NULL) {
logMsg("semMCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
if((pvtData.msgQueueLock=semMCreate(optionsSemM))==NULL) {
logMsg("semMCreate failed in errlogInit",0,0,0,0,0,0);
taskSuspend(0);
}
/*Allow an extra MAX_MESSAGE_SIZE for extra margain of safety*/
pbuffer = pvtCalloc(pvtData.buffersize+MAX_MESSAGE_SIZE,sizeof(char));
pvtData.pbuffer = pbuffer;
taskSpawn(ERRLOG_NAME,ERRLOG_PRI,ERRLOG_OPT,
ERRLOG_STACK,(FUNCPTR)errlogTask,
0,0,0,0,0,0,0,0,0,0);
}
LOCAL void errlogTask(void)
{
listenerNode *plistenerNode;
while(TRUE) {
char *pmessage;
pvtSemTake(pvtData.errlogTaskWaitForWork);
while((pmessage = msgbufGetSend())) {
pvtSemTake(pvtData.listenerLock);
if(pvtData.toConsole) printf("%s",pmessage);
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
while(plistenerNode) {
(*plistenerNode->listener)(pmessage);
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
}
semGive(pvtData.listenerLock);
msgbufFreeSend();
}
}
}
LOCAL msgNode *msgbufGetNode()
{
char *pbuffer = (char *)pvtData.pbuffer;
msgNode *pnextSend = 0;
if(ellCount(&pvtData.msgQueue) == 0 ) {
pnextSend = (msgNode *)pbuffer;
} else {
int needed;
int remaining;
msgNode *plast;
plast = (msgNode *)ellLast(&pvtData.msgQueue);
needed = MAX_MESSAGE_SIZE + sizeof(msgNode) + MAX_ALIGNMENT;
remaining = pvtData.buffersize
- ((plast->message - pbuffer) + plast->length);
if(needed < remaining) {
int length,adjust;
length = plast->length;
/*Make length a multiple of MAX_ALIGNMENT*/
adjust = length%MAX_ALIGNMENT;
if(adjust) length += (MAX_ALIGNMENT-adjust);
pnextSend = (msgNode *)(plast->message + length);
}
}
if(!pnextSend) return(0);
pnextSend->message = (char *)pnextSend + sizeof(msgNode);
pnextSend->length = 0;
return(pnextSend);
}
LOCAL char *msgbufGetFree()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
if((ellCount(&pvtData.msgQueue) == 0) && pvtData.missedMessages) {
int nchar;
pnextSend = msgbufGetNode();
nchar = sprintf(pnextSend->message,"errlog = %d messages were discarded\n",
pvtData.missedMessages);
pnextSend->length = nchar + 1;
pvtData.missedMessages = 0;
ellAdd(&pvtData.msgQueue,&pnextSend->node);
}
pvtData.pnextSend = pnextSend = msgbufGetNode();
if(pnextSend) return(pnextSend->message);
++pvtData.missedMessages;
semGive(pvtData.msgQueueLock);
return(0);
}
LOCAL void msgbufSetSize(int size)
{
char *pbuffer = (char *)pvtData.pbuffer;
msgNode *pnextSend = pvtData.pnextSend;
char *message = pnextSend->message;
if(size>MAX_MESSAGE_SIZE) {
int excess;
int nchar;
excess = size - (pvtData.buffersize -(message - pbuffer));
message[TRUNCATE_SIZE] = 0;
if(excess> 0) {
printf("errlog: A message overran buffer by %d. This is VERY bad\n",
excess);
nchar = sprintf(&message[TRUNCATE_SIZE],
"\nerrlog = previous message overran buffer. It was truncated."
" size = %d excess = %d\n", size,excess);
} else {
nchar = sprintf(&message[TRUNCATE_SIZE],
"\nerrlog = previous message too long. It was truncated."
" size=%d It was truncated\n",size);
}
pnextSend->length = TRUNCATE_SIZE + nchar +1;
} else {
pnextSend->length = size+1;
}
ellAdd(&pvtData.msgQueue,&pnextSend->node);
semGive(pvtData.msgQueueLock);
semGive(pvtData.errlogTaskWaitForWork);
}
/*errlogTask is the only task that calls msgbufGetSend and msgbufFreeSend*/
/*Thus errlogTask is the ONLY task that removes messages from msgQueue */
/*This is why each can lock and unlock msgQueue */
/*This is necessary to prevent other tasks from waiting for errlogTask */
LOCAL char * msgbufGetSend()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
semGive(pvtData.msgQueueLock);
if(!pnextSend) return(0);
return(pnextSend->message);
}
LOCAL void msgbufFreeSend()
{
msgNode *pnextSend;
pvtSemTake(pvtData.msgQueueLock);
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
if(!pnextSend) {
printf("errlog: msgbufFreeSend logic error\n");
taskSuspend(0);
}
ellDelete(&pvtData.msgQueue,&pnextSend->node);
semGive(pvtData.msgQueueLock);
}
LOCAL void *pvtCalloc(size_t count,size_t size)
{
size_t *pmem;
pmem = calloc(count,size);
if(!pmem) {
printf("calloc failed in errlog\n");
taskSuspend(0);
}
return(pmem);
}
LOCAL void pvtSemTake(SEM_ID semid)
{
if(semTake(semid,WAIT_FOREVER)!=OK) {
logMsg("epicsPrint: semTake returned error\n",0,0,0,0,0,0);
taskSuspend(0);
}
}

95
src/libCom/error/errlog.h Normal file
View File

@@ -0,0 +1,95 @@
/* src/libCom/errlog.h */
/*****************************************************************
COPYRIGHT NOTIFICATION
*****************************************************************
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
This software was developed under a United States Government license
described on the COPYRIGHT_UniversityOfChicago file included as part
of this distribution.
**********************************************************************/
#ifndef INCerrlogh
#define INCerrlogh
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#define epicsPrintUseProtoANSI
#endif
#ifdef __STDC__
#ifndef epicsPrintUseProtoANSI
#define epicsPrintUseProtoANSI
#endif
#endif
/* define errMessage with a macro so we can print the file and line number*/
#define errMessage(S, PM) \
errPrintf(S, __FILE__, __LINE__, PM)
/* epicsPrintf and epicsVprintf old versions of errlog routines*/
#define epicsPrintf errlogPrintf
#define epicsVprintf errlogVprintf
typedef void(*errlogListener) (const char *message);
typedef enum {errlogInfo,errlogMinor,errlogMajor,errlogFatal} errlogSevEnum;
extern char * errlogSevEnumString[];
#ifdef ERRLOG_INIT
char * errlogSevEnumString[] = {"info","minor","major","fatal"};
#endif
#ifdef epicsPrintUseProtoANSI
epicsShareFunc int epicsShareAPI errlogPrintf(
const char *pformat, ...);
epicsShareFunc int epicsShareAPI errlogVprintf(
const char *pformat,va_list pvar);
epicsShareFunc int epicsShareAPI errlogSevPrintf(
const errlogSevEnum severity,const char *pformat, ...);
epicsShareFunc int epicsShareAPI errlogSevVprintf(
const errlogSevEnum severity,const char *pformat,va_list pvar);
epicsShareFunc int epicsShareAPI errlogMessage(
const char *message);
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString(
const errlogSevEnum severity);
epicsShareFunc void epicsShareAPI errlogSetSevToLog(
const errlogSevEnum severity );
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog(void);
epicsShareFunc void epicsShareAPI errlogAddListener(
errlogListener listener);
epicsShareFunc void epicsShareAPI errlogRemoveListener(
errlogListener listener);
epicsShareFunc void epicsShareAPI eltc(int yesno);
epicsShareFunc void epicsShareAPI errlogInit(int bufsize);
/*other routines that write to log file*/
epicsShareFunc void epicsShareAPI errPrintf(long status, const char *pFileName,
int lineno, const char *pformat, ...);
#else /* not epicsPrintUseProtoANSI */
epicsShareFunc int epicsShareAPI errlogPrintf();
epicsShareFunc int epicsShareAPI errlogVprintf();
epicsShareFunc int epicsShareAPI errlogSevPrintf();
epicsShareFunc int epicsShareAPI errlogSevVprintf();
epicsShareFunc int epicsShareAPI errlogMessage();
epicsShareFunc char * epicsShareAPI errlogGetSevEnumString();
epicsShareFunc void epicsShareAPI errlogSetSevToLog();
epicsShareFunc errlogSevEnum epicsShareAPI errlogGetSevToLog();
epicsShareFunc void epicsShareAPI errlogAddListener();
epicsShareFunc void epicsShareAPI errlogRemoveListener();
epicsShareFunc void epicsShareAPI eltc();
epicsShareFunc void epicsShareAPI errlogInit();
epicsShareFunc void epicsShareAPI errPrintf();
#endif /* ifdef epicsPrintUseProtoANSI */
#ifdef __cplusplus
}
#endif
#endif /*INCerrlogh*/