summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Makefile.am22
-rw-r--r--runtime/atomic.h32
-rw-r--r--runtime/conf.c71
-rw-r--r--runtime/conf.h4
-rw-r--r--runtime/ctok.c17
-rw-r--r--runtime/datetime.c299
-rw-r--r--runtime/datetime.h6
-rw-r--r--runtime/debug.c236
-rw-r--r--runtime/debug.h5
-rw-r--r--runtime/expr.c63
-rw-r--r--runtime/glbl.c45
-rw-r--r--runtime/glbl.h8
-rw-r--r--runtime/module-template.h31
-rw-r--r--runtime/modules.c117
-rw-r--r--runtime/modules.h6
-rw-r--r--runtime/msg.c152
-rw-r--r--runtime/msg.h34
-rw-r--r--runtime/net.c10
-rw-r--r--runtime/obj.c2
-rw-r--r--runtime/parser.c315
-rw-r--r--runtime/parser.h30
-rw-r--r--runtime/queue.c468
-rw-r--r--runtime/queue.h51
-rw-r--r--runtime/rsyslog.c2
-rw-r--r--runtime/rsyslog.h13
-rw-r--r--runtime/srutils.c6
-rw-r--r--runtime/stringbuf.c18
-rw-r--r--runtime/stringbuf.h2
-rw-r--r--runtime/sysvar.c2
-rw-r--r--runtime/var.c40
-rw-r--r--runtime/var.h1
-rw-r--r--runtime/vm.c29
-rw-r--r--runtime/vmop.c97
-rw-r--r--runtime/vmop.h35
-rw-r--r--runtime/vmprg.c41
-rw-r--r--runtime/vmprg.h3
-rw-r--r--runtime/wti.c35
-rw-r--r--runtime/wti.h2
-rw-r--r--runtime/wtp.c30
-rw-r--r--runtime/wtp.h1
40 files changed, 1720 insertions, 661 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 81a9d5bd..2f0a1aa0 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -16,6 +16,8 @@ librsyslog_la_SOURCES = \
glbl.c \
conf.c \
conf.h \
+ parser.h \
+ parser.c \
msg.c \
msg.h \
linkedlist.c \
@@ -83,9 +85,13 @@ librsyslog_la_SOURCES = \
# the files with ../ we need to work on - so that they either become part of the
# runtime or will no longer be needed. -- rgerhards, 2008-06-13
-librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(pthreads_cflags)
+if WITH_MODDIRS
+librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS)
+else
+librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS)
+endif
#librsyslog_la_LDFLAGS = -module -avoid-version
-librsyslog_la_LIBADD = $(dl_libs) $(rt_libs)
+librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS)
#
# regular expression support
@@ -93,7 +99,7 @@ librsyslog_la_LIBADD = $(dl_libs) $(rt_libs)
if ENABLE_REGEXP
pkglib_LTLIBRARIES += lmregexp.la
lmregexp_la_SOURCES = regexp.c regexp.h
-lmregexp_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
+lmregexp_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmregexp_la_LDFLAGS = -module -avoid-version
lmregexp_la_LIBADD =
endif
@@ -104,13 +110,13 @@ pkglib_LTLIBRARIES += lmnet.la lmnetstrms.la
# network support
#
lmnet_la_SOURCES = net.c net.h
-lmnet_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
+lmnet_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmnet_la_LDFLAGS = -module -avoid-version
lmnet_la_LIBADD =
# network stream master class and stream factory
lmnetstrms_la_SOURCES = netstrms.c netstrms.h netstrm.c netstrm.h nssel.c nssel.h
-lmnetstrms_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
+lmnetstrms_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmnetstrms_la_LDFLAGS = -module -avoid-version
lmnetstrms_la_LIBADD =
@@ -119,7 +125,7 @@ lmnetstrms_la_LIBADD =
# plain tcp driver - main driver
pkglib_LTLIBRARIES += lmnsd_ptcp.la
lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h nsdsel_ptcp.c nsdsel_ptcp.h
-lmnsd_ptcp_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
+lmnsd_ptcp_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmnsd_ptcp_la_LDFLAGS = -module -avoid-version
lmnsd_ptcp_la_LIBADD =
endif # if ENABLE_INET
@@ -130,8 +136,8 @@ endif # if ENABLE_INET
if ENABLE_GNUTLS
pkglib_LTLIBRARIES += lmnsd_gtls.la
lmnsd_gtls_la_SOURCES = nsd_gtls.c nsd_gtls.h nsdsel_gtls.c nsdsel_gtls.h
-lmnsd_gtls_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags) $(gnutls_cflags)
+lmnsd_gtls_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(GNUTLS_CFLAGS)
lmnsd_gtls_la_LDFLAGS = -module -avoid-version
-lmnsd_gtls_la_LIBADD = $(gnutls_libs)
+lmnsd_gtls_la_LIBADD = $(GNUTLS_LIBS)
endif
diff --git a/runtime/atomic.h b/runtime/atomic.h
index 430ae7f0..fdf64214 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -1,6 +1,6 @@
/* This header supplies atomic operations. So far, we rely on GCC's
- * atomic builtins. I have no idea if we can check them via autotools,
- * but I am making the necessary provisioning to live without them if
+ * atomic builtins. During configure, we check if atomic operatons are
+ * available. If they are not, I am making the necessary provisioning to live without them if
* they are not available. Please note that you should only use the macros
* here if you think you can actually live WITHOUT an explicit atomic operation,
* because in the non-presence of them, we simply do it without atomicitiy.
@@ -36,16 +36,30 @@
#ifndef INCLUDED_ATOMIC_H
#define INCLUDED_ATOMIC_H
-/* set the following to 1 if we have atomic operations (and #undef it otherwise) */
-/* #define DO_HAVE_ATOMICS 1 */
/* for this release, we disable atomic calls because there seem to be some
* portability problems and we can not fix that without destabilizing the build.
* They simply came in too late. -- rgerhards, 2008-04-02
*/
-/* make sure they are not used!
-#define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&data, 1))
-#define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&data, 1)
-*/
-#define ATOMIC_INC(data) (++(data))
+#ifdef HAVE_ATOMIC_BUILTINS
+# define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
+# define ATOMIC_DEC(data) ((void) __sync_sub_and_fetch(&(data), 1))
+# define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&(data), 1)
+# define ATOMIC_FETCH_32BIT(data) ((unsigned) __sync_fetch_and_and(&(data), 0xffffffff))
+# define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1)
+#else
+ /* note that we gained parctical proof that theoretical problems DO occur
+ * if we do not properly address them. See this blog post for details:
+ * http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html
+ * The bottom line is that if there are no atomics available, we should NOT
+ * simply go ahead and do without them - use mutexes or other things. The
+ * code needs to be checked against all those cases. -- rgerhards, 2009-01-30
+ */
+# warning "atomic builtins not available, using nul operations - rsyslogd will probably be racy!"
+# define ATOMIC_INC(data) (++(data))
+# define ATOMIC_DEC(data) (--(data))
+# define ATOMIC_DEC_AND_FETCH(data) (--(data))
+# define ATOMIC_FETCH_32BIT(data) (data)
+# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1
+#endif
#endif /* #ifndef INCLUDED_ATOMIC_H */
diff --git a/runtime/conf.c b/runtime/conf.c
index 75276a00..ede15cc7 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -46,7 +46,9 @@
#include <glob.h>
#include <sys/types.h>
#ifdef HAVE_LIBGEN_H
-# include <libgen.h>
+# ifndef OS_SOLARIS
+# include <libgen.h>
+# endif
#endif
#include "rsyslog.h"
@@ -68,6 +70,9 @@
#include "ctok.h"
#include "ctok_token.h"
+#ifdef OS_SOLARIS
+# define NAME_MAX MAXNAMELEN
+#endif
/* forward definitions */
static rsRetVal cfline(uchar *line, selector_t **pfCurr);
@@ -83,6 +88,8 @@ DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(net)
+static int iNbrActions; /* number of actions the running config has. Needs to be init on ReInitConf() */
+
/* The following global variables are used for building
* tag and host selector lines during startup and config reload.
* This is stored as a global variable pool because of its ease. It is
@@ -188,6 +195,7 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
char pattern[MAXFNAME];
uchar *cfgFile;
glob_t cfgFiles;
+ int result;
size_t i = 0;
struct stat fileInfo;
@@ -195,14 +203,21 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
ASSERT(*pp != NULL);
if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) {
- errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract group name");
+ errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
/* Use GLOB_MARK to append a trailing slash for directories.
* Required by doIncludeDirectory().
*/
- glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ result = glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ if(result != 0) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s",
+ pattern, errStr);
+ ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
+ }
for(i = 0; i < cfgFiles.gl_pathc; i++) {
cfgFile = (uchar*) cfgFiles.gl_pathv[i];
@@ -560,8 +575,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int
}
-/*
- * Helper to cfline(). This function takes the filter part of a traditional, PRI
+/* Helper to cfline(). This function takes the filter part of a traditional, PRI
* based line and decodes the PRIs given in the selector line. It processed the
* line up to the beginning of the action part. A pointer to that beginnig is
* passed back to the caller.
@@ -577,8 +591,9 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
int pri;
int singlpri = 0;
int ignorepri = 0;
- uchar buf[MAXLINE];
+ uchar buf[2048]; /* buffer for facility and priority names */
uchar xbuf[200];
+ DEFiRet;
ASSERT(pline != NULL);
ASSERT(*pline != NULL);
@@ -603,7 +618,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
continue;
/* collect priority name */
- for (bp = buf; *q && !strchr("\t ,;", *q); )
+ for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; )
*bp++ = *q++;
*bp = '\0';
@@ -614,6 +629,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
/* decode priority name */
if ( *buf == '!' ) {
ignorepri = 1;
+ /* copy below is ok, we can NOT go off the allocated area */
for (bp=buf; *(bp+1); bp++)
*bp=*(bp+1);
*bp='\0';
@@ -639,7 +655,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
/* scan facilities */
while (*p && !strchr("\t .;", *p)) {
- for (bp = buf; *p && !strchr("\t ,;.", *p); )
+ for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; )
*bp++ = *p++;
*bp = '\0';
if (*buf == '*') {
@@ -722,7 +738,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
p++;
*pline = p;
- return RS_RET_OK;
+ RETiRet;
}
@@ -778,6 +794,10 @@ dbgprintf("calling expression parser, pp %p ('%s')\n", *pline, *pline);
CHKiRet(ctok.Getpp(tok, pline));
CHKiRet(ctok.Destruct(&tok));
+ /* debug support - print vmprg after construction (uncomment to use) */
+ /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */
+ vmprgDebugPrint(f->f_filterData.f_expr->pVmprg);
+
/* we now need to skip whitespace to the action part, else we confuse
* the legacy rsyslog conf parser. -- rgerhards, 2008-02-25
*/
@@ -862,6 +882,8 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register selector_t *f)
f->f_filterData.prop.operation = FIOP_STARTSWITH;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
f->f_filterData.prop.operation = FIOP_REGEX;
+ } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) {
+ f->f_filterData.prop.operation = FIOP_EREREGEX;
} else {
errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector",
(char*) rsCStrGetSzStrNoNULL(pCSCompOp));
@@ -1060,6 +1082,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
pAction->f_ReduceRepeated = 0;
}
pAction->bEnabled = 1; /* action is enabled */
+ iNbrActions++; /* one more active action! */
}
break;
}
@@ -1159,6 +1182,34 @@ cfline(uchar *line, selector_t **pfCurr)
}
+/* Reinitialize the configuration subsystem. This is a "work-around" to the fact
+ * that we do not yet have actual config objects. This method is to be called
+ * whenever a totally new config is started (which means on startup and HUP).
+ * Note that it MUST NOT be called for an included config file.
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+ReInitConf(void)
+{
+ DEFiRet;
+ iNbrActions = 0; /* this is what we created the function for ;) - action count is reset */
+ RETiRet;
+}
+
+
+/* return the current number of active actions
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+GetNbrActActions(int *piNbrActions)
+{
+ DEFiRet;
+ assert(piNbrActions != NULL);
+ *piNbrActions = iNbrActions;
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-29
*/
@@ -1179,6 +1230,8 @@ CODESTARTobjQueryInterface(conf)
pIf->doIncludeLine = doIncludeLine;
pIf->cfline = cfline;
pIf->processConfFile = processConfFile;
+ pIf->ReInitConf = ReInitConf;
+ pIf->GetNbrActActions = GetNbrActActions;
finalize_it:
ENDobjQueryInterface(conf)
diff --git a/runtime/conf.h b/runtime/conf.h
index 31ca27b3..2494d4dc 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -37,8 +37,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal (*cfline)(uchar *line, selector_t **pfCurr);
rsRetVal (*processConfFile)(uchar *pConfFile);
+ rsRetVal (*ReInitConf)(void);
+ rsRetVal (*GetNbrActActions)(int *);
ENDinterface(conf)
-#define confCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define confCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* prototypes */
diff --git a/runtime/ctok.c b/runtime/ctok.c
index ceab15bd..d2cd8bbd 100644
--- a/runtime/ctok.c
+++ b/runtime/ctok.c
@@ -259,12 +259,17 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
}
CHKiRet(rsCStrConstruct(&pstrVal));
- /* this loop is quite simple, a variable name is terminated by whitespace. */
- while(!isspace(c)) {
+ /* this loop is quite simple, a variable name is terminated when a non-supported
+ * character is detected. Note that we currently permit a numerical digit as the
+ * first char, which is not permitted by ABNF. -- rgerhards, 2009-03-10
+ */
+ while(isalpha(c) || isdigit(c) || (c == '_') || (c == '-')) {
CHKiRet(rsCStrAppendChar(pstrVal, tolower(c)));
CHKiRet(ctokGetCharFromStream(pThis, &c));
}
- CHKiRet(rsCStrFinish(pStrB));
+ CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put not processed char back */
+
+ CHKiRet(rsCStrFinish(pstrVal));
CHKiRet(var.SetString(pToken->pVar, pstrVal));
pstrVal = NULL;
@@ -389,6 +394,7 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
uchar c;
uchar szWord[128];
int bRetry = 0; /* retry parse? Only needed for inline comments... */
+ cstr_t *pstrVal;
ISOBJ_TYPE_assert(pThis, ctok);
ASSERT(ppToken != NULL);
@@ -512,7 +518,10 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
/* push c back, higher level parser needs it */
CHKiRet(ctokUngetCharFromStream(pThis, c));
pToken->tok = ctok_FUNCTION;
- /* TODO: fill function name */
+ /* fill function name */
+ CHKiRet(rsCStrConstruct(&pstrVal));
+ CHKiRet(rsCStrSetSzStr(pstrVal, szWord));
+ CHKiRet(var.SetString(pToken->pVar, pstrVal));
} else { /* give up... */
dbgprintf("parser has an invalid word (token) '%s'\n", szWord);
pToken->tok = ctok_INVALID;
diff --git a/runtime/datetime.c b/runtime/datetime.c
index aeb5fac5..676f76d5 100644
--- a/runtime/datetime.c
+++ b/runtime/datetime.c
@@ -62,9 +62,14 @@ DEFobjCurrIf(errmsg)
* most portable and removes the need for additional structures
* (but I have to admit it is somewhat "bulky";)).
*
- * Obviously, all caller-provided pointers must not be NULL...
+ * Obviously, *t must not be NULL...
+ *
+ * rgerhards, 2008-10-07: added ttSeconds to provide a way to
+ * obtain the second-resolution UNIX timestamp. This is needed
+ * in some situations to minimize time() calls (namely when doing
+ * output processing). This can be left NULL if not needed.
*/
-static void getCurrTime(struct syslogTime *t)
+static void getCurrTime(struct syslogTime *t, time_t *ttSeconds)
{
struct timeval tp;
struct tm *tm;
@@ -83,6 +88,9 @@ static void getCurrTime(struct syslogTime *t)
# else
gettimeofday(&tp, NULL);
# endif
+ if(ttSeconds != NULL)
+ *ttSeconds = tp.tv_sec;
+
tm = localtime_r((time_t*) &(tp.tv_sec), &tmBuf);
t->year = tm->tm_year + 1900;
@@ -159,18 +167,34 @@ static int srSLMGParseInt32(char** ppsz)
/**
* Parse a TIMESTAMP-3339.
- * updates the parse pointer position.
+ * updates the parse pointer position. The pTime parameter
+ * is guranteed to be updated only if a new valid timestamp
+ * could be obtained (restriction added 2008-09-16 by rgerhards).
*/
-static int
+static rsRetVal
ParseTIMESTAMP3339(struct syslogTime *pTime, char** ppszTS)
{
char *pszTS = *ppszTS;
+ /* variables to temporarily hold time information while we parse */
+ int year;
+ int month;
+ int day;
+ int hour; /* 24 hour clock */
+ int minute;
+ int second;
+ int secfrac; /* fractional seconds (must be 32 bit!) */
+ int secfracPrecision;
+ char OffsetMode; /* UTC offset + or - */
+ char OffsetHour; /* UTC offset in hours */
+ int OffsetMinute; /* UTC offset in minutes */
+ /* end variables to temporarily hold time information while we parse */
+ DEFiRet;
assert(pTime != NULL);
assert(ppszTS != NULL);
assert(pszTS != NULL);
- pTime->year = srSLMGParseInt32(&pszTS);
+ year = srSLMGParseInt32(&pszTS);
/* We take the liberty to accept slightly malformed timestamps e.g. in
* the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course,
@@ -178,105 +202,129 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, char** ppszTS)
* here because at postion 11, there is no "T" in such cases ;)
*/
if(*pszTS++ != '-')
- return FALSE;
- pTime->month = srSLMGParseInt32(&pszTS);
- if(pTime->month < 1 || pTime->month > 12)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ month = srSLMGParseInt32(&pszTS);
+ if(month < 1 || month > 12)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != '-')
- return FALSE;
- pTime->day = srSLMGParseInt32(&pszTS);
- if(pTime->day < 1 || pTime->day > 31)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ day = srSLMGParseInt32(&pszTS);
+ if(day < 1 || day > 31)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != 'T')
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- pTime->hour = srSLMGParseInt32(&pszTS);
- if(pTime->hour < 0 || pTime->hour > 23)
- return FALSE;
+ hour = srSLMGParseInt32(&pszTS);
+ if(hour < 0 || hour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->minute = srSLMGParseInt32(&pszTS);
- if(pTime->minute < 0 || pTime->minute > 59)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ minute = srSLMGParseInt32(&pszTS);
+ if(minute < 0 || minute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->second = srSLMGParseInt32(&pszTS);
- if(pTime->second < 0 || pTime->second > 60)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ second = srSLMGParseInt32(&pszTS);
+ if(second < 0 || second > 60)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* Now let's see if we have secfrac */
- if(*pszTS == '.')
- {
+ if(*pszTS == '.') {
char *pszStart = ++pszTS;
- pTime->secfrac = srSLMGParseInt32(&pszTS);
- pTime->secfracPrecision = (int) (pszTS - pszStart);
- }
- else
- {
- pTime->secfracPrecision = 0;
- pTime->secfrac = 0;
+ secfrac = srSLMGParseInt32(&pszTS);
+ secfracPrecision = (int) (pszTS - pszStart);
+ } else {
+ secfracPrecision = 0;
+ secfrac = 0;
}
/* check the timezone */
if(*pszTS == 'Z')
{
pszTS++; /* eat Z */
- pTime->OffsetMode = 'Z';
- pTime->OffsetHour = 0;
- pTime->OffsetMinute = 0;
- }
- else if((*pszTS == '+') || (*pszTS == '-'))
- {
- pTime->OffsetMode = *pszTS;
+ OffsetMode = 'Z';
+ OffsetHour = 0;
+ OffsetMinute = 0;
+ } else if((*pszTS == '+') || (*pszTS == '-')) {
+ OffsetMode = *pszTS;
pszTS++;
- pTime->OffsetHour = srSLMGParseInt32(&pszTS);
- if(pTime->OffsetHour < 0 || pTime->OffsetHour > 23)
- return FALSE;
+ OffsetHour = srSLMGParseInt32(&pszTS);
+ if(OffsetHour < 0 || OffsetHour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->OffsetMinute = srSLMGParseInt32(&pszTS);
- if(pTime->OffsetMinute < 0 || pTime->OffsetMinute > 59)
- return FALSE;
- }
- else
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ OffsetMinute = srSLMGParseInt32(&pszTS);
+ if(OffsetMinute < 0 || OffsetMinute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ } else {
/* there MUST be TZ information */
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ }
/* OK, we actually have a 3339 timestamp, so let's indicated this */
if(*pszTS == ' ')
++pszTS;
else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- /* update parse pointer */
+ /* we had success, so update parse pointer and caller-provided timestamp */
*ppszTS = pszTS;
+ pTime->timeType = 2;
+ pTime->year = year;
+ pTime->month = month;
+ pTime->day = day;
+ pTime->hour = hour;
+ pTime->minute = minute;
+ pTime->second = second;
+ pTime->secfrac = secfrac;
+ pTime->secfracPrecision = secfracPrecision;
+ pTime->OffsetMode = OffsetMode;
+ pTime->OffsetHour = OffsetHour;
+ pTime->OffsetMinute = OffsetMinute;
- return TRUE;
+finalize_it:
+ RETiRet;
}
/**
- * Parse a TIMESTAMP-3164.
- * Returns TRUE on parse OK, FALSE on parse error.
+ * Parse a TIMESTAMP-3164. The pTime parameter
+ * is guranteed to be updated only if a new valid timestamp
+ * could be obtained (restriction added 2008-09-16 by rgerhards). This
+ * also means the caller *must* provide a valid (probably current)
+ * timstamp in pTime when calling this function. a 3164 timestamp contains
+ * only partial information and only that partial information is updated.
+ * So the "output timestamp" is a valid timestamp only if the "input
+ * timestamp" was valid, too. The is actually an optimization, as it
+ * permits us to use a pre-aquired timestamp and thus avoids to do
+ * a (costly) time() call. Thanks to David Lang for insisting on
+ * time() call reduction ;).
*/
-static int
+static rsRetVal
ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
{
+ /* variables to temporarily hold time information while we parse */
+ int month;
+ int day;
+ int year = 0; /* 0 means no year provided */
+ int hour; /* 24 hour clock */
+ int minute;
+ int second;
+ /* end variables to temporarily hold time information while we parse */
char *pszTS;
+ DEFiRet;
assert(ppszTS != NULL);
pszTS = *ppszTS;
assert(pszTS != NULL);
assert(pTime != NULL);
- getCurrTime(pTime); /* obtain the current year and UTC offsets! */
-
/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
* we may see the following character sequences occur:
*
@@ -301,117 +349,117 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
++pszTS;
if(*pszTS == 'n') {
++pszTS;
- pTime->month = 1;
+ month = 1;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else if(*pszTS == 'u') {
++pszTS;
if(*pszTS == 'n') {
++pszTS;
- pTime->month = 6;
+ month = 6;
} else if(*pszTS == 'l') {
++pszTS;
- pTime->month = 7;
+ month = 7;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'F':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'b') {
++pszTS;
- pTime->month = 2;
+ month = 2;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'M':
if(*pszTS == 'a') {
++pszTS;
if(*pszTS == 'r') {
++pszTS;
- pTime->month = 3;
+ month = 3;
} else if(*pszTS == 'y') {
++pszTS;
- pTime->month = 5;
+ month = 5;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'A':
if(*pszTS == 'p') {
++pszTS;
if(*pszTS == 'r') {
++pszTS;
- pTime->month = 4;
+ month = 4;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else if(*pszTS == 'u') {
++pszTS;
if(*pszTS == 'g') {
++pszTS;
- pTime->month = 8;
+ month = 8;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'S':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'p') {
++pszTS;
- pTime->month = 9;
+ month = 9;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'O':
if(*pszTS == 'c') {
++pszTS;
if(*pszTS == 't') {
++pszTS;
- pTime->month = 10;
+ month = 10;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'N':
if(*pszTS == 'o') {
++pszTS;
if(*pszTS == 'v') {
++pszTS;
- pTime->month = 11;
+ month = 11;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'D':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'c') {
++pszTS;
- pTime->month = 12;
+ month = 12;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
default:
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
}
/* done month */
if(*pszTS++ != ' ')
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* we accept a slightly malformed timestamp when receiving. This is
* we accept one-digit days
@@ -419,42 +467,69 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
if(*pszTS == ' ')
++pszTS;
- pTime->day = srSLMGParseInt32(&pszTS);
- if(pTime->day < 1 || pTime->day > 31)
- return FALSE;
+ day = srSLMGParseInt32(&pszTS);
+ if(day < 1 || day > 31)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ' ')
- return FALSE;
- pTime->hour = srSLMGParseInt32(&pszTS);
- if(pTime->hour < 0 || pTime->hour > 23)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+
+ /* time part */
+ hour = srSLMGParseInt32(&pszTS);
+ if(hour > 1970 && hour < 2100) {
+ /* if so, we assume this actually is a year. This is a format found
+ * e.g. in Cisco devices.
+ * (if you read this 2100+ trying to fix a bug, congratulate myself
+ * to how long the code survived - me no longer ;)) -- rgerhards, 2008-11-18
+ */
+ year = hour;
+
+ /* re-query the hour, this time it must be valid */
+ if(*pszTS++ != ' ')
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ hour = srSLMGParseInt32(&pszTS);
+ }
+
+ if(hour < 0 || hour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->minute = srSLMGParseInt32(&pszTS);
- if(pTime->minute < 0 || pTime->minute > 59)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ minute = srSLMGParseInt32(&pszTS);
+ if(minute < 0 || minute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->second = srSLMGParseInt32(&pszTS);
- if(pTime->second < 0 || pTime->second > 60)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ second = srSLMGParseInt32(&pszTS);
+ if(second < 0 || second > 60)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- /* we provide support for an exter ":" after the date. While this is an
+ /* we provide support for an extra ":" after the date. While this is an
* invalid format, it occurs frequently enough (e.g. with Cisco devices)
* to permit it as a valid case. -- rgerhards, 2008-09-12
*/
if(*pszTS++ == ':')
- ++pszTS;
+ ++pszTS; /* just skip past it */
- /* OK, we actually have a 3164 timestamp, so let's indicate this
- * and fill the rest of the properties. */
+ /* we had success, so update parse pointer and caller-provided timestamp
+ * fields we do not have are not updated in the caller's timestamp. This
+ * is the reason why the caller must pass in a correct timestamp.
+ */
+ *ppszTS = pszTS; /* provide updated parse position back to caller */
pTime->timeType = 1;
+ pTime->month = month;
+ if(year > 0)
+ pTime->year = year; /* persist year if detected */
+ pTime->day = day;
+ pTime->hour = hour;
+ pTime->minute = minute;
+ pTime->second = second;
pTime->secfracPrecision = 0;
pTime->secfrac = 0;
- *ppszTS = pszTS; /* provide updated parse position back to caller */
- return TRUE;
+
+finalize_it:
+ RETiRet;
}
/*******************************************************************
diff --git a/runtime/datetime.h b/runtime/datetime.h
index 755cc0ed..0739588d 100644
--- a/runtime/datetime.h
+++ b/runtime/datetime.h
@@ -35,9 +35,9 @@ typedef struct datetime_s {
/* interfaces */
BEGINinterface(datetime) /* name must also be changed in ENDinterface macro! */
- void (*getCurrTime)(struct syslogTime *t);
- int (*ParseTIMESTAMP3339)(struct syslogTime *pTime, char** ppszTS);
- int (*ParseTIMESTAMP3164)(struct syslogTime *pTime, char** pszTS);
+ void (*getCurrTime)(struct syslogTime *t, time_t *ttSeconds);
+ rsRetVal (*ParseTIMESTAMP3339)(struct syslogTime *pTime, char** ppszTS);
+ rsRetVal (*ParseTIMESTAMP3164)(struct syslogTime *pTime, char** pszTS);
int (*formatTimestampToMySQL)(struct syslogTime *ts, char* pDst, size_t iLenDst);
int (*formatTimestampToPgSQL)(struct syslogTime *ts, char *pDst, size_t iLenDst);
int (*formatTimestamp3339)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
diff --git a/runtime/debug.c b/runtime/debug.c
index 9d45c737..96004e47 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -1,3 +1,4 @@
+#include <sys/syscall.h>
/* debug.c
*
* This file proides debug and run time error analysis support. Some of the
@@ -43,6 +44,9 @@
#include <pthread.h>
#include <ctype.h>
#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#include "rsyslog.h"
#include "debug.h"
@@ -62,8 +66,8 @@ static int bPrintTime = 1; /* print a timestamp together with debug message */
static int bPrintAllDebugOnExit = 0;
static int bAbortTrace = 1; /* print a trace after SIGABRT or SIGSEGV */
static char *pszAltDbgFileName = NULL; /* if set, debug output is *also* sent to here */
-static FILE *altdbg = NULL; /* and the handle for alternate debug output */
-static FILE *stddbg;
+static int altdbg = -1; /* and the handle for alternate debug output */
+static int stddbg;
/* list of files/objects that should be printed */
typedef struct dbgPrintName_s {
@@ -113,8 +117,7 @@ static dbgThrdInfo_t *dbgCallStackListRoot = NULL;
static dbgThrdInfo_t *dbgCallStackListLast = NULL;
static pthread_mutex_t mutCallStack;
-static pthread_mutex_t mutdbgprintf;
-static pthread_mutex_t mutdbgoprint;
+static pthread_mutex_t mutdbgprint;
static pthread_key_t keyCallStack;
@@ -529,7 +532,23 @@ static inline void dbgMutexUnlockLog(pthread_mutex_t *pmut, dbgFuncDB_t *pFuncDB
pthread_mutex_lock(&mutMutLog);
pLog = dbgMutLogFindSpecific(pmut, MUTOP_LOCK, NULL);
+#if 0 /* toggle for testing */
assert(pLog != NULL);
+#else
+/* the change below seems not to work - the problem seems to be a real race... I keep this code in just in case
+ * I need to re-use it. It should be removed once we are finished analyzing this problem. -- rgerhards, 2008-09-17
+ */
+if(pLog == NULL) {
+ /* this may happen due to some races. We do not try to avoid
+ * this, as it would complicate the "real" code. This is not justified
+ * just to keep the debug info system up. -- rgerhards, 2008-09-17
+ */
+ pthread_mutex_unlock(&mutMutLog);
+ dbgprintf("%s:%d:%s: mutex %p UNlocked [but we did not yet know this mutex!]\n",
+ pFuncDB->file, unlockLn, pFuncDB->func, (void*)pmut);
+ return; /* if we don't know it yet, we can not clean up... */
+}
+#endif
/* we found the last lock entry. We now need to see from which FuncDB we need to
* remove it. This is recorded inside the mutex log entry.
@@ -801,8 +820,6 @@ sigsegvHdlr(int signum)
}
dbgprintf("\n\nTo submit bug reports, visit http://www.rsyslog.com/bugs\n\n");
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
/* and finally abort... */
/* TODO: think about restarting rsyslog in this case: may be a good idea,
@@ -811,56 +828,47 @@ sigsegvHdlr(int signum)
abort();
}
-
+#if 1
#pragma GCC diagnostic ignored "-Wempty-body"
-/* print some debug output when an object is given
- * This is mostly a copy of dbgprintf, but I do not know how to combine it
- * into a single function as we have variable arguments and I don't know how to call
- * from one vararg function into another. I don't dig in this, it is OK for the
- * time being. -- rgerhards, 2008-01-29
+/* write the debug message. This is a helper to dbgprintf and dbgoprint which
+ * contains common code. added 2008-09-26 rgerhards
*/
-void
-dbgoprint(obj_t *pObj, char *fmt, ...)
+static void
+dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
{
static pthread_t ptLastThrdID = 0;
static int bWasNL = 0;
- va_list ap;
- static char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
- static char pszWriteBuf[1024];
+ char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
+ char pszWriteBuf[1024];
size_t lenWriteBuf;
struct timespec t;
+ uchar *pszObjName = NULL;
- if(!(Debug && debugging_on))
- return;
-
- /* a quick and very dirty hack to enable us to display just from those objects
- * that we are interested in. So far, this must be changed at compile time (and
- * chances are great it is commented out while you read it. Later, this shall
- * be selectable via the environment. -- rgerhards, 2008-02-20
+ /* we must get the object name before we lock the mutex, because the object
+ * potentially calls back into us. If we locked the mutex, we would deadlock
+ * ourselfs. On the other hand, the GetName call needs not to be protected, as
+ * this thread has a valid reference. If such an object is deleted by another
+ * thread, we are in much more trouble than just for dbgprint(). -- rgerhards, 2008-09-26
*/
-#if 0
- if(objGetObjID(pObj) != OBJexpr)
- return;
-#endif
-
+ if(pObj != NULL) {
+ pszObjName = obj.GetName(pObj);
+ }
- pthread_mutex_lock(&mutdbgoprint);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgoprint);
+ pthread_mutex_lock(&mutdbgprint);
+ pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
/* The bWasNL handler does not really work. It works if no thread
* switching occurs during non-NL messages. Else, things are messed
* up. Anyhow, it works well enough to provide useful help during
* getting this up and running. It is questionable if the extra effort
- * is worth fixing it, giving the limited appliability.
- * rgerhards, 2005-10-25
+ * is worth fixing it, giving the limited appliability. -- rgerhards, 2005-10-25
* I have decided that it is not worth fixing it - especially as it works
- * pretty well.
- * rgerhards, 2007-06-15
+ * pretty well. -- rgerhards, 2007-06-15
*/
if(ptLastThrdID != pthread_self()) {
if(!bWasNL) {
- if(stddbg != NULL) fprintf(stddbg, "\n");
- if(altdbg != NULL) fprintf(altdbg, "\n");
+ if(stddbg != -1) write(stddbg, "\n", 1);
+ if(altdbg != -1) write(altdbg, "\n", 1);
bWasNL = 1;
}
ptLastThrdID = pthread_self();
@@ -874,113 +882,84 @@ dbgoprint(obj_t *pObj, char *fmt, ...)
if(bWasNL) {
if(bPrintTime) {
clock_gettime(CLOCK_REALTIME, &t);
- if(stddbg != NULL) fprintf(stddbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(altdbg != NULL) fprintf(altdbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf),
+ "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
}
- if(stddbg != NULL) fprintf(stddbg, "%s: ", pszThrdName);
- if(altdbg != NULL) fprintf(altdbg, "%s: ", pszThrdName);
+
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszThrdName);
+ // use for testing: lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "{%ld}%s: ", (long) syscall(SYS_gettid), pszThrdName);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
/* print object name header if we have an object */
- if(pObj != NULL) {
- if(stddbg != NULL) fprintf(stddbg, "%s: ", obj.GetName(pObj));
- if(altdbg != NULL) fprintf(altdbg, "%s: ", obj.GetName(pObj));
+ if(pszObjName != NULL) {
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszObjName);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
}
}
- bWasNL = (*(fmt + strlen(fmt) - 1) == '\n') ? 1 : 0;
+ if(stddbg != -1) write(stddbg, pszMsg, lenMsg);
+ if(altdbg != -1) write(altdbg, pszMsg, lenMsg);
+
+ bWasNL = (pszMsg[lenMsg - 1] == '\n') ? 1 : 0;
+
+ pthread_cleanup_pop(1);
+}
+#pragma GCC diagnostic warning "-Wempty-body"
+#endif
+
+/* print some debug output when an object is given
+ * This is mostly a copy of dbgprintf, but I do not know how to combine it
+ * into a single function as we have variable arguments and I don't know how to call
+ * from one vararg function into another. I don't dig in this, it is OK for the
+ * time being. -- rgerhards, 2008-01-29
+ */
+void
+dbgoprint(obj_t *pObj, char *fmt, ...)
+{
+ va_list ap;
+ char pszWriteBuf[1024];
+ size_t lenWriteBuf;
+
+ if(!(Debug && debugging_on))
+ return;
+
+ /* a quick and very dirty hack to enable us to display just from those objects
+ * that we are interested in. So far, this must be changed at compile time (and
+ * chances are great it is commented out while you read it. Later, this shall
+ * be selectable via the environment. -- rgerhards, 2008-02-20
+ */
+#if 0
+ if(objGetObjID(pObj) != OBJexpr)
+ return;
+#endif
+
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
- if(lenWriteBuf >= sizeof(pszWriteBuf)) {
- /* if our buffer was too small, we simply truncate. TODO: maybe something better? */
- lenWriteBuf = sizeof(pszWriteBuf) - 1;
- }
va_end(ap);
- /*
- if(stddbg != NULL) fprintf(stddbg, "%s", pszWriteBuf);
- if(altdbg != NULL) fprintf(altdbg, "%s", pszWriteBuf);
- */
- if(stddbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, stddbg);
- if(altdbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, altdbg);
-
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
- pthread_cleanup_pop(1);
+ dbgprint(pObj, pszWriteBuf, lenWriteBuf);
}
-#pragma GCC diagnostic warning "-Wempty-body"
-#pragma GCC diagnostic ignored "-Wempty-body"
/* print some debug output when no object is given
* WARNING: duplicate code, see dbgoprin above!
*/
void
dbgprintf(char *fmt, ...)
{
- static pthread_t ptLastThrdID = 0;
- static int bWasNL = 0;
va_list ap;
- static char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
- static char pszWriteBuf[1024];
+ char pszWriteBuf[1024];
size_t lenWriteBuf;
- struct timespec t;
if(!(Debug && debugging_on))
return;
- pthread_mutex_lock(&mutdbgprintf);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprintf);
-
- /* The bWasNL handler does not really work. It works if no thread
- * switching occurs during non-NL messages. Else, things are messed
- * up. Anyhow, it works well enough to provide useful help during
- * getting this up and running. It is questionable if the extra effort
- * is worth fixing it, giving the limited appliability.
- * rgerhards, 2005-10-25
- * I have decided that it is not worth fixing it - especially as it works
- * pretty well.
- * rgerhards, 2007-06-15
- */
- if(ptLastThrdID != pthread_self()) {
- if(!bWasNL) {
- if(stddbg != NULL) fprintf(stddbg, "\n");
- if(altdbg != NULL) fprintf(altdbg, "\n");
- bWasNL = 1;
- }
- ptLastThrdID = pthread_self();
- }
-
- /* do not cache the thread name, as the caller might have changed it
- * TODO: optimized, invalidate cache when new name is set
- */
- dbgGetThrdName(pszThrdName, sizeof(pszThrdName), ptLastThrdID, 0);
-
- if(bWasNL) {
- if(bPrintTime) {
- clock_gettime(CLOCK_REALTIME, &t);
- if(stddbg != NULL) fprintf(stddbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(altdbg != NULL) fprintf(altdbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- }
- if(stddbg != NULL) fprintf(stddbg, "%s: ", pszThrdName);
- if(altdbg != NULL) fprintf(altdbg, "%s: ", pszThrdName);
- }
- bWasNL = (*(fmt + strlen(fmt) - 1) == '\n') ? 1 : 0;
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
- if(lenWriteBuf >= sizeof(pszWriteBuf)) {
- /* if our buffer was too small, we simply truncate. TODO: maybe something better? */
- lenWriteBuf = sizeof(pszWriteBuf) - 1;
- }
va_end(ap);
- /*
- if(stddbg != NULL) fprintf(stddbg, "%s", pszWriteBuf);
- if(altdbg != NULL) fprintf(altdbg, "%s", pszWriteBuf);
- */
- if(stddbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, stddbg);
- if(altdbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, altdbg);
-
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
- pthread_cleanup_pop(1);
+ dbgprint(NULL, pszWriteBuf, lenWriteBuf);
}
-#pragma GCC diagnostic warning "-Wempty-body"
void tester(void)
{
@@ -994,7 +973,7 @@ ENDfunc
int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int line)
{
int iStackPtr = 0; /* TODO: find some better default, this one hurts the least, but it is not clean */
- dbgThrdInfo_t *pThrd = dbgGetThrdInfo();
+ dbgThrdInfo_t *pThrd;
dbgFuncDBListEntry_t *pFuncDBListEntry;
unsigned int i;
dbgFuncDB_t *pFuncDB;
@@ -1005,6 +984,8 @@ int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int
pFuncDB = *ppFuncDB;
assert((pFuncDB == NULL) || (pFuncDB->magic == dbgFUNCDB_MAGIC));
+ pThrd = dbgGetThrdInfo(); /* we must do this AFTER the mutexes are initialized! */
+
if(pFuncDB == NULL) {
/* we do not yet have a funcDB and need to create a new one. We also add it
* to the linked list of funcDBs. Please note that when a module is unloaded and
@@ -1259,7 +1240,7 @@ dbgGetRuntimeOptions(void)
uchar *optname;
/* set some defaults */
- stddbg = stdout;
+ stddbg = 1;
if((pszOpts = (uchar*) getenv("RSYSLOG_DEBUG")) != NULL) {
/* we have options set, so let's process them */
@@ -1301,7 +1282,7 @@ dbgGetRuntimeOptions(void)
} else if(!strcasecmp((char*)optname, "nologtimestamp")) {
bPrintTime = 0;
} else if(!strcasecmp((char*)optname, "nostdout")) {
- stddbg = NULL;
+ stddbg = -1;
} else if(!strcasecmp((char*)optname, "noaborttrace")) {
bAbortTrace = 0;
} else if(!strcasecmp((char*)optname, "filetrace")) {
@@ -1326,7 +1307,7 @@ dbgGetRuntimeOptions(void)
rsRetVal dbgClassInit(void)
{
- DEFiRet;
+ rsRetVal iRet; /* do not use DEFiRet, as this makes calls into the debug system! */
struct sigaction sigAct;
sigset_t sigSet;
@@ -1340,8 +1321,7 @@ rsRetVal dbgClassInit(void)
pthread_mutex_init(&mutFuncDBList, NULL);
pthread_mutex_init(&mutMutLog, NULL);
pthread_mutex_init(&mutCallStack, NULL);
- pthread_mutex_init(&mutdbgprintf, NULL);
- pthread_mutex_init(&mutdbgoprint, NULL);
+ pthread_mutex_init(&mutdbgprint, NULL);
/* while we try not to use any of the real rsyslog code (to avoid infinite loops), we
* need to have the ability to query object names. Thus, we need to obtain a pointer to
@@ -1363,7 +1343,7 @@ rsRetVal dbgClassInit(void)
if(pszAltDbgFileName != NULL) {
/* we have a secondary file, so let's open it) */
- if((altdbg = fopen(pszAltDbgFileName, "w")) == NULL) {
+ if((altdbg = open(pszAltDbgFileName, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, S_IRUSR|S_IWUSR)) == -1) {
fprintf(stderr, "alternate debug file could not be opened, ignoring. Error: %s\n", strerror(errno));
}
}
@@ -1371,7 +1351,7 @@ rsRetVal dbgClassInit(void)
dbgSetThrdName((uchar*)"main thread");
finalize_it:
- RETiRet;
+ return(iRet);
}
@@ -1383,8 +1363,8 @@ rsRetVal dbgClassExit(void)
if(bPrintAllDebugOnExit)
dbgPrintAllDebugInfo();
- if(altdbg != NULL)
- fclose(altdbg);
+ if(altdbg != -1)
+ close(altdbg);
/* now free all of our memory to make the memory debugger happy... */
pFuncDBListEtry = pFuncDBListRoot;
diff --git a/runtime/debug.h b/runtime/debug.h
index ed914677..1375493d 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -101,6 +101,8 @@ void dbgSetThrdName(uchar *pszName);
void dbgPrintAllDebugInfo(void);
/* macros */
+#define DBGPRINTF(...) if(Debug) { dbgprintf(__VA_ARGS__); }
+#define DBGOPRINT(...) if(Debug) { dbgoprint(__VA_ARGS__); }
#ifdef RTINST
# define BEGINfunc static dbgFuncDB_t *pdbgFuncDB; int dbgCALLStaCK_POP_POINT = dbgEntrFunc(&pdbgFuncDB, __FILE__, __func__, __LINE__);
# define ENDfunc dbgExitFunc(pdbgFuncDB, dbgCALLStaCK_POP_POINT, RS_RET_NO_IRET);
@@ -132,7 +134,8 @@ void dbgPrintAllDebugInfo(void);
/* debug aides */
-#ifdef RTINST
+//#ifdef RTINST
+#if 0 // temporarily removed for helgrind
#define d_pthread_mutex_lock(x) dbgMutexLock(x, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
#define d_pthread_mutex_trylock(x) dbgMutexTryLock(x, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
#define d_pthread_mutex_unlock(x) dbgMutexUnlock(x, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
diff --git a/runtime/expr.c b/runtime/expr.c
index ee5b9e2c..38ed1c68 100644
--- a/runtime/expr.c
+++ b/runtime/expr.c
@@ -55,11 +55,63 @@ DEFobjCurrIf(ctok)
* rgerhards, 2008-02-19
*/
-/* forward definiton - thanks to recursive ABNF, we can not avoid at least one ;) */
+/* forward definition - thanks to recursive ABNF, we can not avoid at least one ;) */
static rsRetVal expr(expr_t *pThis, ctok_t *tok);
static rsRetVal
+function(expr_t *pThis, ctok_t *tok)
+{
+ DEFiRet;
+ ctok_token_t *pToken = NULL;
+ int iNumArgs = 0;
+ var_t *pVar;
+
+ ISOBJ_TYPE_assert(pThis, expr);
+ ISOBJ_TYPE_assert(tok, ctok);
+
+ CHKiRet(ctok.GetToken(tok, &pToken));
+ /* note: pToken is destructed in finalize_it */
+
+ if(pToken->tok == ctok_LPAREN) {
+ CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */
+ CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */
+ } else
+ ABORT_FINALIZE(RS_RET_FUNC_NO_LPAREN);
+
+ /* we first push all the params on the stack. Then we call the function */
+ while(pToken->tok != ctok_RPAREN) {
+ ++iNumArgs;
+ CHKiRet(ctok.UngetToken(tok, pToken)); /* not for us, so let others process it */
+ CHKiRet(expr(pThis, tok));
+ CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one, needed for while() check */
+ if(pToken->tok == ctok_COMMA) {
+ CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */
+ CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */
+ if(pToken->tok == ctok_RPAREN) {
+ ABORT_FINALIZE(RS_RET_FUNC_MISSING_EXPR);
+ }
+ }
+ }
+
+
+ /* now push number of arguments - this must be on top of the stack */
+ CHKiRet(var.Construct(&pVar));
+ CHKiRet(var.ConstructFinalize(pVar));
+ CHKiRet(var.SetNumber(pVar, iNumArgs));
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */
+
+
+finalize_it:
+ if(pToken != NULL) {
+ ctok_token.Destruct(&pToken); /* "eat" processed token */
+ }
+
+ RETiRet;
+}
+
+
+static rsRetVal
terminal(expr_t *pThis, ctok_t *tok)
{
DEFiRet;
@@ -85,8 +137,12 @@ terminal(expr_t *pThis, ctok_t *tok)
break;
case ctok_FUNCTION:
dbgoprint((obj_t*) pThis, "function\n");
- /* TODO: vm: call - well, need to implement that first */
- ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED);
+ CHKiRet(function(pThis, tok)); /* this creates the stack call frame */
+ /* ... but we place the call instruction onto the stack ourselfs (because
+ * we have all relevant information)
+ */
+ CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_FUNC_CALL, pVar)); /* add to program */
break;
case ctok_MSGVAR:
dbgoprint((obj_t*) pThis, "MSGVAR\n");
@@ -406,6 +462,7 @@ ENDobjQueryInterface(expr)
*/
BEGINObjClassInit(expr, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* request objects we use */
+ CHKiRet(objUse(var, CORE_COMPONENT));
CHKiRet(objUse(vmprg, CORE_COMPONENT));
CHKiRet(objUse(var, CORE_COMPONENT));
CHKiRet(objUse(ctok_token, CORE_COMPONENT));
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 11a664f8..28f14320 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -51,11 +51,16 @@ DEFobjStaticHelpers
* class...
*/
static uchar *pszWorkDir = NULL;
+static int bOptimizeUniProc = 1; /* enable uniprocessor optimizations */
+static int bHUPisRestart = 1; /* should SIGHUP cause a full system restart? */
+static int bPreserveFQDN = 0; /* should FQDNs always be preserved? */
+static int iMaxLine = 2048; /* maximum length of a syslog message */
static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
static int bDisableDNS = 0; /* don't look up IP addresses of remote messages */
static uchar *LocalHostName = NULL;/* our hostname - read-only after startup */
+static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup */
static uchar *LocalDomain; /* our local domain name - read-only after startup */
static char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u., never touched by init */
static char **LocalHosts = NULL;/* these hosts are logged with their hostname - read-only after startup, never touched by init */
@@ -84,6 +89,10 @@ static dataType Get##nameFunc(void) \
return(nameVar); \
}
+SIMP_PROP(OptimizeUniProc, bOptimizeUniProc, int)
+SIMP_PROP(PreserveFQDN, bPreserveFQDN, int)
+SIMP_PROP(HUPisRestart, bHUPisRestart, int)
+SIMP_PROP(MaxLine, iMaxLine, int)
SIMP_PROP(DefPFFamily, iDefPFFamily, int) /* note that in the future we may check the family argument */
SIMP_PROP(DropMalPTRMsgs, bDropMalPTRMsgs, int)
SIMP_PROP(Option_DisallowWarning, option_DisallowWarning, int)
@@ -92,6 +101,7 @@ SIMP_PROP(LocalDomain, LocalDomain, uchar*)
SIMP_PROP(StripDomains, StripDomains, char**)
SIMP_PROP(LocalHosts, LocalHosts, char**)
+SIMP_PROP_SET(LocalFQDNName, LocalFQDNName, uchar*)
SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*)
SIMP_PROP_SET(DfltNetstrmDrvr, pszDfltNetstrmDrvr, uchar*) /* TODO: use custom function which frees existing value */
SIMP_PROP_SET(DfltNetstrmDrvrCAF, pszDfltNetstrmDrvrCAF, uchar*) /* TODO: use custom function which frees existing value */
@@ -108,7 +118,27 @@ SIMP_PROP_SET(DfltNetstrmDrvrCertFile, pszDfltNetstrmDrvrCertFile, uchar*) /* TO
static uchar*
GetLocalHostName(void)
{
- return(LocalHostName == NULL ? (uchar*) "[localhost]" : LocalHostName);
+ uchar *pszRet;
+
+ if(LocalHostName == NULL)
+ pszRet = (uchar*) "[localhost]";
+ else {
+ if(GetPreserveFQDN() == 1)
+ pszRet = LocalFQDNName;
+ else
+ pszRet = LocalHostName;
+ }
+ return(pszRet);
+}
+
+
+/* return the current localhost name as FQDN (requires FQDN to be set)
+ * TODO: we should set the FQDN ourselfs in here!
+ */
+static uchar*
+GetLocalFQDNName(void)
+{
+ return(LocalFQDNName == NULL ? (uchar*) "[localhost]" : LocalFQDNName);
}
@@ -170,10 +200,15 @@ CODESTARTobjQueryInterface(glbl)
#define SIMP_PROP(name) \
pIf->Get##name = Get##name; \
pIf->Set##name = Set##name;
+ SIMP_PROP(MaxLine);
+ SIMP_PROP(OptimizeUniProc);
+ SIMP_PROP(PreserveFQDN);
+ SIMP_PROP(HUPisRestart);
SIMP_PROP(DefPFFamily);
SIMP_PROP(DropMalPTRMsgs);
SIMP_PROP(Option_DisallowWarning);
SIMP_PROP(DisableDNS);
+ SIMP_PROP(LocalFQDNName)
SIMP_PROP(LocalHostName)
SIMP_PROP(LocalDomain)
SIMP_PROP(StripDomains)
@@ -213,6 +248,9 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
pszWorkDir = NULL;
}
bDropMalPTRMsgs = 0;
+ bOptimizeUniProc = 1;
+ bHUPisRestart = 1;
+ bPreserveFQDN = 0;
return RS_RET_OK;
}
@@ -232,6 +270,9 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */
CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"hupisrestart", 0, eCmdHdlrBinary, NULL, &bHUPisRestart, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
ENDObjClassInit(glbl)
@@ -252,6 +293,8 @@ BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */
free(pszWorkDir);
if(LocalHostName != NULL)
free(LocalHostName);
+ if(LocalFQDNName != NULL)
+ free(LocalFQDNName);
ENDObjClassExit(glbl)
/* vi:set ai:
diff --git a/runtime/glbl.h b/runtime/glbl.h
index 90436319..5bdf4f57 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -40,10 +40,15 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
#define SIMP_PROP(name, dataType) \
dataType (*Get##name)(void); \
rsRetVal (*Set##name)(dataType);
+ SIMP_PROP(MaxLine, int)
+ SIMP_PROP(OptimizeUniProc, int)
+ SIMP_PROP(HUPisRestart, int)
+ SIMP_PROP(PreserveFQDN, int)
SIMP_PROP(DefPFFamily, int)
SIMP_PROP(DropMalPTRMsgs, int)
SIMP_PROP(Option_DisallowWarning, int)
SIMP_PROP(DisableDNS, int)
+ SIMP_PROP(LocalFQDNName, uchar*)
SIMP_PROP(LocalHostName, uchar*)
SIMP_PROP(LocalDomain, uchar*)
SIMP_PROP(StripDomains, char**)
@@ -54,7 +59,8 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
SIMP_PROP(DfltNetstrmDrvrCertFile, uchar*)
#undef SIMP_PROP
ENDinterface(glbl)
-#define glblCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define glblCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
+/* version 2 had PreserveFQDN added - rgerhards, 2008-12-08 */
/* the remaining prototypes */
PROTOTYPEObj(glbl);
diff --git a/runtime/module-template.h b/runtime/module-template.h
index eb39b587..6f7d877c 100644
--- a/runtime/module-template.h
+++ b/runtime/module-template.h
@@ -481,6 +481,33 @@ static rsRetVal afterRun(void)\
}
-/*
- * vi:set ai:
+/* doHUP()
+ * This function is optional. Currently, it is available to output plugins
+ * only, but may be made available to other types of plugins in the future.
+ * A plugin does not need to define this entry point. If if does, it gets
+ * called when a non-restart type of HUP is done. A plugin should register
+ * this function so that it can close files, connection or other ressources
+ * on HUP - if it can be assume the user wanted to do this as a part of HUP
+ * processing. Note that the name "HUP" has historical reasons, it stems back
+ * to the infamous SIGHUP which was sent to restart a syslogd. We still retain
+ * that legacy, but may move this to a different signal.
+ * rgerhards, 2008-10-22
+ */
+#define CODEqueryEtryPt_doHUP \
+ else if(!strcmp((char*) name, "doHUP")) {\
+ *pEtryPoint = doHUP;\
+ }
+#define BEGINdoHUP \
+static rsRetVal doHUP(instanceData __attribute__((unused)) *pData)\
+{\
+ DEFiRet;
+
+#define CODESTARTdoHUP
+
+#define ENDdoHUP \
+ RETiRet;\
+}
+
+
+/* vim:set ai:
*/
diff --git a/runtime/modules.c b/runtime/modules.c
index ceb4768c..d548a949 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -49,6 +49,10 @@
#include <unistd.h>
#include <sys/file.h>
+#ifdef OS_SOLARIS
+# define PATH_MAX MAXPATHLEN
+#endif
+
#include "cfsysline.h"
#include "modules.h"
#include "errmsg.h"
@@ -347,6 +351,7 @@ static rsRetVal
doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr)
{
DEFiRet;
+ rsRetVal localRet;
modInfo_t *pNew = NULL;
rsRetVal (*modGetType)(eModType_t *pType);
@@ -391,6 +396,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume));
+ /* try load optional interfaces */
+ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP);
+ if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND)
+ ABORT_FINALIZE(localRet);
break;
case eMOD_LIB:
break;
@@ -570,6 +579,8 @@ Load(uchar *pModName)
int bHasExtension;
void *pModHdlr, *pModInit;
modInfo_t *pModInfo;
+ uchar *pModDirCurr, *pModDirNext;
+ int iLoadCnt;
assert(pModName != NULL);
dbgprintf("Requested to load module '%s'\n", pModName);
@@ -591,48 +602,84 @@ Load(uchar *pModName)
pModInfo = GetNxt(pModInfo);
}
- /* now build our load module name */
- if(*pModName == '/') {
- *szPath = '\0'; /* we do not need to append the path - its already in the module name */
- iPathLen = 0;
- } else {
- *szPath = '\0';
- strncat((char *) szPath, (pModDir == NULL) ? _PATH_MODDIR : (char*) pModDir, sizeof(szPath) - 1);
- iPathLen = strlen((char*) szPath);
- if((szPath[iPathLen - 1] != '/')) {
- if((iPathLen <= sizeof(szPath) - 2)) {
- szPath[iPathLen++] = '/';
- szPath[iPathLen] = '\0';
- } else {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir);
+ pModDirNext = NULL;
+ pModHdlr = NULL;
+ iLoadCnt = 0;
+ do {
+ /* now build our load module name */
+ if(*pModName == '/') {
+ *szPath = '\0'; /* we do not need to append the path - its already in the module name */
+ iPathLen = 0;
+ } else {
+ *szPath = '\0';
+
+ iPathLen = strlen((char *)pModDirCurr);
+ pModDirNext = (uchar *)strchr((char *)pModDirCurr, ':');
+ if(pModDirNext)
+ iPathLen = (size_t)(pModDirNext - pModDirCurr);
+
+ if(iPathLen == 0) {
+ if(pModDirNext) {
+ pModDirCurr = pModDirNext + 1;
+ continue;
+ }
+ break;
+ } else if(iPathLen > sizeof(szPath) - 1) {
+ errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
}
+
+ strncat((char *) szPath, (char *)pModDirCurr, iPathLen);
+ iPathLen = strlen((char*) szPath);
+
+ if(pModDirNext)
+ pModDirCurr = pModDirNext + 1;
+
+ if((szPath[iPathLen - 1] != '/')) {
+ if((iPathLen <= sizeof(szPath) - 2)) {
+ szPath[iPathLen++] = '/';
+ szPath[iPathLen] = '\0';
+ } else {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
+ }
+ }
}
- }
- /* ... add actual name ... */
- strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1);
+ /* ... add actual name ... */
+ strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1);
+
+ /* now see if we have an extension and, if not, append ".so" */
+ if(!bHasExtension) {
+ /* we do not have an extension and so need to add ".so"
+ * TODO: I guess this is highly importable, so we should change the
+ * algo over time... -- rgerhards, 2008-03-05
+ */
+ /* ... so now add the extension */
+ strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1);
+ iPathLen += 3;
+ }
- /* now see if we have an extension and, if not, append ".so" */
- if(!bHasExtension) {
- /* we do not have an extension and so need to add ".so"
- * TODO: I guess this is highly importable, so we should change the
- * algo over time... -- rgerhards, 2008-03-05
- */
- /* ... so now add the extension */
- strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1);
- iPathLen += 3;
- }
+ if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
+ }
- if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
- ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
- }
+ /* complete load path constructed, so ... GO! */
+ dbgprintf("loading module '%s'\n", szPath);
+ pModHdlr = dlopen((char *) szPath, RTLD_NOW);
+ iLoadCnt++;
+
+ } while(pModHdlr == NULL && *pModName != '/' && pModDirNext);
- /* complete load path constructed, so ... GO! */
- dbgprintf("loading module '%s'\n", szPath);
- if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror());
+ if(!pModHdlr) {
+ if(iLoadCnt) {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror());
+ } else {
+ errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath,
+ ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir));
+ }
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN);
}
if(!(pModInit = dlsym(pModHdlr, "modInit"))) {
diff --git a/runtime/modules.h b/runtime/modules.h
index 7d34bcf7..372529ee 100644
--- a/runtime/modules.h
+++ b/runtime/modules.h
@@ -44,8 +44,11 @@
* rgerhards, 2008-03-04
* version 3 adds modInfo_t ptr to call of modInit -- rgerhards, 2008-03-10
* version 4 removes needUDPSocket OM callback -- rgerhards, 2008-03-22
+ * version 5 changes the way parsing works for input modules. This is
+ * an important change, parseAndSubmitMessage() goes away. Other
+ * module types are not affected. -- rgerhards, 2008-10-09
*/
-#define CURR_MOD_IF_VERSION 4
+#define CURR_MOD_IF_VERSION 5
typedef enum eModType_ {
eMOD_IN, /* input module */
@@ -88,6 +91,7 @@ typedef struct modInfo_s {
rsRetVal (*tryResume)(void*);/* called to see if module actin can be resumed now */
rsRetVal (*modExit)(void); /* called before termination or module unload */
rsRetVal (*modGetID)(void **); /* get its unique ID from module */
+ rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */
/* below: parse a configuration line - return if processed
* or not. If not, must be parsed to next module.
*/
diff --git a/runtime/msg.c b/runtime/msg.c
index d02b0a04..9aa2ce84 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -42,6 +42,7 @@
#include "msg.h"
#include "var.h"
#include "datetime.h"
+#include "glbl.h"
#include "regexp.h"
#include "atomic.h"
@@ -49,6 +50,7 @@
DEFobjStaticHelpers
DEFobjCurrIf(var)
DEFobjCurrIf(datetime)
+DEFobjCurrIf(glbl)
DEFobjCurrIf(regexp)
static syslogCODE rs_prioritynames[] =
@@ -138,8 +140,8 @@ void (*funcMsgPrepareEnqueue)(msg_t *pMsg);
#define MsgLock(pMsg) funcLock(pMsg)
#define MsgUnlock(pMsg) funcUnlock(pMsg)
#else
-#define MsgLock(pMsg) {dbgprintf("line %d\n - ", __LINE__); funcLock(pMsg);; }
-#define MsgUnlock(pMsg) {dbgprintf("line %d - ", __LINE__); funcUnlock(pMsg); }
+#define MsgLock(pMsg) {dbgprintf("MsgLock line %d\n - ", __LINE__); funcLock(pMsg);; }
+#define MsgUnlock(pMsg) {dbgprintf("MsgUnlock line %d - ", __LINE__); funcUnlock(pMsg); }
#endif
/* the next function is a dummy to be used by the looking functions
@@ -240,12 +242,21 @@ rsRetVal MsgEnableThreadSafety(void)
/* end locking functions */
-/* "Constructor" for a msg "object". Returns a pointer to
+/* This is common code for all Constructors. It is defined in an
+ * inline'able function so that we can save a function call in the
+ * actual constructors (otherwise, the msgConstruct would need
+ * to call msgConstructWithTime(), which would require a
+ * function call). Now, both can use this inline function. This
+ * enables us to be optimal, but still have the code just once.
* the new object or NULL if no such object could be allocated.
* An object constructed via this function should only be destroyed
- * via "msgDestruct()".
+ * via "msgDestruct()". This constructor does not query system time
+ * itself but rather uses a user-supplied value. This enables the caller
+ * to do some tricks to save processing time (done, for example, in the
+ * udp input).
+ * rgerhards, 2008-10-06
*/
-rsRetVal msgConstruct(msg_t **ppThis)
+static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
{
DEFiRet;
msg_t *pM;
@@ -258,7 +269,6 @@ rsRetVal msgConstruct(msg_t **ppThis)
pM->iRefCount = 1;
pM->iSeverity = -1;
pM->iFacility = -1;
- datetime.getCurrTime(&(pM->tRcvdAt));
objConstructSetObjInfo(pM);
/* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/
@@ -270,12 +280,64 @@ finalize_it:
}
+/* "Constructor" for a msg "object". Returns a pointer to
+ * the new object or NULL if no such object could be allocated.
+ * An object constructed via this function should only be destroyed
+ * via "msgDestruct()". This constructor does not query system time
+ * itself but rather uses a user-supplied value. This enables the caller
+ * to do some tricks to save processing time (done, for example, in the
+ * udp input).
+ * rgerhards, 2008-10-06
+ */
+rsRetVal msgConstructWithTime(msg_t **ppThis, struct syslogTime *stTime, time_t ttGenTime)
+{
+ DEFiRet;
+
+ CHKiRet(msgBaseConstruct(ppThis));
+ (*ppThis)->ttGenTime = ttGenTime;
+ memcpy(&(*ppThis)->tRcvdAt, stTime, sizeof(struct syslogTime));
+ memcpy(&(*ppThis)->tTIMESTAMP, stTime, sizeof(struct syslogTime));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* "Constructor" for a msg "object". Returns a pointer to
+ * the new object or NULL if no such object could be allocated.
+ * An object constructed via this function should only be destroyed
+ * via "msgDestruct()". This constructor, for historical reasons,
+ * also sets the two timestamps to the current time.
+ */
+rsRetVal msgConstruct(msg_t **ppThis)
+{
+ DEFiRet;
+
+ CHKiRet(msgBaseConstruct(ppThis));
+ /* we initialize both timestamps to contain the current time, so that they
+ * are consistent. Also, this saves us from doing any further time calls just
+ * to obtain a timestamp. The memcpy() should not really make a difference,
+ * especially as I think there is no codepath currently where it would not be
+ * required (after I have cleaned up the pathes ;)). -- rgerhards, 2008-10-02
+ */
+ datetime.getCurrTime(&((*ppThis)->tRcvdAt), &((*ppThis)->ttGenTime));
+ memcpy(&(*ppThis)->tTIMESTAMP, &(*ppThis)->tRcvdAt, sizeof(struct syslogTime));
+
+finalize_it:
+ RETiRet;
+}
+
+
BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODESTART macros! */
int currRefCount;
CODESTARTobjDestruct(msg)
- /* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pM, pM->iRefCount - 1); */
- MsgLock(pThis);
- currRefCount = --pThis->iRefCount;
+ /* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pThis, pThis->iRefCount - 1); */
+# ifdef HAVE_ATOMIC_BUILTINS
+ currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
+# else
+ MsgLock(pThis);
+ currRefCount = --pThis->iRefCount;
+# endif
if(currRefCount == 0)
{
/* DEV Debugging Only! dbgprintf("msgDestruct\t0x%lx, RefCount now 0, doing DESTROY\n", (unsigned long)pThis); */
@@ -287,6 +349,8 @@ CODESTARTobjDestruct(msg)
free(pThis->pszTAG);
if(pThis->pszHOSTNAME != NULL)
free(pThis->pszHOSTNAME);
+ if(pThis->pszInputName != NULL)
+ free(pThis->pszInputName);
if(pThis->pszRcvFrom != NULL)
free(pThis->pszRcvFrom);
if(pThis->pszRcvFromIP != NULL)
@@ -333,7 +397,9 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSPROCID);
if(pThis->pCSMSGID != NULL)
rsCStrDestruct(&pThis->pCSMSGID);
+# ifndef HAVE_ATOMIC_BUILTINS
MsgUnlock(pThis);
+# endif
funcDeleteMutex(pThis);
} else {
MsgUnlock(pThis);
@@ -381,7 +447,7 @@ msg_t* MsgDup(msg_t* pOld)
assert(pOld != NULL);
BEGINfunc
- if(msgConstruct(&pNew) != RS_RET_OK) {
+ if(msgConstructWithTime(&pNew, &pOld->tTIMESTAMP, pOld->ttGenTime) != RS_RET_OK) {
return NULL;
}
@@ -392,8 +458,7 @@ msg_t* MsgDup(msg_t* pOld)
pNew->bParseHOSTNAME = pOld->bParseHOSTNAME;
pNew->msgFlags = pOld->msgFlags;
pNew->iProtocolVersion = pOld->iProtocolVersion;
- memcpy(&pNew->tRcvdAt, &pOld->tRcvdAt, sizeof(struct syslogTime));
- memcpy(&pNew->tTIMESTAMP, &pOld->tTIMESTAMP, sizeof(struct syslogTime));
+ pNew->ttGenTime = pOld->ttGenTime;
tmpCOPYSZ(Severity);
tmpCOPYSZ(SeverityStr);
tmpCOPYSZ(Facility);
@@ -447,6 +512,7 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
objSerializeSCALAR(pStrm, iSeverity, SHORT);
objSerializeSCALAR(pStrm, iFacility, SHORT);
objSerializeSCALAR(pStrm, msgFlags, INT);
+ objSerializeSCALAR(pStrm, ttGenTime, INT);
objSerializeSCALAR(pStrm, tRcvdAt, SYSLOGTIME);
objSerializeSCALAR(pStrm, tTIMESTAMP, SYSLOGTIME);
@@ -455,6 +521,7 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
objSerializePTR(pStrm, pszUxTradMsg, PSZ);
objSerializePTR(pStrm, pszTAG, PSZ);
objSerializePTR(pStrm, pszHOSTNAME, PSZ);
+ objSerializePTR(pStrm, pszInputName, PSZ);
objSerializePTR(pStrm, pszRcvFrom, PSZ);
objSerializePTR(pStrm, pszRcvFromIP, PSZ);
@@ -480,9 +547,13 @@ finalize_it:
msg_t *MsgAddRef(msg_t *pM)
{
assert(pM != NULL);
- MsgLock(pM);
- pM->iRefCount++;
- MsgUnlock(pM);
+# ifdef HAVE_ATOMIC_BUILTINS
+ ATOMIC_INC(pM->iRefCount);
+# else
+ MsgLock(pM);
+ pM->iRefCount++;
+ MsgUnlock(pM);
+# endif
/* DEV debugging only! dbgprintf("MsgAddRef\t0x%x done, Ref now: %d\n", (int)pM, pM->iRefCount);*/
return(pM);
}
@@ -678,6 +749,7 @@ char *getMSG(msg_t *pM)
char *getPRI(msg_t *pM)
{
int pri;
+ BEGINfunc
if(pM == NULL)
return "";
@@ -697,6 +769,7 @@ char *getPRI(msg_t *pM)
}
MsgUnlock(pM);
+ ENDfunc
return (char*)pM->pszPRI;
}
@@ -711,6 +784,7 @@ int getPRIi(msg_t *pM)
char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
{
+ BEGINfunc
if(pM == NULL)
return "";
@@ -782,11 +856,13 @@ char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
MsgUnlock(pM);
return(pM->pszTIMESTAMP_SecFrac);
}
+ ENDfunc
return "INVALID eFmt OPTION!";
}
char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
{
+ BEGINfunc
if(pM == NULL)
return "";
@@ -858,6 +934,7 @@ char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
MsgUnlock(pM);
return(pM->pszRcvdAt_SecFrac);
}
+ ENDfunc
return "INVALID eFmt OPTION!";
}
@@ -1217,6 +1294,18 @@ char *getHOSTNAME(msg_t *pM)
}
+uchar *getInputName(msg_t *pM)
+{
+ if(pM == NULL)
+ return (uchar*) "";
+ else
+ if(pM->pszInputName == NULL)
+ return (uchar*) "";
+ else
+ return pM->pszInputName;
+}
+
+
char *getRcvFrom(msg_t *pM)
{
if(pM == NULL)
@@ -1397,6 +1486,19 @@ static int getAPPNAMELen(msg_t *pM)
return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME);
}
+/* rgerhards 2008-09-10: set pszInputName in msg object
+ */
+void MsgSetInputName(msg_t *pMsg, char* pszInputName)
+{
+ assert(pMsg != NULL);
+ if(pMsg->pszInputName != NULL)
+ free(pMsg->pszInputName);
+
+ pMsg->iLenInputName = strlen(pszInputName);
+ if((pMsg->pszInputName = malloc(pMsg->iLenInputName + 1)) != NULL) {
+ memcpy(pMsg->pszInputName, pszInputName, pMsg->iLenInputName + 1);
+ }
+}
/* rgerhards 2004-11-16: set pszRcvFrom in msg object
*/
@@ -1578,7 +1680,7 @@ static uchar *getNOW(eNOWType eNow)
return NULL;
}
- datetime.getCurrTime(&t);
+ datetime.getCurrTime(&t, NULL);
switch(eNow) {
case NOW_NOW:
snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
@@ -1683,6 +1785,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = getRawMsg(pMsg);
} else if(!strcmp((char*) pName, "uxtradmsg")) {
pRes = getUxTradMsg(pMsg);
+ } else if(!strcmp((char*) pName, "inputname")) {
+ pRes = (char*) getInputName(pMsg);
} else if(!strcmp((char*) pName, "fromhost")) {
pRes = getRcvFrom(pMsg);
} else if(!strcmp((char*) pName, "fromhost-ip")) {
@@ -1770,6 +1874,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
+ } else if(!strcmp((char*) pName, "$myhostname")) {
+ pRes = (char*) glbl.GetLocalHostName();
} else {
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
@@ -1807,6 +1913,11 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
++pFld; /* skip to field terminator */
if(*pFld == pTpe->data.field.field_delim) {
++pFld; /* eat it */
+ if (pTpe->data.field.field_expand != 0) {
+ while (*pFld == pTpe->data.field.field_delim) {
+ ++pFld;
+ }
+ }
++iCurrFld;
}
}
@@ -2369,6 +2480,8 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
MsgSetUxTradMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszTAG")) {
MsgSetTAG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
+ } else if(isProp("pszInputName")) {
+ MsgSetInputName(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszRcvFromIP")) {
MsgSetRcvFromIP(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszRcvFrom")) {
@@ -2383,6 +2496,8 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
MsgSetPROCID(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pCSMSGID")) {
MsgSetMSGID(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
+ } else if(isProp("ttGenTime")) {
+ pThis->ttGenTime = pProp->val.num;
} else if(isProp("tRcvdAt")) {
memcpy(&pThis->tRcvdAt, &pProp->val.vSyslogTime, sizeof(struct syslogTime));
} else if(isProp("tTIMESTAMP")) {
@@ -2431,6 +2546,7 @@ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
/* request objects we use */
CHKiRet(objUse(var, CORE_COMPONENT));
CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
/* set our own handlers */
OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize);
@@ -2443,7 +2559,5 @@ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
funcDeleteMutex = MsgLockingDummy;
funcMsgPrepareEnqueue = MsgLockingDummy;
ENDObjClassInit(msg)
-
-/*
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/runtime/msg.h b/runtime/msg.h
index fadbb48a..c8350626 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -53,7 +53,9 @@ struct msg {
pthread_mutexattr_t mutAttr;
short bDoLock; /* use the mutex? */
pthread_mutex_t mut;
- int iRefCount; /* reference counter (0 = unused) */
+ flowControl_t flowCtlType; /**< type of flow control we can apply, for enqueueing, needs not to be persisted because
+ once data has entered the queue, this property is no longer needed. */
+ short iRefCount; /* reference counter (0 = unused) */
short bParseHOSTNAME; /* should the hostname be parsed from the message? */
/* background: the hostname is not present on "regular" messages
* received via UNIX domain sockets from the same machine. However,
@@ -61,8 +63,6 @@ short bDoLock; /* use the mutex? */
* sockets. All in all, the parser would need parse templates, that would
* resolve all these issues... rgerhards, 2005-10-06
*/
- flowControl_t flowCtlType; /**< type of flow control we can apply, for enqueueing, needs not to be persisted because
- once data has entered the queue, this property is no longer needed. */
short iSeverity; /* the severity 0..7 */
uchar *pszSeverity; /* severity as string... */
int iLenSeverity; /* ... and its length. */
@@ -92,12 +92,21 @@ short bDoLock; /* use the mutex? */
int iLenRcvFrom; /* Length of pszRcvFrom */
uchar *pszRcvFromIP; /* IP of system message was received from */
int iLenRcvFromIP; /* Length of pszRcvFromIP */
+ uchar *pszInputName; /* name of the input module that submitted this message */
+ int iLenInputName; /* Length of pszInputName */
short iProtocolVersion;/* protocol version of message received 0 - legacy, 1 syslog-protocol) */
cstr_t *pCSProgName; /* the (BSD) program name */
- cstr_t *pCSStrucData;/* STRUCTURED-DATA */
+ cstr_t *pCSStrucData; /* STRUCTURED-DATA */
cstr_t *pCSAPPNAME; /* APP-NAME */
cstr_t *pCSPROCID; /* PROCID */
cstr_t *pCSMSGID; /* MSGID */
+ time_t ttGenTime; /* time msg object was generated, same as tRcvdAt, but a Unix timestamp.
+ While this field looks redundant, it is required because a Unix timestamp
+ is used at later processing stages (namely in the output arena). Thanks to
+ the subleties of how time is defined, there is no reliable way to reconstruct
+ the Unix timestamp from the syslogTime fields (in practice, we may be close
+ enough to reliable, but I prefer to leave the subtle things to the OS, where
+ it obviously is solved in way or another...). */
struct syslogTime tRcvdAt;/* time the message entered this program */
char *pszRcvdAt3164; /* time as RFC3164 formatted string (always 15 charcters) */
char *pszRcvdAt3339; /* time as RFC3164 formatted string (32 charcters at most) */
@@ -113,11 +122,24 @@ short bDoLock; /* use the mutex? */
int msgFlags; /* flags associated with this message */
};
+
+/* message flags (msgFlags), not an enum for historical reasons
+ */
+#define NOFLAG 0x000 /* no flag is set (to be used when a flag must be specified and none is required) */
+#define INTERNAL_MSG 0x001 /* msg generated by logmsgInternal() --> special handling */
+/* 0x002 not used because it was previously a known value - rgerhards, 2008-10-09 */
+#define IGNDATE 0x004 /* ignore, if given, date in message and use date of reception as msg date */
+#define MARK 0x008 /* this message is a mark */
+#define NEEDS_PARSING 0x010 /* raw message, must be parsed before processing can be done */
+#define PARSE_HOSTNAME 0x020 /* parse the hostname during message parsing */
+
+
/* function prototypes
*/
PROTOTYPEObjClassInit(msg);
char* getProgramName(msg_t*);
rsRetVal msgConstruct(msg_t **ppThis);
+rsRetVal msgConstructWithTime(msg_t **ppThis, struct syslogTime *stTime, time_t ttGenTime);
rsRetVal msgDestruct(msg_t **ppM);
msg_t* MsgDup(msg_t* pOld);
msg_t *MsgAddRef(msg_t *pM);
@@ -136,6 +158,7 @@ char *getSeverity(msg_t *pM);
char *getSeverityStr(msg_t *pM);
char *getFacility(msg_t *pM);
char *getFacilityStr(msg_t *pM);
+void MsgSetInputName(msg_t *pMsg, char*);
rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME);
char *getAPPNAME(msg_t *pM);
rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID);
@@ -178,6 +201,5 @@ extern void (*funcMsgPrepareEnqueue)(msg_t *pMsg);
#define MsgPrepareEnqueue(pMsg) funcMsgPrepareEnqueue(pMsg)
#endif /* #ifndef MSG_H_INCLUDED */
-/*
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/runtime/net.c b/runtime/net.c
index c5fa771e..db2d7e37 100644
--- a/runtime/net.c
+++ b/runtime/net.c
@@ -63,6 +63,11 @@
#include "errmsg.h"
#include "net.h"
+#ifdef OS_SOLARIS
+# define s6_addr32 _S6_un._S6_u32
+ typedef unsigned int u_int32_t;
+#endif
+
MODULE_TYPE_LIB
/* static data */
@@ -1041,7 +1046,6 @@ should_use_so_bsdcompat(void)
#define SO_BSDCOMPAT 0
#endif
-
/* get the hostname of the message source. This was originally in cvthname()
* but has been moved out of it because of clarity and fuctional separation.
* It must be provided by the socket we received the message on as well as
@@ -1234,7 +1238,9 @@ rsRetVal cvthname(struct sockaddr_storage *f, uchar *pszHost, uchar *pszHostFQDN
* make this in option in the long term. (rgerhards, 2007-09-11)
*/
strcpy((char*)pszHost, (char*)pszHostFQDN);
- if ((p = (uchar*) strchr((char*)pszHost, '.'))) { /* find start of domain name "machine.example.com" */
+ if( (glbl.GetPreserveFQDN() == 0)
+ && (p = (uchar*) strchr((char*)pszHost, '.'))) { /* find start of domain name "machine.example.com" */
+ strcmp((char*)(p + 1), (char*)glbl.GetLocalDomain());
if(strcmp((char*)(p + 1), (char*)glbl.GetLocalDomain()) == 0) {
*p = '\0'; /* simply terminate the string */
} else {
diff --git a/runtime/obj.c b/runtime/obj.c
index 082aa691..2a9df9ed 100644
--- a/runtime/obj.c
+++ b/runtime/obj.c
@@ -780,7 +780,7 @@ Deserialize(void *ppObj, uchar *pszTypeExpected, strm_t *pStrm, rsRetVal (*fFixu
DEFiRet;
rsRetVal iRetLocal;
obj_t *pObj = NULL;
- int oVers = 0; /* after all, it is totally useless but takes up some execution time... */
+ int oVers = 0; /* keep compiler happy, but it is totally useless but takes up some execution time... */
cstr_t *pstrID = NULL;
objInfo_t *pObjInfo;
diff --git a/runtime/parser.c b/runtime/parser.c
new file mode 100644
index 00000000..b4ab0a3e
--- /dev/null
+++ b/runtime/parser.c
@@ -0,0 +1,315 @@
+/* parser.c
+ * This module contains functions for message parsers. It still needs to be
+ * converted into an object (and much extended).
+ *
+ * Module begun 2008-10-09 by Rainer Gerhards (based on previous code from syslogd.c)
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#include "config.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#ifdef USE_NETZIP
+#include <zlib.h>
+#endif
+
+#include "rsyslog.h"
+#include "dirty.h"
+#include "msg.h"
+#include "obj.h"
+#include "errmsg.h"
+
+/* some defines */
+#define DEFUPRI (LOG_USER|LOG_NOTICE)
+
+/* definitions for objects we access */
+DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(errmsg)
+
+/* static data */
+
+
+/* this is a dummy class init
+ */
+rsRetVal parserClassInit(void)
+{
+ DEFiRet;
+
+ /* request objects we use */
+ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+// TODO: free components! see action.c
+finalize_it:
+ RETiRet;
+}
+
+
+/* uncompress a received message if it is compressed.
+ * pMsg->pszRawMsg buffer is updated.
+ * rgerhards, 2008-10-09
+ */
+static inline rsRetVal uncompressMessage(msg_t *pMsg)
+{
+ DEFiRet;
+# ifdef USE_NETZIP
+ uchar *deflateBuf = NULL;
+ uLongf iLenDefBuf;
+ uchar *pszMsg;
+ size_t lenMsg;
+
+ assert(pMsg != NULL);
+ pszMsg = pMsg->pszRawMsg;
+ lenMsg = pMsg->iLenRawMsg;
+
+ /* we first need to check if we have a compressed record. If so,
+ * we must decompress it.
+ */
+ if(lenMsg > 0 && *pszMsg == 'z') { /* compressed data present? (do NOT change order if conditions!) */
+ /* we have compressed data, so let's deflate it. We support a maximum
+ * message size of iMaxLine. If it is larger, an error message is logged
+ * and the message is dropped. We do NOT try to decompress larger messages
+ * as such might be used for denial of service. It might happen to later
+ * builds that such functionality be added as an optional, operator-configurable
+ * feature.
+ */
+ int ret;
+ iLenDefBuf = glbl.GetMaxLine();
+ CHKmalloc(deflateBuf = malloc(sizeof(uchar) * (iLenDefBuf + 1)));
+ ret = uncompress((uchar *) deflateBuf, &iLenDefBuf, (uchar *) pszMsg+1, lenMsg-1);
+ DBGPRINTF("Compressed message uncompressed with status %d, length: new %ld, old %d.\n",
+ ret, (long) iLenDefBuf, (int) (lenMsg-1));
+ /* Now check if the uncompression worked. If not, there is not much we can do. In
+ * that case, we log an error message but ignore the message itself. Storing the
+ * compressed text is dangerous, as it contains control characters. So we do
+ * not do this. If someone would like to have a copy, this code here could be
+ * modified to do a hex-dump of the buffer in question. We do not include
+ * this functionality right now.
+ * rgerhards, 2006-12-07
+ */
+ if(ret != Z_OK) {
+ errmsg.LogError(0, NO_ERRCODE, "Uncompression of a message failed with return code %d "
+ "- enable debug logging if you need further information. "
+ "Message ignored.", ret);
+ FINALIZE; /* unconditional exit, nothing left to do... */
+ }
+ free(pMsg->pszRawMsg);
+ pMsg->pszRawMsg = deflateBuf;
+ pMsg->iLenRawMsg = iLenDefBuf;
+ deflateBuf = NULL; /* logically "freed" - caller is now responsible */
+ }
+finalize_it:
+ if(deflateBuf != NULL)
+ free(deflateBuf);
+
+# else /* ifdef USE_NETZIP */
+
+ /* in this case, we still need to check if the message is compressed. If so, we must
+ * tell the user we can not accept it.
+ */
+ if(pMsg->iLenRawMsg > 0 && *pMsg->pszRawMsg == 'z') {
+ errmsg.LogError(0, NO_ERRCODE, "Received a compressed message, but rsyslogd does not have compression "
+ "support enabled. The message will be ignored.");
+ ABORT_FINALIZE(RS_RET_NO_ZIP);
+ }
+
+finalize_it:
+# endif /* ifdef USE_NETZIP */
+
+ RETiRet;
+}
+
+
+/* sanitize a received message
+ * if a message gets to large during sanitization, it is truncated. This is
+ * as specified in the upcoming syslog RFC series.
+ * rgerhards, 2008-10-09
+ * We check if we have a NUL character at the very end of the
+ * message. This seems to be a frequent problem with a number of senders.
+ * So I have now decided to drop these NULs. However, if they are intentional,
+ * that may cause us some problems, e.g. with syslog-sign. On the other hand,
+ * current code always has problems with intentional NULs (as it needs to escape
+ * them to prevent problems with the C string libraries), so that does not
+ * really matter. Just to be on the save side, we'll log destruction of such
+ * NULs in the debug log.
+ * rgerhards, 2007-09-14
+ */
+static inline rsRetVal
+sanitizeMessage(msg_t *pMsg)
+{
+ DEFiRet;
+ uchar *pszMsg;
+ uchar *pDst; /* destination for copy job */
+ size_t lenMsg;
+ size_t iSrc;
+ size_t iDst;
+ size_t iMaxLine;
+
+ assert(pMsg != NULL);
+
+# ifdef USE_NETZIP
+ CHKiRet(uncompressMessage(pMsg));
+# endif
+
+ pszMsg = pMsg->pszRawMsg;
+ lenMsg = pMsg->iLenRawMsg;
+
+ /* remove NUL character at end of message (see comment in function header) */
+ if(pszMsg[lenMsg-1] == '\0') {
+ DBGPRINTF("dropped NUL at very end of message\n");
+ lenMsg--;
+ }
+
+ /* then we check if we need to drop trailing LFs, which often make
+ * their way into syslog messages unintentionally. In order to remain
+ * compatible to recent IETF developments, we allow the user to
+ * turn on/off this handling. rgerhards, 2007-07-23
+ */
+ if(bDropTrailingLF && pszMsg[lenMsg-1] == '\n') {
+ DBGPRINTF("dropped LF at very end of message (DropTrailingLF is set)\n");
+ lenMsg--;
+ }
+
+ /* now copy over the message and sanitize it */
+ /* TODO: can we get cheaper memory alloc? {alloca()?}*/
+ iMaxLine = glbl.GetMaxLine();
+ CHKmalloc(pDst = malloc(sizeof(uchar) * (iMaxLine + 1)));
+ iSrc = iDst = 0;
+ while(iSrc < lenMsg && iDst < iMaxLine) {
+ if(pszMsg[iSrc] == '\0') { /* guard against \0 characters... */
+ /* changed to the sequence (somewhat) proposed in
+ * draft-ietf-syslog-protocol-19. rgerhards, 2006-11-30
+ */
+ if(iDst + 3 < iMaxLine) { /* do we have space? */
+ pDst[iDst++] = cCCEscapeChar;
+ pDst[iDst++] = '0';
+ pDst[iDst++] = '0';
+ pDst[iDst++] = '0';
+ } /* if we do not have space, we simply ignore the '\0'... */
+ /* log an error? Very questionable... rgerhards, 2006-11-30 */
+ /* decided: we do not log an error, it won't help... rger, 2007-06-21 */
+ } else if(bEscapeCCOnRcv && iscntrl((int) pszMsg[iSrc])) {
+ /* we are configured to escape control characters. Please note
+ * that this most probably break non-western character sets like
+ * Japanese, Korean or Chinese. rgerhards, 2007-07-17
+ * Note: sysklogd logs octal values only for DEL and CCs above 127.
+ * For others, it logs ^n where n is the control char converted to an
+ * alphabet character. We like consistency and thus escape it to octal
+ * in all cases. If someone complains, we may change the mode. At least
+ * we known now what's going on.
+ * rgerhards, 2007-07-17
+ */
+ if(iDst + 3 < iMaxLine) { /* do we have space? */
+ pDst[iDst++] = cCCEscapeChar;
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0300) >> 6);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0070) >> 3);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0007));
+ } /* again, if we do not have space, we ignore the char - see comment at '\0' */
+ } else {
+ pDst[iDst++] = pszMsg[iSrc];
+ }
+ ++iSrc;
+ }
+ pDst[iDst] = '\0'; /* space *is* reserved for this! */
+
+ /* we have a sanitized string. Let's save it now */
+ free(pMsg->pszRawMsg);
+ if((pMsg->pszRawMsg = malloc((iDst+1) * sizeof(uchar))) == NULL) {
+ /* when we get no new buffer, we use what we already have ;) */
+ pMsg->pszRawMsg = pDst;
+ } else {
+ /* trim buffer */
+ memcpy(pMsg->pszRawMsg, pDst, iDst+1);
+ free(pDst); /* too big! */
+ pMsg->iLenRawMsg = iDst;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+/* Parse a received message. The object's rawmsg property is taken and
+ * parsed according to the relevant standards. This can later be
+ * extended to support configured parsers.
+ * rgerhards, 2008-10-09
+ */
+rsRetVal parseMsg(msg_t *pMsg)
+{
+ DEFiRet;
+ uchar *msg;
+ int pri;
+
+ CHKiRet(sanitizeMessage(pMsg));
+
+ /* we needed to sanitize first, because we otherwise do not have a C-string we can print... */
+ DBGPRINTF("msg parser: flags %x, from '%s', msg '%s'\n", pMsg->msgFlags, pMsg->pszRcvFrom, pMsg->pszRawMsg);
+
+ /* pull PRI */
+ pri = DEFUPRI;
+ msg = pMsg->pszRawMsg;
+ if(*msg == '<') {
+ pri = 0;
+ while(isdigit((int) *++msg)) {
+ pri = 10 * pri + (*msg - '0');
+ }
+ if(*msg == '>')
+ ++msg;
+ if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFUPRI;
+ }
+ pMsg->iFacility = LOG_FAC(pri);
+ pMsg->iSeverity = LOG_PRI(pri);
+ MsgSetUxTradMsg(pMsg, (char*) msg);
+
+ if(pMsg->bParseHOSTNAME == 0)
+ MsgSetHOSTNAME(pMsg, (char*) pMsg->pszRcvFrom);
+
+ /* rger 2005-11-24 (happy thanksgiving!): we now need to check if we have
+ * a traditional syslog message or one formatted according to syslog-protocol.
+ * We need to apply different parsers depending on that. We use the
+ * -protocol VERSION field for the detection.
+ */
+ if(msg[0] == '1' && msg[1] == ' ') {
+ dbgprintf("Message has syslog-protocol format.\n");
+ setProtocolVersion(pMsg, 1);
+ if(parseRFCSyslogMsg(pMsg, pMsg->msgFlags) == 1) {
+ msgDestruct(&pMsg);
+ ABORT_FINALIZE(RS_RET_ERR); // TODO: we need to handle these cases!
+ }
+ } else { /* we have legacy syslog */
+ dbgprintf("Message has legacy syslog format.\n");
+ setProtocolVersion(pMsg, 0);
+ if(parseLegacySyslogMsg(pMsg, pMsg->msgFlags) == 1) {
+ msgDestruct(&pMsg);
+ ABORT_FINALIZE(RS_RET_ERR); // TODO: we need to handle these cases!
+ }
+ }
+
+ /* finalize message object */
+ pMsg->msgFlags &= ~NEEDS_PARSING; /* this message is now parsed */
+ MsgPrepareEnqueue(pMsg); /* "historical" name - preparese for multi-threading */
+
+finalize_it:
+ RETiRet;
+}
diff --git a/runtime/parser.h b/runtime/parser.h
new file mode 100644
index 00000000..cec9c083
--- /dev/null
+++ b/runtime/parser.h
@@ -0,0 +1,30 @@
+/* header for parser.c
+ * This is not yet an object, but contains all those code necessary to
+ * parse syslog messages.
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#ifndef INCLUDED_PARSE_H
+#define INCLUDED_PARSE_H
+
+extern rsRetVal parserClassInit(void);
+extern rsRetVal parseMsg(msg_t*);
+
+#endif /* #ifndef INCLUDED_PARSE_H */
diff --git a/runtime/queue.c b/runtime/queue.c
index 9f9943bc..c4a0fad2 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -49,20 +49,26 @@
#include "obj.h"
#include "wtp.h"
#include "wti.h"
+#include "atomic.h"
+
+#ifdef OS_SOLARIS
+# include <sched.h>
+# define pthread_yield() sched_yield()
+#endif
/* static data */
DEFobjStaticHelpers
DEFobjCurrIf(glbl)
/* forward-definitions */
-rsRetVal queueChkPersist(queue_t *pThis);
-static rsRetVal queueSetEnqOnly(queue_t *pThis, int bEnqOnly, int bLockMutex);
-static rsRetVal queueRateLimiter(queue_t *pThis);
-static int queueChkStopWrkrDA(queue_t *pThis);
-static int queueIsIdleDA(queue_t *pThis);
-static rsRetVal queueConsumerDA(queue_t *pThis, wti_t *pWti, int iCancelStateSave);
-static rsRetVal queueConsumerCancelCleanup(void *arg1, void *arg2);
-static rsRetVal queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex);
+rsRetVal qqueueChkPersist(qqueue_t *pThis);
+static rsRetVal qqueueSetEnqOnly(qqueue_t *pThis, int bEnqOnly, int bLockMutex);
+static rsRetVal qqueueRateLimiter(qqueue_t *pThis);
+static int qqueueChkStopWrkrDA(qqueue_t *pThis);
+static int qqueueIsIdleDA(qqueue_t *pThis);
+static rsRetVal qqueueConsumerDA(qqueue_t *pThis, wti_t *pWti, int iCancelStateSave);
+static rsRetVal qqueueConsumerCancelCleanup(void *arg1, void *arg2);
+static rsRetVal qqueueUngetObj(qqueue_t *pThis, obj_t *pUsr, int bLockMutex);
/* some constants for queuePersist () */
#define QUEUE_CHECKPOINT 1
@@ -76,7 +82,7 @@ static rsRetVal queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex);
* rgerhards, 2008-01-29
*/
static inline int
-queueGetOverallQueueSize(queue_t *pThis)
+qqueueGetOverallQueueSize(qqueue_t *pThis)
{
#if 0 /* leave a bit in for debugging -- rgerhards, 2008-01-30 */
BEGINfunc
@@ -95,7 +101,7 @@ ENDfunc
* This function returns void, as it makes no sense to communicate an error back, even if
* it happens.
*/
-static inline void queueDrain(queue_t *pThis)
+static inline void queueDrain(qqueue_t *pThis)
{
void *pUsr;
@@ -118,26 +124,26 @@ static inline void queueDrain(queue_t *pThis)
* this point in time. The mutex must be locked when
* ths function is called. -- rgerhards, 2008-01-25
*/
-static inline rsRetVal queueAdviseMaxWorkers(queue_t *pThis)
+static inline rsRetVal qqueueAdviseMaxWorkers(qqueue_t *pThis)
{
DEFiRet;
int iMaxWorkers;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(!pThis->bEnqOnly) {
if(pThis->bRunsDA) {
/* if we have not yet reached the high water mark, there is no need to start a
* worker. -- rgerhards, 2008-01-26
*/
- if(queueGetOverallQueueSize(pThis) >= pThis->iHighWtrMrk || pThis->bQueueStarted == 0) {
+ if(qqueueGetOverallQueueSize(pThis) >= pThis->iHighWtrMrk || pThis->bQueueStarted == 0) {
wtpAdviseMaxWorkers(pThis->pWtpDA, 1); /* disk queues have always one worker */
}
} else {
if(pThis->qType == QUEUETYPE_DISK || pThis->iMinMsgsPerWrkr == 0) {
iMaxWorkers = 1;
} else {
- iMaxWorkers = queueGetOverallQueueSize(pThis) / pThis->iMinMsgsPerWrkr + 1;
+ iMaxWorkers = qqueueGetOverallQueueSize(pThis) / pThis->iMinMsgsPerWrkr + 1;
}
wtpAdviseMaxWorkers(pThis->pWtpReg, iMaxWorkers); /* disk queues have always one worker */
}
@@ -152,11 +158,11 @@ static inline rsRetVal queueAdviseMaxWorkers(queue_t *pThis)
* rgerhards, 2008-02-27
*/
static rsRetVal
-queueWaitDAModeInitialized(queue_t *pThis)
+qqueueWaitDAModeInitialized(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ASSERT(pThis->bRunsDA);
while(pThis->bRunsDA != 2) {
@@ -178,17 +184,17 @@ queueWaitDAModeInitialized(queue_t *pThis)
* rgerhards, 2008-01-15
*/
static rsRetVal
-queueTurnOffDAMode(queue_t *pThis)
+qqueueTurnOffDAMode(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ASSERT(pThis->bRunsDA);
/* at this point, we need a fully initialized DA queue. So if it isn't, we finally need
* to wait for its startup... -- rgerhards, 2008-01-25
*/
- queueWaitDAModeInitialized(pThis);
+ qqueueWaitDAModeInitialized(pThis);
/* if we need to pull any data that we still need from the (child) disk queue,
* now would be the time to do so. At present, we do not need this, but I'd like to
@@ -207,15 +213,15 @@ queueTurnOffDAMode(queue_t *pThis)
/* we destruct the queue object, which will also shutdown the queue worker. As the queue is empty,
* this will be quick.
*/
- queueDestruct(&pThis->pqDA); /* and now we are ready to destruct the DA queue */
+ qqueueDestruct(&pThis->pqDA); /* and now we are ready to destruct the DA queue */
dbgoprint((obj_t*) pThis, "disk-assistance has been turned off, disk queue was empty (iRet %d)\n",
iRet);
/* now we need to check if the regular queue has some messages. This may be the case
* when it is waiting that the high water mark is reached again. If so, we need to start up
* a regular worker. -- rgerhards, 2008-01-26
*/
- if(queueGetOverallQueueSize(pThis) > 0) {
- queueAdviseMaxWorkers(pThis);
+ if(qqueueGetOverallQueueSize(pThis) > 0) {
+ qqueueAdviseMaxWorkers(pThis);
}
}
@@ -231,11 +237,11 @@ queueTurnOffDAMode(queue_t *pThis)
* rgerhards, 2008-01-14
*/
static rsRetVal
-queueChkIsDA(queue_t *pThis)
+qqueueChkIsDA(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->pszFilePrefix != NULL) {
pThis->bIsDA = 1;
dbgoprint((obj_t*) pThis, "is disk-assisted, disk will be used on demand\n");
@@ -259,18 +265,18 @@ queueChkIsDA(queue_t *pThis)
* rgerhards, 2008-01-15
*/
static rsRetVal
-queueStartDA(queue_t *pThis)
+qqueueStartDA(qqueue_t *pThis)
{
DEFiRet;
uchar pszDAQName[128];
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->bRunsDA == 2) /* check if already in (fully initialized) DA mode... */
FINALIZE; /* ... then we are already done! */
/* create message queue */
- CHKiRet(queueConstruct(&pThis->pqDA, QUEUETYPE_DISK , 1, 0, pThis->pConsumer));
+ CHKiRet(qqueueConstruct(&pThis->pqDA, QUEUETYPE_DISK , 1, 0, pThis->pConsumer));
/* give it a name */
snprintf((char*) pszDAQName, sizeof(pszDAQName)/sizeof(uchar), "%s[DA]", obj.GetName((obj_t*) pThis));
@@ -281,30 +287,30 @@ queueStartDA(queue_t *pThis)
*/
pThis->pqDA->pqParent = pThis;
- CHKiRet(queueSetpUsr(pThis->pqDA, pThis->pUsr));
- CHKiRet(queueSetsizeOnDiskMax(pThis->pqDA, pThis->sizeOnDiskMax));
- CHKiRet(queueSetiDeqSlowdown(pThis->pqDA, pThis->iDeqSlowdown));
- CHKiRet(queueSetMaxFileSize(pThis->pqDA, pThis->iMaxFileSize));
- CHKiRet(queueSetFilePrefix(pThis->pqDA, pThis->pszFilePrefix, pThis->lenFilePrefix));
- CHKiRet(queueSetiPersistUpdCnt(pThis->pqDA, pThis->iPersistUpdCnt));
- CHKiRet(queueSettoActShutdown(pThis->pqDA, pThis->toActShutdown));
- CHKiRet(queueSettoEnq(pThis->pqDA, pThis->toEnq));
- CHKiRet(queueSetEnqOnly(pThis->pqDA, pThis->bDAEnqOnly, MUTEX_ALREADY_LOCKED));
- CHKiRet(queueSetiDeqtWinFromHr(pThis->pqDA, pThis->iDeqtWinFromHr));
- CHKiRet(queueSetiDeqtWinToHr(pThis->pqDA, pThis->iDeqtWinToHr));
- CHKiRet(queueSetiHighWtrMrk(pThis->pqDA, 0));
- CHKiRet(queueSetiDiscardMrk(pThis->pqDA, 0));
+ CHKiRet(qqueueSetpUsr(pThis->pqDA, pThis->pUsr));
+ CHKiRet(qqueueSetsizeOnDiskMax(pThis->pqDA, pThis->sizeOnDiskMax));
+ CHKiRet(qqueueSetiDeqSlowdown(pThis->pqDA, pThis->iDeqSlowdown));
+ CHKiRet(qqueueSetMaxFileSize(pThis->pqDA, pThis->iMaxFileSize));
+ CHKiRet(qqueueSetFilePrefix(pThis->pqDA, pThis->pszFilePrefix, pThis->lenFilePrefix));
+ CHKiRet(qqueueSetiPersistUpdCnt(pThis->pqDA, pThis->iPersistUpdCnt));
+ CHKiRet(qqueueSettoActShutdown(pThis->pqDA, pThis->toActShutdown));
+ CHKiRet(qqueueSettoEnq(pThis->pqDA, pThis->toEnq));
+ CHKiRet(qqueueSetEnqOnly(pThis->pqDA, pThis->bDAEnqOnly, MUTEX_ALREADY_LOCKED));
+ CHKiRet(qqueueSetiDeqtWinFromHr(pThis->pqDA, pThis->iDeqtWinFromHr));
+ CHKiRet(qqueueSetiDeqtWinToHr(pThis->pqDA, pThis->iDeqtWinToHr));
+ CHKiRet(qqueueSetiHighWtrMrk(pThis->pqDA, 0));
+ CHKiRet(qqueueSetiDiscardMrk(pThis->pqDA, 0));
if(pThis->toQShutdown == 0) {
- CHKiRet(queueSettoQShutdown(pThis->pqDA, 0)); /* if the user really wants... */
+ CHKiRet(qqueueSettoQShutdown(pThis->pqDA, 0)); /* if the user really wants... */
} else {
/* we use the shortest possible shutdown (0 is endless!) because when we run on disk AND
* have an obviously large backlog, we can't finish it in any case. So there is no point
* in holding shutdown longer than necessary. -- rgerhards, 2008-01-15
*/
- CHKiRet(queueSettoQShutdown(pThis->pqDA, 1));
+ CHKiRet(qqueueSettoQShutdown(pThis->pqDA, 1));
}
- iRet = queueStart(pThis->pqDA);
+ iRet = qqueueStart(pThis->pqDA);
/* file not found is expected, that means it is no previous QIF available */
if(iRet != RS_RET_OK && iRet != RS_RET_FILE_NOT_FOUND)
FINALIZE; /* something is wrong */
@@ -322,12 +328,12 @@ queueStartDA(queue_t *pThis)
pthread_cond_broadcast(&pThis->condDAReady); /* signal we are now initialized and ready to go ;) */
dbgoprint((obj_t*) pThis, "is now running in disk assisted mode, disk queue 0x%lx\n",
- queueGetID(pThis->pqDA));
+ qqueueGetID(pThis->pqDA));
finalize_it:
if(iRet != RS_RET_OK) {
if(pThis->pqDA != NULL) {
- queueDestruct(&pThis->pqDA);
+ qqueueDestruct(&pThis->pqDA);
}
dbgoprint((obj_t*) pThis, "error %d creating disk queue - giving up.\n", iRet);
pThis->bIsDA = 0;
@@ -344,7 +350,7 @@ finalize_it:
* rgerhards, 2008-01-16
*/
static inline rsRetVal
-queueInitDA(queue_t *pThis, int bEnqOnly, int bLockMutex)
+qqueueInitDA(qqueue_t *pThis, int bEnqOnly, int bLockMutex)
{
DEFiRet;
DEFVARS_mutexProtection;
@@ -362,12 +368,12 @@ queueInitDA(queue_t *pThis, int bEnqOnly, int bLockMutex)
lenBuf = snprintf((char*)pszBuf, sizeof(pszBuf), "%s:DA", obj.GetName((obj_t*) pThis));
CHKiRet(wtpConstruct (&pThis->pWtpDA));
CHKiRet(wtpSetDbgHdr (pThis->pWtpDA, pszBuf, lenBuf));
- CHKiRet(wtpSetpfChkStopWrkr (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, int)) queueChkStopWrkrDA));
- CHKiRet(wtpSetpfIsIdle (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, int)) queueIsIdleDA));
- CHKiRet(wtpSetpfDoWork (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, void *pWti, int)) queueConsumerDA));
- CHKiRet(wtpSetpfOnWorkerCancel (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, void*pWti)) queueConsumerCancelCleanup));
- CHKiRet(wtpSetpfOnWorkerStartup (pThis->pWtpDA, (rsRetVal (*)(void *pUsr)) queueStartDA));
- CHKiRet(wtpSetpfOnWorkerShutdown(pThis->pWtpDA, (rsRetVal (*)(void *pUsr)) queueTurnOffDAMode));
+ CHKiRet(wtpSetpfChkStopWrkr (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, int)) qqueueChkStopWrkrDA));
+ CHKiRet(wtpSetpfIsIdle (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, int)) qqueueIsIdleDA));
+ CHKiRet(wtpSetpfDoWork (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, void *pWti, int)) qqueueConsumerDA));
+ CHKiRet(wtpSetpfOnWorkerCancel (pThis->pWtpDA, (rsRetVal (*)(void *pUsr, void*pWti)) qqueueConsumerCancelCleanup));
+ CHKiRet(wtpSetpfOnWorkerStartup (pThis->pWtpDA, (rsRetVal (*)(void *pUsr)) qqueueStartDA));
+ CHKiRet(wtpSetpfOnWorkerShutdown(pThis->pWtpDA, (rsRetVal (*)(void *pUsr)) qqueueTurnOffDAMode));
CHKiRet(wtpSetpmutUsr (pThis->pWtpDA, pThis->mut));
CHKiRet(wtpSetpcondBusy (pThis->pWtpDA, &pThis->notEmpty));
CHKiRet(wtpSetiNumWorkerThreads (pThis->pWtpDA, 1));
@@ -400,14 +406,14 @@ finalize_it:
* rgerhards, 2008-01-14
*/
static inline rsRetVal
-queueChkStrtDA(queue_t *pThis)
+qqueueChkStrtDA(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
/* if we do not hit the high water mark, we have nothing to do */
- if(queueGetOverallQueueSize(pThis) != pThis->iHighWtrMrk)
+ if(qqueueGetOverallQueueSize(pThis) != pThis->iHighWtrMrk)
ABORT_FINALIZE(RS_RET_OK);
if(pThis->bRunsDA) {
@@ -421,15 +427,15 @@ queueChkStrtDA(queue_t *pThis)
* we need at least one).
*/
dbgoprint((obj_t*) pThis, "%d entries - passed high water mark in DA mode, send notify\n",
- queueGetOverallQueueSize(pThis));
- queueAdviseMaxWorkers(pThis);
+ qqueueGetOverallQueueSize(pThis));
+ qqueueAdviseMaxWorkers(pThis);
} else {
/* this is the case when we are currently not running in DA mode. So it is time
* to turn it back on.
*/
dbgoprint((obj_t*) pThis, "%d entries - passed high water mark for disk-assisted mode, initiating...\n",
- queueGetOverallQueueSize(pThis));
- queueInitDA(pThis, QUEUE_MODE_ENQDEQ, MUTEX_ALREADY_LOCKED); /* initiate DA mode */
+ qqueueGetOverallQueueSize(pThis));
+ qqueueInitDA(pThis, QUEUE_MODE_ENQDEQ, MUTEX_ALREADY_LOCKED); /* initiate DA mode */
}
finalize_it:
@@ -447,7 +453,7 @@ finalize_it:
*/
/* -------------------- fixed array -------------------- */
-static rsRetVal qConstructFixedArray(queue_t *pThis)
+static rsRetVal qConstructFixedArray(qqueue_t *pThis)
{
DEFiRet;
@@ -463,14 +469,14 @@ static rsRetVal qConstructFixedArray(queue_t *pThis)
pThis->tVars.farray.head = 0;
pThis->tVars.farray.tail = 0;
- queueChkIsDA(pThis);
+ qqueueChkIsDA(pThis);
finalize_it:
RETiRet;
}
-static rsRetVal qDestructFixedArray(queue_t *pThis)
+static rsRetVal qDestructFixedArray(qqueue_t *pThis)
{
DEFiRet;
@@ -485,7 +491,7 @@ static rsRetVal qDestructFixedArray(queue_t *pThis)
}
-static rsRetVal qAddFixedArray(queue_t *pThis, void* in)
+static rsRetVal qAddFixedArray(qqueue_t *pThis, void* in)
{
DEFiRet;
@@ -498,7 +504,7 @@ static rsRetVal qAddFixedArray(queue_t *pThis, void* in)
RETiRet;
}
-static rsRetVal qDelFixedArray(queue_t *pThis, void **out)
+static rsRetVal qDelFixedArray(qqueue_t *pThis, void **out)
{
DEFiRet;
@@ -517,7 +523,7 @@ static rsRetVal qDelFixedArray(queue_t *pThis, void **out)
/* first some generic functions which are also used for the unget linked list */
-static inline rsRetVal queueAddLinkedList(qLinkedList_t **ppRoot, qLinkedList_t **ppLast, void* pUsr)
+static inline rsRetVal qqueueAddLinkedList(qLinkedList_t **ppRoot, qLinkedList_t **ppLast, void* pUsr)
{
DEFiRet;
qLinkedList_t *pEntry;
@@ -543,7 +549,7 @@ finalize_it:
RETiRet;
}
-static inline rsRetVal queueDelLinkedList(qLinkedList_t **ppRoot, qLinkedList_t **ppLast, obj_t **ppUsr)
+static inline rsRetVal qqueueDelLinkedList(qLinkedList_t **ppRoot, qLinkedList_t **ppLast, obj_t **ppUsr)
{
DEFiRet;
qLinkedList_t *pEntry;
@@ -570,7 +576,7 @@ static inline rsRetVal queueDelLinkedList(qLinkedList_t **ppRoot, qLinkedList_t
/* end generic functions which are also used for the unget linked list */
-static rsRetVal qConstructLinkedList(queue_t *pThis)
+static rsRetVal qConstructLinkedList(qqueue_t *pThis)
{
DEFiRet;
@@ -579,13 +585,13 @@ static rsRetVal qConstructLinkedList(queue_t *pThis)
pThis->tVars.linklist.pRoot = 0;
pThis->tVars.linklist.pLast = 0;
- queueChkIsDA(pThis);
+ qqueueChkIsDA(pThis);
RETiRet;
}
-static rsRetVal qDestructLinkedList(queue_t __attribute__((unused)) *pThis)
+static rsRetVal qDestructLinkedList(qqueue_t __attribute__((unused)) *pThis)
{
DEFiRet;
@@ -598,11 +604,11 @@ static rsRetVal qDestructLinkedList(queue_t __attribute__((unused)) *pThis)
RETiRet;
}
-static rsRetVal qAddLinkedList(queue_t *pThis, void* pUsr)
+static rsRetVal qAddLinkedList(qqueue_t *pThis, void* pUsr)
{
DEFiRet;
- iRet = queueAddLinkedList(&pThis->tVars.linklist.pRoot, &pThis->tVars.linklist.pLast, pUsr);
+ iRet = qqueueAddLinkedList(&pThis->tVars.linklist.pRoot, &pThis->tVars.linklist.pLast, pUsr);
#if 0
qLinkedList_t *pEntry;
@@ -626,10 +632,10 @@ finalize_it:
RETiRet;
}
-static rsRetVal qDelLinkedList(queue_t *pThis, obj_t **ppUsr)
+static rsRetVal qDelLinkedList(qqueue_t *pThis, obj_t **ppUsr)
{
DEFiRet;
- iRet = queueDelLinkedList(&pThis->tVars.linklist.pRoot, &pThis->tVars.linklist.pLast, ppUsr);
+ iRet = qqueueDelLinkedList(&pThis->tVars.linklist.pRoot, &pThis->tVars.linklist.pLast, ppUsr);
#if 0
qLinkedList_t *pEntry;
@@ -656,11 +662,11 @@ static rsRetVal qDelLinkedList(queue_t *pThis, obj_t **ppUsr)
static rsRetVal
-queueLoadPersStrmInfoFixup(strm_t *pStrm, queue_t __attribute__((unused)) *pThis)
+qqueueLoadPersStrmInfoFixup(strm_t *pStrm, qqueue_t __attribute__((unused)) *pThis)
{
DEFiRet;
ISOBJ_TYPE_assert(pStrm, strm);
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
CHKiRet(strmSetDir(pStrm, glbl.GetWorkDir(), strlen((char*)glbl.GetWorkDir())));
finalize_it:
RETiRet;
@@ -672,14 +678,14 @@ finalize_it:
* rgerhards, 2008-01-15
*/
static rsRetVal
-queueHaveQIF(queue_t *pThis)
+qqueueHaveQIF(qqueue_t *pThis)
{
DEFiRet;
uchar pszQIFNam[MAXFNAME];
size_t lenQIFNam;
struct stat stat_buf;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->pszFilePrefix == NULL)
ABORT_FINALIZE(RS_RET_NO_FILEPREFIX);
@@ -709,7 +715,7 @@ finalize_it:
* rgerhards, 2008-01-11
*/
static rsRetVal
-queueTryLoadPersistedInfo(queue_t *pThis)
+qqueueTryLoadPersistedInfo(qqueue_t *pThis)
{
DEFiRet;
strm_t *psQIF = NULL;
@@ -719,7 +725,7 @@ queueTryLoadPersistedInfo(queue_t *pThis)
int iUngottenObjs;
obj_t *pUsr;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
/* Construct file name */
lenQIFNam = snprintf((char*)pszQIFNam, sizeof(pszQIFNam) / sizeof(uchar), "%s/%s.qi",
@@ -754,15 +760,15 @@ queueTryLoadPersistedInfo(queue_t *pThis)
while(iUngottenObjs > 0) {
/* fill the queue from disk */
CHKiRet(obj.Deserialize((void*) &pUsr, (uchar*)"msg", psQIF, NULL, NULL));
- queueUngetObj(pThis, pUsr, MUTEX_ALREADY_LOCKED);
+ qqueueUngetObj(pThis, pUsr, MUTEX_ALREADY_LOCKED);
--iUngottenObjs; /* one less */
}
/* and now the stream objects (some order as when persisted!) */
CHKiRet(obj.Deserialize(&pThis->tVars.disk.pWrite, (uchar*) "strm", psQIF,
- (rsRetVal(*)(obj_t*,void*))queueLoadPersStrmInfoFixup, pThis));
+ (rsRetVal(*)(obj_t*,void*))qqueueLoadPersStrmInfoFixup, pThis));
CHKiRet(obj.Deserialize(&pThis->tVars.disk.pRead, (uchar*) "strm", psQIF,
- (rsRetVal(*)(obj_t*,void*))queueLoadPersStrmInfoFixup, pThis));
+ (rsRetVal(*)(obj_t*,void*))qqueueLoadPersStrmInfoFixup, pThis));
CHKiRet(strmSeekCurrOffs(pThis->tVars.disk.pWrite));
CHKiRet(strmSeekCurrOffs(pThis->tVars.disk.pRead));
@@ -792,7 +798,7 @@ finalize_it:
* allowed file size at this point - that should be a config setting...
* rgerhards, 2008-01-10
*/
-static rsRetVal qConstructDisk(queue_t *pThis)
+static rsRetVal qConstructDisk(qqueue_t *pThis)
{
DEFiRet;
int bRestarted = 0;
@@ -800,7 +806,7 @@ static rsRetVal qConstructDisk(queue_t *pThis)
ASSERT(pThis != NULL);
/* and now check if there is some persistent information that needs to be read in */
- iRet = queueTryLoadPersistedInfo(pThis);
+ iRet = qqueueTryLoadPersistedInfo(pThis);
if(iRet == RS_RET_OK)
bRestarted = 1;
else if(iRet != RS_RET_FILE_NOT_FOUND)
@@ -842,7 +848,7 @@ finalize_it:
}
-static rsRetVal qDestructDisk(queue_t *pThis)
+static rsRetVal qDestructDisk(qqueue_t *pThis)
{
DEFiRet;
@@ -854,7 +860,7 @@ static rsRetVal qDestructDisk(queue_t *pThis)
RETiRet;
}
-static rsRetVal qAddDisk(queue_t *pThis, void* pUsr)
+static rsRetVal qAddDisk(qqueue_t *pThis, void* pUsr)
{
DEFiRet;
number_t nWriteCount;
@@ -881,7 +887,7 @@ finalize_it:
RETiRet;
}
-static rsRetVal qDelDisk(queue_t *pThis, void **ppUsr)
+static rsRetVal qDelDisk(qqueue_t *pThis, void **ppUsr)
{
DEFiRet;
@@ -912,18 +918,18 @@ finalize_it:
}
/* -------------------- direct (no queueing) -------------------- */
-static rsRetVal qConstructDirect(queue_t __attribute__((unused)) *pThis)
+static rsRetVal qConstructDirect(qqueue_t __attribute__((unused)) *pThis)
{
return RS_RET_OK;
}
-static rsRetVal qDestructDirect(queue_t __attribute__((unused)) *pThis)
+static rsRetVal qDestructDirect(qqueue_t __attribute__((unused)) *pThis)
{
return RS_RET_OK;
}
-static rsRetVal qAddDirect(queue_t *pThis, void* pUsr)
+static rsRetVal qAddDirect(qqueue_t *pThis, void* pUsr)
{
DEFiRet;
@@ -940,7 +946,7 @@ static rsRetVal qAddDirect(queue_t *pThis, void* pUsr)
RETiRet;
}
-static rsRetVal qDelDirect(queue_t __attribute__((unused)) *pThis, __attribute__((unused)) void **out)
+static rsRetVal qDelDirect(qqueue_t __attribute__((unused)) *pThis, __attribute__((unused)) void **out)
{
return RS_RET_OK;
}
@@ -955,12 +961,12 @@ static rsRetVal qDelDirect(queue_t __attribute__((unused)) *pThis, __attribute__
* rgerhards, 2008-01-20
*/
static rsRetVal
-queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex)
+qqueueUngetObj(qqueue_t *pThis, obj_t *pUsr, int bLockMutex)
{
DEFiRet;
DEFVARS_mutexProtection;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ISOBJ_assert(pUsr); /* TODO: we aborted right at this place at least 3 times -- race? 2008-02-28, -03-10, -03-15
The second time I noticed it the queue was in destruction with NO worker threads
running. The pUsr ptr was totally off and provided no clue what it may be pointing
@@ -969,7 +975,7 @@ queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex)
dbgoprint((obj_t*) pThis, "ungetting user object %s\n", obj.GetName(pUsr));
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, bLockMutex);
- iRet = queueAddLinkedList(&pThis->pUngetRoot, &pThis->pUngetLast, pUsr);
+ iRet = qqueueAddLinkedList(&pThis->pUngetRoot, &pThis->pUngetLast, pUsr);
++pThis->iUngottenObjs; /* indicate one more */
END_MTX_PROTECTED_OPERATIONS(pThis->mut);
@@ -985,14 +991,14 @@ queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex)
* rgerhards, 2008-01-29
*/
static rsRetVal
-queueGetUngottenObj(queue_t *pThis, obj_t **ppUsr)
+qqueueGetUngottenObj(qqueue_t *pThis, obj_t **ppUsr)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ASSERT(ppUsr != NULL);
- iRet = queueDelLinkedList(&pThis->pUngetRoot, &pThis->pUngetLast, ppUsr);
+ iRet = qqueueDelLinkedList(&pThis->pUngetRoot, &pThis->pUngetLast, ppUsr);
--pThis->iUngottenObjs; /* indicate one less */
dbgoprint((obj_t*) pThis, "dequeued ungotten user object %s\n", obj.GetName(*ppUsr));
@@ -1006,7 +1012,7 @@ queueGetUngottenObj(queue_t *pThis, obj_t **ppUsr)
* things truely different. -- rgerhards, 2008-02-12
*/
static rsRetVal
-queueAdd(queue_t *pThis, void *pUsr)
+qqueueAdd(qqueue_t *pThis, void *pUsr)
{
DEFiRet;
@@ -1015,7 +1021,7 @@ queueAdd(queue_t *pThis, void *pUsr)
CHKiRet(pThis->qAdd(pThis, pUsr));
if(pThis->qType != QUEUETYPE_DIRECT) {
- ++pThis->iQueueSize;
+ ATOMIC_INC(pThis->iQueueSize);
dbgoprint((obj_t*) pThis, "entry added, size now %d entries\n", pThis->iQueueSize);
}
@@ -1029,7 +1035,7 @@ finalize_it:
* ungotten list and, if so, dequeue it first.
*/
static rsRetVal
-queueDel(queue_t *pThis, void *pUsr)
+qqueueDel(qqueue_t *pThis, void *pUsr)
{
DEFiRet;
@@ -1041,10 +1047,10 @@ queueDel(queue_t *pThis, void *pUsr)
* losing the whole process because it loops... -- rgerhards, 2008-01-03
*/
if(pThis->iUngottenObjs > 0) {
- iRet = queueGetUngottenObj(pThis, (obj_t**) pUsr);
+ iRet = qqueueGetUngottenObj(pThis, (obj_t**) pUsr);
} else {
iRet = pThis->qDel(pThis, pUsr);
- --pThis->iQueueSize;
+ ATOMIC_DEC(pThis->iQueueSize);
}
dbgoprint((obj_t*) pThis, "entry deleted, state %d, size now %d entries\n",
@@ -1065,14 +1071,14 @@ queueDel(queue_t *pThis, void *pUsr)
* complex) if each would have its own shutdown. The function does not self check
* this condition - the caller must make sure it is not called with a parent.
*/
-static rsRetVal queueShutdownWorkers(queue_t *pThis)
+static rsRetVal qqueueShutdownWorkers(qqueue_t *pThis)
{
DEFiRet;
DEFVARS_mutexProtection;
struct timespec tTimeout;
rsRetVal iRetLocal;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ASSERT(pThis->pqParent == NULL); /* detect invalid calling sequence */
dbgoprint((obj_t*) pThis, "initiating worker thread shutdown sequence\n");
@@ -1086,7 +1092,7 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
/* first try to shutdown the queue within the regular shutdown period */
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, LOCK_MUTEX); /* some workers may be running in parallel! */
- if(queueGetOverallQueueSize(pThis) > 0) {
+ if(qqueueGetOverallQueueSize(pThis) > 0) {
if(pThis->bRunsDA) {
/* We may have waited on the low water mark. As it may have changed, we
* see if we reactivate the worker.
@@ -1124,7 +1130,7 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
if(pThis->bRunsDA) {
END_MTX_PROTECTED_OPERATIONS(pThis->mut);
dbgoprint((obj_t*) pThis, "we have a DA queue (0x%lx), requesting its shutdown.\n",
- queueGetID(pThis->pqDA));
+ qqueueGetID(pThis->pqDA));
/* we use the same absolute timeout as above, so we do not use more than the configured
* timeout interval!
*/
@@ -1153,19 +1159,19 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
/* at this stage, we need to have the DA worker properly initialized and running (if there is one) */
if(pThis->bRunsDA)
- queueWaitDAModeInitialized(pThis);
+ qqueueWaitDAModeInitialized(pThis);
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, LOCK_MUTEX); /* some workers may be running in parallel! */
/* optimize parameters for shutdown of DA-enabled queues */
- if(pThis->bIsDA && queueGetOverallQueueSize(pThis) > 0 && pThis->bSaveOnShutdown) {
+ if(pThis->bIsDA && qqueueGetOverallQueueSize(pThis) > 0 && pThis->bSaveOnShutdown) {
/* switch to enqueue-only mode so that no more actions happen */
if(pThis->bRunsDA == 0) {
- queueInitDA(pThis, QUEUE_MODE_ENQONLY, MUTEX_ALREADY_LOCKED); /* switch to DA mode */
+ qqueueInitDA(pThis, QUEUE_MODE_ENQONLY, MUTEX_ALREADY_LOCKED); /* switch to DA mode */
} else {
/* TODO: RACE: we may reach this point when the DA worker has been initialized (state 1)
* but is not yet running (state 2). In this case, pThis->pqDA is NULL! rgerhards, 2008-02-27
*/
- queueSetEnqOnly(pThis->pqDA, QUEUE_MODE_ENQONLY, MUTEX_ALREADY_LOCKED); /* switch to enqueue-only mode */
+ qqueueSetEnqOnly(pThis->pqDA, QUEUE_MODE_ENQONLY, MUTEX_ALREADY_LOCKED); /* switch to enqueue-only mode */
}
END_MTX_PROTECTED_OPERATIONS(pThis->mut);
/* make sure we do not timeout before we are done */
@@ -1187,7 +1193,7 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
* they will automatically terminate as there no longer is any message left to process.
*/
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, LOCK_MUTEX); /* some workers may be running in parallel! */
- if(queueGetOverallQueueSize(pThis) > 0) {
+ if(qqueueGetOverallQueueSize(pThis) > 0) {
timeoutComp(&tTimeout, pThis->toActShutdown);
if(wtpGetCurNumWrkr(pThis->pWtpReg, LOCK_MUTEX) > 0) {
END_MTX_PROTECTED_OPERATIONS(pThis->mut);
@@ -1256,7 +1262,7 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
* Well, more precisely, they *are in termination*. Some cancel cleanup handlers
* may still be running.
*/
- dbgoprint((obj_t*) pThis, "worker threads terminated, remaining queue size %d.\n", queueGetOverallQueueSize(pThis));
+ dbgoprint((obj_t*) pThis, "worker threads terminated, remaining queue size %d.\n", qqueueGetOverallQueueSize(pThis));
RETiRet;
}
@@ -1268,22 +1274,23 @@ static rsRetVal queueShutdownWorkers(queue_t *pThis)
* is done by queueStart(). The reason is that we want to give the caller a chance
* to modify some parameters before the queue is actually started.
*/
-rsRetVal queueConstruct(queue_t **ppThis, queueType_t qType, int iWorkerThreads,
+rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThreads,
int iMaxQueueSize, rsRetVal (*pConsumer)(void*,void*))
{
DEFiRet;
- queue_t *pThis;
+ qqueue_t *pThis;
ASSERT(ppThis != NULL);
ASSERT(pConsumer != NULL);
ASSERT(iWorkerThreads >= 0);
- if((pThis = (queue_t *)calloc(1, sizeof(queue_t))) == NULL) {
+ if((pThis = (qqueue_t *)calloc(1, sizeof(qqueue_t))) == NULL) {
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
}
/* we have an object, so let's fill the properties */
objConstructSetObjInfo(pThis);
+ pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
if((pThis->pszSpoolDir = (uchar*) strdup((char*)glbl.GetWorkDir())) == NULL)
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
@@ -1314,7 +1321,7 @@ rsRetVal queueConstruct(queue_t **ppThis, queueType_t qType, int iWorkerThreads,
pThis->qConstruct = qConstructLinkedList;
pThis->qDestruct = qDestructLinkedList;
pThis->qAdd = qAddLinkedList;
- pThis->qDel = (rsRetVal (*)(queue_t*,void**)) qDelLinkedList;
+ pThis->qDel = (rsRetVal (*)(qqueue_t*,void**)) qDelLinkedList;
break;
case QUEUETYPE_DISK:
pThis->qConstruct = qConstructDisk;
@@ -1341,25 +1348,25 @@ finalize_it:
/* cancellation cleanup handler for queueWorker ()
* Updates admin structure and frees ressources.
* Params:
- * arg1 - user pointer (in this case a queue_t)
+ * arg1 - user pointer (in this case a qqueue_t)
* arg2 - user data pointer (in this case a queue data element, any object [queue's pUsr ptr!])
* Note that arg2 may be NULL, in which case no dequeued but unprocessed pUsr exists!
* rgerhards, 2008-01-16
*/
static rsRetVal
-queueConsumerCancelCleanup(void *arg1, void *arg2)
+qqueueConsumerCancelCleanup(void *arg1, void *arg2)
{
DEFiRet;
- queue_t *pThis = (queue_t*) arg1;
+ qqueue_t *pThis = (qqueue_t*) arg1;
obj_t *pUsr = (obj_t*) arg2;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pUsr != NULL) {
/* make sure the data element is not lost */
dbgoprint((obj_t*) pThis, "cancelation cleanup handler consumer called, we need to unget one user data element\n");
- CHKiRet(queueUngetObj(pThis, pUsr, LOCK_MUTEX));
+ CHKiRet(qqueueUngetObj(pThis, pUsr, LOCK_MUTEX));
}
finalize_it:
@@ -1381,13 +1388,13 @@ finalize_it:
* the return state!
* rgerhards, 2008-01-24
*/
-static int queueChkDiscardMsg(queue_t *pThis, int iQueueSize, int bRunsDA, void *pUsr)
+static int qqueueChkDiscardMsg(qqueue_t *pThis, int iQueueSize, int bRunsDA, void *pUsr)
{
DEFiRet;
rsRetVal iRetLocal;
int iSeverity;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ISOBJ_assert(pUsr);
if(pThis->iDiscardMrk > 0 && iQueueSize >= pThis->iDiscardMrk && bRunsDA == 0) {
@@ -1412,7 +1419,7 @@ finalize_it:
* rgerhards, 2008-10-21
*/
static rsRetVal
-queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
+qqueueDequeueConsumable(qqueue_t *pThis, wti_t *pWti, int iCancelStateSave)
{
DEFiRet;
void *pUsr;
@@ -1420,9 +1427,9 @@ queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
int bRunsDA; /* cache for early mutex release */
/* dequeue element (still protected from mutex) */
- iRet = queueDel(pThis, &pUsr);
- queueChkPersist(pThis);
- iQueueSize = queueGetOverallQueueSize(pThis); /* cache this for after mutex release */
+ iRet = qqueueDel(pThis, &pUsr);
+ qqueueChkPersist(pThis);
+ iQueueSize = qqueueGetOverallQueueSize(pThis); /* cache this for after mutex release */
bRunsDA = pThis->bRunsDA; /* cache this for after mutex release */
/* We now need to save the user pointer for the cancel cleanup handler, BUT ONLY
@@ -1449,8 +1456,13 @@ queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
pthread_cond_broadcast(&pThis->belowLightDlyWtrMrk);
}
- d_pthread_mutex_unlock(pThis->mut);
+ /* rgerhards, 2008-09-30: I reversed the order of cond_signal und mutex_unlock
+ * as of the pthreads recommendation on predictable scheduling behaviour. I don't see
+ * any problems caused by this, but I add this comment in case some will be seen
+ * in the next time.
+ */
pthread_cond_signal(&pThis->notFull);
+ d_pthread_mutex_unlock(pThis->mut);
pthread_setcancelstate(iCancelStateSave, NULL);
/* WE ARE NO LONGER PROTECTED BY THE MUTEX */
@@ -1468,7 +1480,7 @@ queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
* provide real-time creation of spool files.
* Note: It is OK to use the cached iQueueSize here, because it does not hurt if it is slightly wrong.
*/
- CHKiRet(queueChkDiscardMsg(pThis, iQueueSize, bRunsDA, pUsr));
+ CHKiRet(qqueueChkDiscardMsg(pThis, iQueueSize, bRunsDA, pUsr));
finalize_it:
if(iRet != RS_RET_OK && iRet != RS_RET_DISCARDMSG) {
@@ -1517,7 +1529,7 @@ finalize_it:
* but you get the idea from the code above.
*/
static rsRetVal
-queueRateLimiter(queue_t *pThis)
+qqueueRateLimiter(qqueue_t *pThis)
{
DEFiRet;
int iDelay;
@@ -1525,9 +1537,7 @@ queueRateLimiter(queue_t *pThis)
time_t tCurr;
struct tm m;
- ISOBJ_TYPE_assert(pThis, queue);
-
- dbgoprint((obj_t*) pThis, "entering rate limiter\n");
+ ISOBJ_TYPE_assert(pThis, qqueue);
iDelay = 0;
if(pThis->iDeqtWinToHr != 25) { /* 25 means disabled */
@@ -1582,14 +1592,14 @@ queueRateLimiter(queue_t *pThis)
* rgerhards, 2008-01-21
*/
static rsRetVal
-queueConsumerReg(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
+qqueueConsumerReg(qqueue_t *pThis, wti_t *pWti, int iCancelStateSave)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ISOBJ_TYPE_assert(pWti, wti);
- CHKiRet(queueDequeueConsumable(pThis, pWti, iCancelStateSave));
+ CHKiRet(qqueueDequeueConsumable(pThis, pWti, iCancelStateSave));
CHKiRet(pThis->pConsumer(pThis->pUsr, pWti->pUsrp));
/* we now need to check if we should deliberately delay processing a bit
@@ -1616,15 +1626,15 @@ finalize_it:
* rgerhards, 2008-01-14
*/
static rsRetVal
-queueConsumerDA(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
+qqueueConsumerDA(qqueue_t *pThis, wti_t *pWti, int iCancelStateSave)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ISOBJ_TYPE_assert(pWti, wti);
- CHKiRet(queueDequeueConsumable(pThis, pWti, iCancelStateSave));
- CHKiRet(queueEnqObj(pThis->pqDA, eFLOWCTL_NO_DELAY, pWti->pUsrp));
+ CHKiRet(qqueueDequeueConsumable(pThis, pWti, iCancelStateSave));
+ CHKiRet(qqueueEnqObj(pThis->pqDA, eFLOWCTL_NO_DELAY, pWti->pUsrp));
finalize_it:
dbgoprint((obj_t*) pThis, "DAConsumer returns with iRet %d\n", iRet);
@@ -1640,7 +1650,7 @@ finalize_it:
* the DA queue
*/
static int
-queueChkStopWrkrDA(queue_t *pThis)
+qqueueChkStopWrkrDA(qqueue_t *pThis)
{
/* if our queue is in destruction, we drain to the DA queue and so we shall not terminate
* until we have done so.
@@ -1659,7 +1669,7 @@ queueChkStopWrkrDA(queue_t *pThis)
&& pThis->pqDA->tVars.disk.sizeOnDisk > pThis->pqDA->sizeOnDiskMax) {
/* this queue can never grow, so we can give up... */
bStopWrkr = 1;
- } else if(queueGetOverallQueueSize(pThis) < pThis->iHighWtrMrk && pThis->bQueueStarted == 1) {
+ } else if(qqueueGetOverallQueueSize(pThis) < pThis->iHighWtrMrk && pThis->bQueueStarted == 1) {
bStopWrkr = 1;
} else {
bStopWrkr = 0;
@@ -1682,9 +1692,9 @@ queueChkStopWrkrDA(queue_t *pThis)
* the DA queue
*/
static int
-queueChkStopWrkrReg(queue_t *pThis)
+qqueueChkStopWrkrReg(qqueue_t *pThis)
{
- return pThis->bEnqOnly || pThis->bRunsDA || (pThis->pqParent != NULL && queueGetOverallQueueSize(pThis) == 0);
+ return pThis->bEnqOnly || pThis->bRunsDA || (pThis->pqParent != NULL && qqueueGetOverallQueueSize(pThis) == 0);
}
@@ -1692,26 +1702,26 @@ queueChkStopWrkrReg(queue_t *pThis)
* are not stable! DA queue version
*/
static int
-queueIsIdleDA(queue_t *pThis)
+qqueueIsIdleDA(qqueue_t *pThis)
{
/* remember: iQueueSize is the DA queue size, not the main queue! */
/* TODO: I think we need just a single function for DA and non-DA mode - but I leave it for now as is */
- return(queueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && queueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk));
+ return(qqueueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && qqueueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk));
}
/* must only be called when the queue mutex is locked, else results
* are not stable! Regular queue version
*/
static int
-queueIsIdleReg(queue_t *pThis)
+qqueueIsIdleReg(qqueue_t *pThis)
{
#if 0 /* enable for performance testing */
int ret;
- ret = queueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && queueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk);
+ ret = qqueueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && qqueueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk);
if(ret) fprintf(stderr, "queue is idle\n");
return ret;
#else
/* regular code! */
- return(queueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && queueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk));
+ return(qqueueGetOverallQueueSize(pThis) == 0 || (pThis->bRunsDA && qqueueGetOverallQueueSize(pThis) <= pThis->iLowWtrMrk));
#endif
}
@@ -1730,11 +1740,11 @@ queueIsIdleReg(queue_t *pThis)
* I am telling this, because I, too, always get confused by those...
*/
static rsRetVal
-queueRegOnWrkrShutdown(queue_t *pThis)
+qqueueRegOnWrkrShutdown(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->pqParent != NULL) {
pThis->pqParent->bChildIsDone = 1; /* indicate we are done */
@@ -1751,11 +1761,11 @@ queueRegOnWrkrShutdown(queue_t *pThis)
* hook to indicate in the parent queue (if we are a child) that we are not done yet.
*/
static rsRetVal
-queueRegOnWrkrStartup(queue_t *pThis)
+qqueueRegOnWrkrStartup(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->pqParent != NULL) {
pThis->pqParent->bChildIsDone = 0;
@@ -1768,7 +1778,7 @@ queueRegOnWrkrStartup(queue_t *pThis)
/* start up the queue - it must have been constructed and parameters defined
* before.
*/
-rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
+rsRetVal qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
{
DEFiRet;
rsRetVal iRetLocal;
@@ -1806,7 +1816,7 @@ rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
dbgoprint((obj_t*) pThis, "type %d, enq-only %d, disk assisted %d, maxFileSz %lld, qsize %d, child %d starting\n",
pThis->qType, pThis->bEnqOnly, pThis->bIsDA, pThis->iMaxFileSize,
- queueGetOverallQueueSize(pThis), pThis->pqParent == NULL ? 0 : 1);
+ qqueueGetOverallQueueSize(pThis), pThis->pqParent == NULL ? 0 : 1);
if(pThis->qType == QUEUETYPE_DIRECT)
FINALIZE; /* with direct queues, we are already finished... */
@@ -1817,13 +1827,13 @@ rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
lenBuf = snprintf((char*)pszBuf, sizeof(pszBuf), "%s:Reg", obj.GetName((obj_t*) pThis));
CHKiRet(wtpConstruct (&pThis->pWtpReg));
CHKiRet(wtpSetDbgHdr (pThis->pWtpReg, pszBuf, lenBuf));
- CHKiRet(wtpSetpfRateLimiter (pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) queueRateLimiter));
- CHKiRet(wtpSetpfChkStopWrkr (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) queueChkStopWrkrReg));
- CHKiRet(wtpSetpfIsIdle (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) queueIsIdleReg));
- CHKiRet(wtpSetpfDoWork (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, void *pWti, int)) queueConsumerReg));
- CHKiRet(wtpSetpfOnWorkerCancel (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, void*pWti))queueConsumerCancelCleanup));
- CHKiRet(wtpSetpfOnWorkerStartup (pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) queueRegOnWrkrStartup));
- CHKiRet(wtpSetpfOnWorkerShutdown(pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) queueRegOnWrkrShutdown));
+ CHKiRet(wtpSetpfRateLimiter (pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) qqueueRateLimiter));
+ CHKiRet(wtpSetpfChkStopWrkr (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) qqueueChkStopWrkrReg));
+ CHKiRet(wtpSetpfIsIdle (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, int)) qqueueIsIdleReg));
+ CHKiRet(wtpSetpfDoWork (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, void *pWti, int)) qqueueConsumerReg));
+ CHKiRet(wtpSetpfOnWorkerCancel (pThis->pWtpReg, (rsRetVal (*)(void *pUsr, void*pWti))qqueueConsumerCancelCleanup));
+ CHKiRet(wtpSetpfOnWorkerStartup (pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) qqueueRegOnWrkrStartup));
+ CHKiRet(wtpSetpfOnWorkerShutdown(pThis->pWtpReg, (rsRetVal (*)(void *pUsr)) qqueueRegOnWrkrShutdown));
CHKiRet(wtpSetpmutUsr (pThis->pWtpReg, pThis->mut));
CHKiRet(wtpSetpcondBusy (pThis->pWtpReg, &pThis->notEmpty));
CHKiRet(wtpSetiNumWorkerThreads (pThis->pWtpReg, pThis->iNumWorkerThreads));
@@ -1836,10 +1846,10 @@ rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
/* If we are disk-assisted, we need to check if there is a QIF file
* which we need to load. -- rgerhards, 2008-01-15
*/
- iRetLocal = queueHaveQIF(pThis);
+ iRetLocal = qqueueHaveQIF(pThis);
if(iRetLocal == RS_RET_OK) {
dbgoprint((obj_t*) pThis, "on-disk queue present, needs to be reloaded\n");
- queueInitDA(pThis, QUEUE_MODE_ENQDEQ, LOCK_MUTEX); /* initiate DA mode */
+ qqueueInitDA(pThis, QUEUE_MODE_ENQDEQ, LOCK_MUTEX); /* initiate DA mode */
bInitialized = 1; /* we are done */
} else {
/* TODO: use logerror? -- rgerhards, 2008-01-16 */
@@ -1856,7 +1866,7 @@ rsRetVal queueStart(queue_t *pThis) /* this is the ConstructionFinalizer */
/* if the queue already contains data, we need to start the correct number of worker threads. This can be
* the case when a disk queue has been loaded. If we did not start it here, it would never start.
*/
- queueAdviseMaxWorkers(pThis);
+ qqueueAdviseMaxWorkers(pThis);
pThis->bQueueStarted = 1;
finalize_it:
@@ -1871,7 +1881,7 @@ finalize_it:
* and 0 otherwise.
* rgerhards, 2008-01-10
*/
-static rsRetVal queuePersist(queue_t *pThis, int bIsCheckpoint)
+static rsRetVal qqueuePersist(qqueue_t *pThis, int bIsCheckpoint)
{
DEFiRet;
strm_t *psQIF = NULL; /* Queue Info File */
@@ -1882,7 +1892,7 @@ static rsRetVal queuePersist(queue_t *pThis, int bIsCheckpoint)
ASSERT(pThis != NULL);
if(pThis->qType != QUEUETYPE_DISK) {
- if(queueGetOverallQueueSize(pThis) > 0) {
+ if(qqueueGetOverallQueueSize(pThis) > 0) {
/* This error code is OK, but we will probably not implement this any time
* The reason is that persistence happens via DA queues. But I would like to
* leave the code as is, as we so have a hook in case we need one.
@@ -1893,13 +1903,13 @@ static rsRetVal queuePersist(queue_t *pThis, int bIsCheckpoint)
FINALIZE; /* if the queue is empty, we are happy and done... */
}
- dbgoprint((obj_t*) pThis, "persisting queue to disk, %d entries...\n", queueGetOverallQueueSize(pThis));
+ dbgoprint((obj_t*) pThis, "persisting queue to disk, %d entries...\n", qqueueGetOverallQueueSize(pThis));
/* Construct file name */
lenQIFNam = snprintf((char*)pszQIFNam, sizeof(pszQIFNam) / sizeof(uchar), "%s/%s.qi",
(char*) glbl.GetWorkDir(), (char*)pThis->pszFilePrefix);
- if((bIsCheckpoint != QUEUE_CHECKPOINT) && (queueGetOverallQueueSize(pThis) == 0)) {
+ if((bIsCheckpoint != QUEUE_CHECKPOINT) && (qqueueGetOverallQueueSize(pThis) == 0)) {
if(pThis->bNeedDelQIF) {
unlink((char*)pszQIFNam);
pThis->bNeedDelQIF = 0;
@@ -1933,7 +1943,7 @@ static rsRetVal queuePersist(queue_t *pThis, int bIsCheckpoint)
* to the regular files. -- rgerhards, 2008-01-29
*/
while(pThis->iUngottenObjs > 0) {
- CHKiRet(queueGetUngottenObj(pThis, &pUsr));
+ CHKiRet(qqueueGetUngottenObj(pThis, &pUsr));
CHKiRet((objSerialize(pUsr))(pUsr, psQIF));
objDestruct(pUsr);
}
@@ -1967,14 +1977,14 @@ finalize_it:
* abide to our regular call interface)...
* rgerhards, 2008-01-13
*/
-rsRetVal queueChkPersist(queue_t *pThis)
+rsRetVal qqueueChkPersist(qqueue_t *pThis)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(pThis->iPersistUpdCnt && ++pThis->iUpdsSincePersist >= pThis->iPersistUpdCnt) {
- queuePersist(pThis, QUEUE_CHECKPOINT);
+ qqueuePersist(pThis, QUEUE_CHECKPOINT);
pThis->iUpdsSincePersist = 0;
}
@@ -1983,8 +1993,8 @@ rsRetVal queueChkPersist(queue_t *pThis)
/* destructor for the queue object */
-BEGINobjDestruct(queue) /* be sure to specify the object type also in END and CODESTART macros! */
-CODESTARTobjDestruct(queue)
+BEGINobjDestruct(qqueue) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(qqueue)
pThis->bQueueInDestruction = 1; /* indicate we are in destruction (modifies some behaviour) */
/* shut down all workers (handles *all* of the persistence logic)
@@ -1994,7 +2004,7 @@ CODESTARTobjDestruct(queue)
* with a child! -- rgerhards, 2008-01-28
*/
if(pThis->qType != QUEUETYPE_DIRECT && !pThis->bEnqOnly && pThis->pqParent == NULL)
- queueShutdownWorkers(pThis);
+ qqueueShutdownWorkers(pThis);
/* finally destruct our (regular) worker thread pool
* Note: currently pWtpReg is never NULL, but if we optimize our logic, this may happen,
@@ -2019,7 +2029,7 @@ CODESTARTobjDestruct(queue)
wtpDestruct(&pThis->pWtpDA);
}
if(pThis->pqDA != NULL) {
- queueDestruct(&pThis->pqDA);
+ qqueueDestruct(&pThis->pqDA);
}
/* persist the queue (we always do that - queuePersits() does cleanup if the queue is empty)
@@ -2029,7 +2039,7 @@ CODESTARTobjDestruct(queue)
* disk queues and DA mode. Anyhow, it doesn't hurt to know that we could extend it here
* if need arises (what I doubt...) -- rgerhards, 2008-01-25
*/
- CHKiRet_Hdlr(queuePersist(pThis, QUEUE_NO_CHECKPOINT)) {
+ CHKiRet_Hdlr(qqueuePersist(pThis, QUEUE_NO_CHECKPOINT)) {
dbgoprint((obj_t*) pThis, "error %d persisting queue - data lost!\n", iRet);
}
@@ -2054,7 +2064,7 @@ CODESTARTobjDestruct(queue)
if(pThis->pszSpoolDir != NULL)
free(pThis->pszSpoolDir);
-ENDobjDestruct(queue)
+ENDobjDestruct(qqueue)
/* set the queue's file prefix
@@ -2063,7 +2073,7 @@ ENDobjDestruct(queue)
* rgerhards, 2008-01-09
*/
rsRetVal
-queueSetFilePrefix(queue_t *pThis, uchar *pszPrefix, size_t iLenPrefix)
+qqueueSetFilePrefix(qqueue_t *pThis, uchar *pszPrefix, size_t iLenPrefix)
{
DEFiRet;
@@ -2086,11 +2096,11 @@ finalize_it:
* rgerhards, 2008-01-09
*/
rsRetVal
-queueSetMaxFileSize(queue_t *pThis, size_t iMaxFileSize)
+qqueueSetMaxFileSize(qqueue_t *pThis, size_t iMaxFileSize)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
if(iMaxFileSize < 1024) {
ABORT_FINALIZE(RS_RET_VALUE_TOO_LOW);
@@ -2107,14 +2117,22 @@ finalize_it:
* Enqueues the new element and awakes worker thread.
*/
rsRetVal
-queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
+qqueueEnqObj(qqueue_t *pThis, flowControl_t flowCtlType, void *pUsr)
{
DEFiRet;
int iCancelStateSave;
- int i;
struct timespec t;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
+
+ /* first check if we need to discard this message (which will cause CHKiRet() to exit)
+ * rgerhards, 2008-10-07: It is OK to do this outside of mutex protection. The iQueueSize
+ * and bRunsDA parameters may not reflect the correct settings here, but they are
+ * "good enough" in the sense that they can be used to drive the decision. Valgrind's
+ * threading tools may point this access to be an error, but this is done
+ * intentional. I do not see this causes problems to us.
+ */
+ CHKiRet(qqueueChkDiscardMsg(pThis, pThis->iQueueSize, pThis->bRunsDA, pUsr));
/* Please note that this function is not cancel-safe and consequently
* sets the calling thread's cancelibility state to PTHREAD_CANCEL_DISABLE
@@ -2127,14 +2145,10 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
d_pthread_mutex_lock(pThis->mut);
}
- /* first check if we need to discard this message (which will cause CHKiRet() to exit) */
- CHKiRet(queueChkDiscardMsg(pThis, pThis->iQueueSize, pThis->bRunsDA, pUsr));
-
/* then check if we need to add an assistance disk queue */
if(pThis->bIsDA)
- CHKiRet(queueChkStrtDA(pThis));
+ CHKiRet(qqueueChkStrtDA(pThis));
-
/* handle flow control
* There are two different flow control mechanisms: basic and advanced flow control.
* Basic flow control has always been implemented and protects the queue structures
@@ -2186,20 +2200,24 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
}
/* and finally enqueue the message */
- CHKiRet(queueAdd(pThis, pUsr));
- queueChkPersist(pThis);
+ CHKiRet(qqueueAdd(pThis, pUsr));
+ qqueueChkPersist(pThis);
finalize_it:
if(pThis->qType != QUEUETYPE_DIRECT) {
+ /* make sure at least one worker is running. */
+ qqueueAdviseMaxWorkers(pThis);
+ /* and release the mutex */
d_pthread_mutex_unlock(pThis->mut);
- i = pthread_cond_signal(&pThis->notEmpty);
- dbgoprint((obj_t*) pThis, "EnqueueMsg signaled condition (%d)\n", i);
pthread_setcancelstate(iCancelStateSave, NULL);
- }
-
- /* make sure at least one worker is running. */
- if(pThis->qType != QUEUETYPE_DIRECT) {
- queueAdviseMaxWorkers(pThis);
+ dbgoprint((obj_t*) pThis, "EnqueueMsg advised worker start\n");
+ /* the following pthread_yield is experimental, but brought us performance
+ * benefit. For details, please see http://kb.monitorware.com/post14216.html#p14216
+ * rgerhards, 2008-10-09
+ * but this is only true for uniprocessors, so we guard it with an optimize flag -- rgerhards, 2008-10-22
+ */
+ if(pThis->bOptimizeUniProc)
+ pthread_yield();
}
RETiRet;
@@ -2215,12 +2233,12 @@ finalize_it:
* rgerhards, 2008-01-16
*/
static rsRetVal
-queueSetEnqOnly(queue_t *pThis, int bEnqOnly, int bLockMutex)
+qqueueSetEnqOnly(qqueue_t *pThis, int bEnqOnly, int bLockMutex)
{
DEFiRet;
DEFVARS_mutexProtection;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
/* for simplicity, we do one big mutex lock. This method is extremely seldom
* called, so that doesn't matter... -- rgerhards, 2008-01-16
@@ -2259,24 +2277,24 @@ finalize_it:
/* some simple object access methods */
-DEFpropSetMeth(queue, iPersistUpdCnt, int)
-DEFpropSetMeth(queue, iDeqtWinFromHr, int)
-DEFpropSetMeth(queue, iDeqtWinToHr, int)
-DEFpropSetMeth(queue, toQShutdown, long)
-DEFpropSetMeth(queue, toActShutdown, long)
-DEFpropSetMeth(queue, toWrkShutdown, long)
-DEFpropSetMeth(queue, toEnq, long)
-DEFpropSetMeth(queue, iHighWtrMrk, int)
-DEFpropSetMeth(queue, iLowWtrMrk, int)
-DEFpropSetMeth(queue, iDiscardMrk, int)
-DEFpropSetMeth(queue, iFullDlyMrk, int)
-DEFpropSetMeth(queue, iDiscardSeverity, int)
-DEFpropSetMeth(queue, bIsDA, int)
-DEFpropSetMeth(queue, iMinMsgsPerWrkr, int)
-DEFpropSetMeth(queue, bSaveOnShutdown, int)
-DEFpropSetMeth(queue, pUsr, void*)
-DEFpropSetMeth(queue, iDeqSlowdown, int)
-DEFpropSetMeth(queue, sizeOnDiskMax, int64)
+DEFpropSetMeth(qqueue, iPersistUpdCnt, int)
+DEFpropSetMeth(qqueue, iDeqtWinFromHr, int)
+DEFpropSetMeth(qqueue, iDeqtWinToHr, int)
+DEFpropSetMeth(qqueue, toQShutdown, long)
+DEFpropSetMeth(qqueue, toActShutdown, long)
+DEFpropSetMeth(qqueue, toWrkShutdown, long)
+DEFpropSetMeth(qqueue, toEnq, long)
+DEFpropSetMeth(qqueue, iHighWtrMrk, int)
+DEFpropSetMeth(qqueue, iLowWtrMrk, int)
+DEFpropSetMeth(qqueue, iDiscardMrk, int)
+DEFpropSetMeth(qqueue, iFullDlyMrk, int)
+DEFpropSetMeth(qqueue, iDiscardSeverity, int)
+DEFpropSetMeth(qqueue, bIsDA, int)
+DEFpropSetMeth(qqueue, iMinMsgsPerWrkr, int)
+DEFpropSetMeth(qqueue, bSaveOnShutdown, int)
+DEFpropSetMeth(qqueue, pUsr, void*)
+DEFpropSetMeth(qqueue, iDeqSlowdown, int)
+DEFpropSetMeth(qqueue, sizeOnDiskMax, int64)
/* This function can be used as a generic way to set properties. Only the subset
@@ -2285,11 +2303,11 @@ DEFpropSetMeth(queue, sizeOnDiskMax, int64)
* rgerhards, 2008-01-11
*/
#define isProp(name) !rsCStrSzStrCmp(pProp->pcsName, (uchar*) name, sizeof(name) - 1)
-static rsRetVal queueSetProperty(queue_t *pThis, var_t *pProp)
+static rsRetVal qqueueSetProperty(qqueue_t *pThis, var_t *pProp)
{
DEFiRet;
- ISOBJ_TYPE_assert(pThis, queue);
+ ISOBJ_TYPE_assert(pThis, qqueue);
ASSERT(pProp != NULL);
if(isProp("iQueueSize")) {
@@ -2311,19 +2329,19 @@ finalize_it:
#undef isProp
/* dummy */
-rsRetVal queueQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
+rsRetVal qqueueQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
/* Initialize the stream class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-01-09
*/
-BEGINObjClassInit(queue, 1, OBJ_IS_CORE_MODULE)
+BEGINObjClassInit(qqueue, 1, OBJ_IS_CORE_MODULE)
/* request objects we use */
CHKiRet(objUse(glbl, CORE_COMPONENT));
/* now set our own handlers */
- OBJSetMethodHandler(objMethod_SETPROPERTY, queueSetProperty);
-ENDObjClassInit(queue)
+ OBJSetMethodHandler(objMethod_SETPROPERTY, qqueueSetProperty);
+ENDObjClassInit(qqueue)
/* vi:set ai:
*/
diff --git a/runtime/queue.h b/runtime/queue.h
index 9e75b31b..a267862d 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -58,6 +58,7 @@ typedef struct qWrkThrd_s {
typedef struct queue_s {
BEGINobjInstance;
queueType_t qType;
+ int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
int bEnqOnly; /* does queue run in enqueue-only mode (1) or not (0)? */
int bSaveOnShutdown;/* persists everthing on shutdown (if DA!)? 1-yes, 0-no */
int bQueueStarted; /* has queueStart() been called on this queue? 1-yes, 0-no */
@@ -159,7 +160,7 @@ typedef struct queue_s {
strm_t *pRead; /* current file to be read */
} disk;
} tVars;
-} queue_t;
+} qqueue_t;
/* some symbolic constants for easier reference */
#define QUEUE_MODE_ENQDEQ 0
@@ -176,30 +177,30 @@ typedef struct queue_s {
#define QUEUE_TIMEOUT_ETERNAL 24 * 60 * 60 * 1000
/* prototypes */
-rsRetVal queueDestruct(queue_t **ppThis);
-rsRetVal queueEnqObj(queue_t *pThis, flowControl_t flwCtlType, void *pUsr);
-rsRetVal queueStart(queue_t *pThis);
-rsRetVal queueSetMaxFileSize(queue_t *pThis, size_t iMaxFileSize);
-rsRetVal queueSetFilePrefix(queue_t *pThis, uchar *pszPrefix, size_t iLenPrefix);
-rsRetVal queueConstruct(queue_t **ppThis, queueType_t qType, int iWorkerThreads,
+rsRetVal qqueueDestruct(qqueue_t **ppThis);
+rsRetVal qqueueEnqObj(qqueue_t *pThis, flowControl_t flwCtlType, void *pUsr);
+rsRetVal qqueueStart(qqueue_t *pThis);
+rsRetVal qqueueSetMaxFileSize(qqueue_t *pThis, size_t iMaxFileSize);
+rsRetVal qqueueSetFilePrefix(qqueue_t *pThis, uchar *pszPrefix, size_t iLenPrefix);
+rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThreads,
int iMaxQueueSize, rsRetVal (*pConsumer)(void*,void*));
-PROTOTYPEObjClassInit(queue);
-PROTOTYPEpropSetMeth(queue, iPersistUpdCnt, int);
-PROTOTYPEpropSetMeth(queue, iDeqtWinFromHr, int);
-PROTOTYPEpropSetMeth(queue, iDeqtWinToHr, int);
-PROTOTYPEpropSetMeth(queue, toQShutdown, long);
-PROTOTYPEpropSetMeth(queue, toActShutdown, long);
-PROTOTYPEpropSetMeth(queue, toWrkShutdown, long);
-PROTOTYPEpropSetMeth(queue, toEnq, long);
-PROTOTYPEpropSetMeth(queue, iHighWtrMrk, int);
-PROTOTYPEpropSetMeth(queue, iLowWtrMrk, int);
-PROTOTYPEpropSetMeth(queue, iDiscardMrk, int);
-PROTOTYPEpropSetMeth(queue, iDiscardSeverity, int);
-PROTOTYPEpropSetMeth(queue, iMinMsgsPerWrkr, int);
-PROTOTYPEpropSetMeth(queue, bSaveOnShutdown, int);
-PROTOTYPEpropSetMeth(queue, pUsr, void*);
-PROTOTYPEpropSetMeth(queue, iDeqSlowdown, int);
-PROTOTYPEpropSetMeth(queue, sizeOnDiskMax, int64);
-#define queueGetID(pThis) ((unsigned long) pThis)
+PROTOTYPEObjClassInit(qqueue);
+PROTOTYPEpropSetMeth(qqueue, iPersistUpdCnt, int);
+PROTOTYPEpropSetMeth(qqueue, iDeqtWinFromHr, int);
+PROTOTYPEpropSetMeth(qqueue, iDeqtWinToHr, int);
+PROTOTYPEpropSetMeth(qqueue, toQShutdown, long);
+PROTOTYPEpropSetMeth(qqueue, toActShutdown, long);
+PROTOTYPEpropSetMeth(qqueue, toWrkShutdown, long);
+PROTOTYPEpropSetMeth(qqueue, toEnq, long);
+PROTOTYPEpropSetMeth(qqueue, iHighWtrMrk, int);
+PROTOTYPEpropSetMeth(qqueue, iLowWtrMrk, int);
+PROTOTYPEpropSetMeth(qqueue, iDiscardMrk, int);
+PROTOTYPEpropSetMeth(qqueue, iDiscardSeverity, int);
+PROTOTYPEpropSetMeth(qqueue, iMinMsgsPerWrkr, int);
+PROTOTYPEpropSetMeth(qqueue, bSaveOnShutdown, int);
+PROTOTYPEpropSetMeth(qqueue, pUsr, void*);
+PROTOTYPEpropSetMeth(qqueue, iDeqSlowdown, int);
+PROTOTYPEpropSetMeth(qqueue, sizeOnDiskMax, int64);
+#define qqueueGetID(pThis) ((unsigned long) pThis)
#endif /* #ifndef QUEUE_H_INCLUDED */
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index 54db12c2..8df100a1 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -157,7 +157,7 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF)
if(ppErrObj != NULL) *ppErrObj = "wtp";
CHKiRet(wtpClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "queue";
- CHKiRet(queueClassInit(NULL));
+ CHKiRet(qqueueClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "vmstk";
CHKiRet(vmstkClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "sysvar";
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 06ffae86..899f5e13 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -123,6 +123,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_TRUE = -3, /**< to indicate a true state (can be used as TRUE, legacy) */
RS_RET_FALSE = -2, /**< to indicate a false state (can be used as FALSE, legacy) */
RS_RET_NO_IRET = -8, /**< This is a trick for the debuging system - it means no iRet is provided */
+ RS_RET_VALIDATION_RUN = -9, /**< indicates a (config) validation run, processing not carried out */
RS_RET_ERR = -3000, /**< generic failure */
RS_TRUNCAT_TOO_LARGE = -3001, /**< truncation operation where too many chars should be truncated */
RS_RET_FOUND_AT_STRING_END = -3002, /**< some value found, but at the last pos of string */
@@ -246,9 +247,17 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_RETRY = -2100, /**< call should be retried (e.g. EGAIN on recv) */
RS_RET_GSS_ERR = -2101, /**< generic error occured in GSSAPI subsystem */
RS_RET_CERTLESS = -2102, /**< state: we run without machine cert (this may be OK) */
- RS_RET_QUEUE_FULL = -2103, /**< queue is full, operation could not be completed */
- RS_RET_ACCEPT_ERR = -2104, /**< error during accept() system call */
+ RS_RET_NO_ACTIONS = -2103, /**< no active actions are configured (no output will be created) */
+ RS_RET_CONF_FILE_NOT_FOUND = -2104, /**< config file or directory not found */
+ RS_RET_QUEUE_FULL = -2105, /**< queue is full, operation could not be completed */
+ RS_RET_ACCEPT_ERR = -2106, /**< error during accept() system call */
+ RS_RET_INVLD_TIME = -2107, /**< invalid timestamp (e.g. could not be parsed) */
+ RS_RET_NO_ZIP = -2108, /**< ZIP functionality is not present */
RS_RET_CODE_ERR = -2109, /**< program code (internal) error */
+ RS_RET_FUNC_NO_LPAREN = -2110, /**< left parenthesis missing after function call (rainerscript) */
+ RS_RET_FUNC_MISSING_EXPR = -2111, /**< no expression after comma in function call (rainerscript) */
+ RS_RET_INVLD_NBR_ARGUMENTS = -2112, /**< invalid number of arguments for function call (rainerscript) */
+ RS_RET_INVLD_FUNC = -2113, /**< invalid function name for function call (rainerscript) */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/srutils.c b/runtime/srutils.c
index 97cc3252..d01ca20d 100644
--- a/runtime/srutils.c
+++ b/runtime/srutils.c
@@ -371,6 +371,7 @@ int getNumberDigits(long lNum)
rsRetVal
timeoutComp(struct timespec *pt, long iTimeout)
{
+ BEGINfunc
assert(pt != NULL);
/* compute timeout */
clock_gettime(CLOCK_REALTIME, pt);
@@ -379,6 +380,7 @@ timeoutComp(struct timespec *pt, long iTimeout)
pt->tv_nsec -= 1000000000;
}
pt->tv_sec += iTimeout / 1000;
+ ENDfunc
return RS_RET_OK; /* so far, this is static... */
}
@@ -393,6 +395,7 @@ timeoutVal(struct timespec *pt)
{
struct timespec t;
long iTimeout;
+ BEGINfunc
assert(pt != NULL);
/* compute timeout */
@@ -403,6 +406,7 @@ timeoutVal(struct timespec *pt)
if(iTimeout < 0)
iTimeout = 0;
+ ENDfunc
return iTimeout;
}
@@ -454,7 +458,7 @@ srSleep(int iSeconds, int iuSeconds)
* Added 2008-01-30
*/
char *rs_strerror_r(int errnum, char *buf, size_t buflen) {
-#ifdef __hpux
+#ifndef HAVE_STRERROR_R
char *pszErr;
pszErr = strerror(errnum);
snprintf(buf, buflen, "%s", pszErr);
diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c
index 93d1e1ef..a5dc625a 100644
--- a/runtime/stringbuf.c
+++ b/runtime/stringbuf.c
@@ -694,6 +694,7 @@ int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
return -1; /* pCS1 is less then psz */
}
+
/* check if a CStr object matches a regex.
* msamia@redhat.com 2007-07-12
* @return returns 0 if matched
@@ -701,25 +702,26 @@ int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
* rgerhards, 2007-07-16: bug is no real bug, because rsyslogd ensures there
* never is a \0 *inside* a property string.
* Note that the function returns -1 if regexp functionality is not available.
- * TODO: change calling interface! -- rgerhards, 2008-03-07
+ * rgerhards: 2009-03-04: ERE support added, via parameter iType: 0 - BRE, 1 - ERE
*/
-int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz)
+rsRetVal rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz, int iType)
{
regex_t preq;
int ret;
-
- BEGINfunc
+ DEFiRet;
if(objUse(regexp, LM_REGEXP_FILENAME) == RS_RET_OK) {
- regexp.regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0);
+ regexp.regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), (iType == 1 ? REG_EXTENDED : 0) | REG_NOSUB);
ret = regexp.regexec(&preq, (char*) psz, 0, NULL, 0);
regexp.regfree(&preq);
+ if(ret != 0)
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
} else {
- ret = 1; /* simulate "not found" */
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
- ENDfunc
- return ret;
+finalize_it:
+ RETiRet;
}
diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h
index c1966449..f3e08439 100644
--- a/runtime/stringbuf.h
+++ b/runtime/stringbuf.h
@@ -136,7 +136,7 @@ int rsCStrCaseInsensitiveLocateInSzStr(cstr_t *pThis, uchar *sz);
int rsCStrStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
-int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz);
+rsRetVal rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz, int iType);
rsRetVal rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber);
rsRetVal rsCStrConvertToBool(cstr_t *pStr, number_t *pBool);
rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend);
diff --git a/runtime/sysvar.c b/runtime/sysvar.c
index 5eec8f67..c102d1f5 100644
--- a/runtime/sysvar.c
+++ b/runtime/sysvar.c
@@ -84,7 +84,7 @@ getNOW(eNOWType eNow, cstr_t **ppStr)
uchar szBuf[16];
struct syslogTime t;
- datetime.getCurrTime(&t);
+ datetime.getCurrTime(&t, NULL);
switch(eNow) {
case NOW_NOW:
snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
diff --git a/runtime/var.c b/runtime/var.c
index 7e51fc6d..559bc56c 100644
--- a/runtime/var.c
+++ b/runtime/var.c
@@ -29,6 +29,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -89,6 +90,44 @@ CODESTARTobjDebugPrint(var)
ENDobjDebugPrint(var)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a variable.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-07
+ */
+static rsRetVal
+Obj2Str(var_t *pThis, cstr_t *pstrPrg)
+{
+ DEFiRet;
+ size_t lenBuf;
+ uchar szBuf[2048];
+
+ ISOBJ_TYPE_assert(pThis, var);
+ assert(pstrPrg != NULL);
+ switch(pThis->varType) {
+ case VARTYPE_STR:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s[cstr]", rsCStrGetSzStr(pThis->val.pStr));
+ break;
+ case VARTYPE_NUMBER:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%lld[nbr]", pThis->val.num);
+ break;
+ default:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "**UNKNOWN**[%d]", pThis->varType);
+ break;
+ }
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* duplicates a var instance
* rgerhards, 2008-02-25
*/
@@ -387,6 +426,7 @@ CODESTARTobjQueryInterface(var)
pIf->ConstructFinalize = varConstructFinalize;
pIf->Destruct = varDestruct;
pIf->DebugPrint = varDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->SetNumber = varSetNumber;
pIf->SetString = varSetString;
pIf->ConvForOperation = ConvForOperation;
diff --git a/runtime/var.h b/runtime/var.h
index bbe7ba33..6d890ec9 100644
--- a/runtime/var.h
+++ b/runtime/var.h
@@ -59,6 +59,7 @@ BEGINinterface(var) /* name must also be changed in ENDinterface macro! */
rsRetVal (*ConvToNumber)(var_t *pThis);
rsRetVal (*ConvToBool)(var_t *pThis);
rsRetVal (*ConvToString)(var_t *pThis);
+ rsRetVal (*Obj2Str)(var_t *pThis, cstr_t*);
rsRetVal (*Duplicate)(var_t *pThis, var_t **ppNew);
ENDinterface(var)
#define varCURR_IF_VERSION 1 /* increment whenever you change the interface above! */
diff --git a/runtime/vm.c b/runtime/vm.c
index bc6c3dd2..a25476c2 100644
--- a/runtime/vm.c
+++ b/runtime/vm.c
@@ -331,6 +331,34 @@ finalize_it:
ENDop(PUSHSYSVAR)
+/* The function call operation is only very roughly implemented. While the plumbing
+ * to reach this instruction is fine, the instruction itself currently supports only
+ * functions with a single argument AND with a name that we know.
+ * TODO: later, we can add here the real logic, that involves looking up function
+ * names, loading them dynamically ... and all that...
+ * implementation begun 2009-03-10 by rgerhards
+ */
+BEGINop(FUNC_CALL) /* remember to set the instruction also in the ENDop macro! */
+ var_t *numOperands;
+ var_t *operand1;
+ int iStrlen;
+CODESTARTop(FUNC_CALL)
+ vmstk.PopNumber(pThis->pStk, &numOperands);
+ if(numOperands->val.num != 1)
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+ vmstk.PopString(pThis->pStk, &operand1); /* guess there's just one ;) */
+ if(!rsCStrSzStrCmp(pOp->operand.pVar->val.pStr, (uchar*) "strlen", 6)) { /* only one supported so far ;) */
+RUNLOG_VAR("%s", rsCStrGetSzStr(operand1->val.pStr));
+ iStrlen = strlen((char*) rsCStrGetSzStr(operand1->val.pStr));
+RUNLOG_VAR("%d", iStrlen);
+ } else
+ ABORT_FINALIZE(RS_RET_INVLD_FUNC);
+ PUSHRESULTop(operand1, iStrlen); // TODO: dummy, FIXME
+ var.Destruct(&numOperands); /* no longer needed */
+finalize_it:
+ENDop(FUNC_CALL)
+
+
/* ------------------------------ end instruction set implementation ------------------------------ */
@@ -412,6 +440,7 @@ execProg(vm_t *pThis, vmprg_t *pProg)
doOP(DIV);
doOP(MOD);
doOP(UNARY_MINUS);
+ doOP(FUNC_CALL);
default:
ABORT_FINALIZE(RS_RET_INVALID_VMOP);
dbgoprint((obj_t*) pThis, "invalid instruction %d in vmprg\n", pCurrOp->opcode);
diff --git a/runtime/vmop.c b/runtime/vmop.c
index 219315c4..a343481e 100644
--- a/runtime/vmop.c
+++ b/runtime/vmop.c
@@ -25,6 +25,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -60,27 +61,61 @@ rsRetVal vmopConstructFinalize(vmop_t __attribute__((unused)) *pThis)
/* destructor for the vmop object */
BEGINobjDestruct(vmop) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(vmop)
- if( pThis->opcode == opcode_PUSHSYSVAR
- || pThis->opcode == opcode_PUSHMSGVAR
- || pThis->opcode == opcode_PUSHCONSTANT) {
- if(pThis->operand.pVar != NULL)
- var.Destruct(&pThis->operand.pVar);
- }
+ if(pThis->operand.pVar != NULL)
+ var.Destruct(&pThis->operand.pVar);
ENDobjDestruct(vmop)
/* DebugPrint support for the vmop object */
BEGINobjDebugPrint(vmop) /* be sure to specify the object type also in END and CODESTART macros! */
uchar *pOpcodeName;
+ cstr_t *pStrVar;
CODESTARTobjDebugPrint(vmop)
vmopOpcode2Str(pThis, &pOpcodeName);
- dbgoprint((obj_t*) pThis, "opcode: %d\t(%s), next %p, var in next line\n", (int) pThis->opcode, pOpcodeName,
- pThis->pNext);
- if(pThis->operand.pVar != NULL)
- var.DebugPrint(pThis->operand.pVar);
+ CHKiRet(rsCStrConstruct(&pStrVar));
+ CHKiRet(rsCStrFinish(&pStrVar));
+ if(pThis->operand.pVar != NULL) {
+ CHKiRet(var.Obj2Str(pThis->operand.pVar, pStrVar));
+ }
+ dbgoprint((obj_t*) pThis, "%.12s\t%s\n", pOpcodeName, rsCStrGetSzStrNoNULL(pStrVar));
+ rsCStrDestruct(&pStrVar);
+finalize_it:
ENDobjDebugPrint(vmop)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of an operation.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmop_t *pThis, cstr_t *pstrPrg)
+{
+ uchar *pOpcodeName;
+ uchar szBuf[2048];
+ size_t lenBuf;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmop);
+ assert(pstrPrg != NULL);
+ vmopOpcode2Str(pThis, &pOpcodeName);
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+ if(pThis->operand.pVar != NULL)
+ CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg));
+ CHKiRet(rsCStrAppendChar(pstrPrg, '\n'));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* set operand (variant case)
* rgerhards, 2008-02-20
*/
@@ -124,37 +159,37 @@ vmopOpcode2Str(vmop_t *pThis, uchar **ppName)
*ppName = (uchar*) "and";
break;
case opcode_PLUS:
- *ppName = (uchar*) "+";
+ *ppName = (uchar*) "add";
break;
case opcode_MINUS:
- *ppName = (uchar*) "-";
+ *ppName = (uchar*) "sub";
break;
case opcode_TIMES:
- *ppName = (uchar*) "*";
+ *ppName = (uchar*) "mul";
break;
case opcode_DIV:
- *ppName = (uchar*) "/";
+ *ppName = (uchar*) "div";
break;
case opcode_MOD:
- *ppName = (uchar*) "%";
+ *ppName = (uchar*) "mod";
break;
case opcode_NOT:
*ppName = (uchar*) "not";
break;
case opcode_CMP_EQ:
- *ppName = (uchar*) "==";
+ *ppName = (uchar*) "cmp_==";
break;
case opcode_CMP_NEQ:
- *ppName = (uchar*) "!=";
+ *ppName = (uchar*) "cmp_!=";
break;
case opcode_CMP_LT:
- *ppName = (uchar*) "<";
+ *ppName = (uchar*) "cmp_<";
break;
case opcode_CMP_GT:
- *ppName = (uchar*) ">";
+ *ppName = (uchar*) "cmp_>";
break;
case opcode_CMP_LTEQ:
- *ppName = (uchar*) "<=";
+ *ppName = (uchar*) "cmp_<=";
break;
case opcode_CMP_CONTAINS:
*ppName = (uchar*) "contains";
@@ -163,28 +198,31 @@ vmopOpcode2Str(vmop_t *pThis, uchar **ppName)
*ppName = (uchar*) "startswith";
break;
case opcode_CMP_GTEQ:
- *ppName = (uchar*) ">=";
+ *ppName = (uchar*) "cmp_>=";
break;
case opcode_PUSHSYSVAR:
- *ppName = (uchar*) "PUSHSYSVAR";
+ *ppName = (uchar*) "push_sysvar";
break;
case opcode_PUSHMSGVAR:
- *ppName = (uchar*) "PUSHMSGVAR";
+ *ppName = (uchar*) "push_msgvar";
break;
case opcode_PUSHCONSTANT:
- *ppName = (uchar*) "PUSHCONSTANT";
+ *ppName = (uchar*) "push_const";
break;
case opcode_POP:
- *ppName = (uchar*) "POP";
+ *ppName = (uchar*) "pop";
break;
case opcode_UNARY_MINUS:
- *ppName = (uchar*) "UNARY_MINUS";
+ *ppName = (uchar*) "unary_minus";
break;
case opcode_STRADD:
- *ppName = (uchar*) "STRADD";
+ *ppName = (uchar*) "strconcat";
+ break;
+ case opcode_FUNC_CALL:
+ *ppName = (uchar*) "func_call";
break;
default:
- *ppName = (uchar*) "INVALID opcode";
+ *ppName = (uchar*) "!invalid_opcode!";
break;
}
@@ -206,8 +244,6 @@ CODESTARTobjQueryInterface(vmop)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmop;
-
pIf->Construct = vmopConstruct;
pIf->ConstructFinalize = vmopConstructFinalize;
pIf->Destruct = vmopDestruct;
@@ -215,6 +251,7 @@ CODESTARTobjQueryInterface(vmop)
pIf->SetOpcode = vmopSetOpcode;
pIf->SetVar = vmopSetVar;
pIf->Opcode2Str = vmopOpcode2Str;
+ pIf->Obj2Str = Obj2Str;
finalize_it:
ENDobjQueryInterface(vmop)
diff --git a/runtime/vmop.h b/runtime/vmop.h
index 97f924d7..938b08fd 100644
--- a/runtime/vmop.h
+++ b/runtime/vmop.h
@@ -26,6 +26,7 @@
#define INCLUDED_VMOP_H
#include "ctok_token.h"
+#include "stringbuf.h"
/* machine instructions types */
typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */
@@ -58,17 +59,44 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
opcode_PUSHMSGVAR = 1002, /* requires var operand */
opcode_PUSHCONSTANT = 1003, /* requires var operand */
opcode_UNARY_MINUS = 1010,
- opcode_END_PROG = 1011
+ opcode_FUNC_CALL = 1012,
+ opcode_END_PROG = 2000
} opcode_t;
+/* Additional doc, operation specific
+
+ FUNC_CALL
+ All parameter passing is via the stack. Parameters are placed onto the stack in reverse order,
+ that means the last parameter is on top of the stack, the first at the bottom location.
+ At the actual top of the stack is the number of parameters. This permits functions to be
+ called with variable number of arguments. The function itself is responsible for poping
+ the right number of parameters of the stack and complaining if the number is incorrect.
+ On exit, a single return value must be pushed onto the stack. The FUNC_CALL operation
+ is generic. Its pVar argument contains the function name string (TODO: very slow, make
+ faster in later releases).
+
+ Sample Function call: sampleFunc(p1, p2, p3) ; returns number 4711 (sample)
+ Stacklayout on entry (order is top to bottom):
+ 3
+ p3
+ p2
+ p1
+ ... other vars ...
+
+ Stack on exit
+ 4711
+ ... other vars ...
+
+ */
+
+
/* the vmop object */
typedef struct vmop_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
opcode_t opcode;
union {
- var_t *pVar;
- /* TODO: add function pointer */
+ var_t *pVar; /* for function call, this is the name (string) of function to be called */
} operand;
struct vmop_s *pNext; /* next operation or NULL, if end of program (logically this belongs to vmprg) */
} vmop_t;
@@ -83,6 +111,7 @@ BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode);
rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar);
rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName);
+ rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr);
ENDinterface(vmop)
#define vmopCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/vmprg.c b/runtime/vmprg.c
index a2b744d7..75915025 100644
--- a/runtime/vmprg.c
+++ b/runtime/vmprg.c
@@ -24,12 +24,14 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rsyslog.h"
#include "obj.h"
#include "vmprg.h"
+#include "stringbuf.h"
/* static data */
DEFobjStaticHelpers
@@ -72,13 +74,47 @@ ENDobjDestruct(vmprg)
BEGINobjDebugPrint(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */
vmop_t *pOp;
CODESTARTobjDebugPrint(vmprg)
- dbgoprint((obj_t*) pThis, "program contents:\n");
+ dbgoprint((obj_t*) pThis, "VM Program:\n");
for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) {
vmop.DebugPrint(pOp);
}
ENDobjDebugPrint(vmprg)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a bytecode program.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg)
+{
+ uchar szAddr[12];
+ vmop_t *pOp;
+ int i;
+ int lenAddr;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmprg);
+ assert(pstrPrg != NULL);
+ i = 0; /* "program counter" */
+ for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) {
+ lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr));
+ vmop.Obj2Str(pOp, pstrPrg);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* add an operation (instruction) to the end of the current program. This
* function is expected to be called while creating the program, but never
* again after this is done and it is being executed. Results are undefined if
@@ -146,12 +182,11 @@ CODESTARTobjQueryInterface(vmprg)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmprg;
-
pIf->Construct = vmprgConstruct;
pIf->ConstructFinalize = vmprgConstructFinalize;
pIf->Destruct = vmprgDestruct;
pIf->DebugPrint = vmprgDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->AddOperation = vmprgAddOperation;
pIf->AddVarOperation = vmprgAddVarOperation;
finalize_it:
diff --git a/runtime/vmprg.h b/runtime/vmprg.h
index db1f62f0..c1042f7d 100644
--- a/runtime/vmprg.h
+++ b/runtime/vmprg.h
@@ -38,7 +38,7 @@
#define INCLUDED_VMPRG_H
#include "vmop.h"
-
+#include "stringbuf.h"
/* the vmprg object */
typedef struct vmprg_s {
@@ -56,6 +56,7 @@ BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Destruct)(vmprg_t **ppThis);
rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp);
rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar);
+ rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr);
ENDinterface(vmprg)
#define vmprgCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/wti.c b/runtime/wti.c
index a2531499..544bffa7 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -39,15 +39,22 @@
#include <pthread.h>
#include <errno.h>
+#ifdef OS_SOLARIS
+# include <sched.h>
+# define pthread_yield() sched_yield()
+#endif
+
#include "rsyslog.h"
#include "stringbuf.h"
#include "srUtils.h"
#include "wtp.h"
#include "wti.h"
#include "obj.h"
+#include "glbl.h"
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
/* forward-definitions */
@@ -113,6 +120,9 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex)
wtiGetDbgHdr(pThis), tCmd, pThis->tCurrCmd);
} else {
dbgprintf("%s: receiving command %d\n", wtiGetDbgHdr(pThis), tCmd);
+ /* we could replace this with a simple if, but we leave the switch in in case we need
+ * to add something at a later stage. -- rgerhards, 2008-09-30
+ */
switch(tCmd) {
case eWRKTHRD_TERMINATING:
/* TODO: re-enable meaningful debug msg! (via function callback?)
@@ -123,10 +133,8 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex)
pthread_cond_signal(&pThis->condExitDone);
dbgprintf("%s: worker terminating\n", wtiGetDbgHdr(pThis));
break;
- case eWRKTHRD_RUNNING:
- pthread_cond_signal(&pThis->condInitDone);
- break;
/* these cases just to satisfy the compiler, we do (yet) not act an them: */
+ case eWRKTHRD_RUNNING:
case eWRKTHRD_STOPPED:
case eWRKTHRD_RUN_CREATED:
case eWRKTHRD_RUN_INIT:
@@ -190,7 +198,6 @@ CODESTARTobjDestruct(wti)
d_pthread_mutex_unlock(&pThis->mut);
/* actual destruction */
- pthread_cond_destroy(&pThis->condInitDone);
pthread_cond_destroy(&pThis->condExitDone);
pthread_mutex_destroy(&pThis->mut);
@@ -202,7 +209,7 @@ ENDobjDestruct(wti)
/* Standard-Constructor for the wti object
*/
BEGINobjConstruct(wti) /* be sure to specify the object type also in END macro! */
- pthread_cond_init(&pThis->condInitDone, NULL);
+ pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
pthread_cond_init(&pThis->condExitDone, NULL);
pthread_mutex_init(&pThis->mut, NULL);
ENDobjConstruct(wti)
@@ -304,7 +311,7 @@ wtiWorkerCancelCleanup(void *arg)
pWtp = pThis->pWtp;
ISOBJ_TYPE_assert(pWtp, wtp);
- dbgprintf("%s: cancelation cleanup handler called.\n", wtiGetDbgHdr(pThis));
+ DBGPRINTF("%s: cancelation cleanup handler called.\n", wtiGetDbgHdr(pThis));
/* call user supplied handler (that one e.g. requeues the element) */
pWtp->pfOnWorkerCancel(pThis->pWtp->pUsr, pThis->pUsrp);
@@ -372,7 +379,8 @@ wtiWorker(wti_t *pThis)
wtpProcessThrdChanges(pWtp);
pthread_testcancel(); /* see big comment in function header */
# if !defined(__hpux) /* pthread_yield is missing there! */
- pthread_yield(); /* see big comment in function header */
+ if(pThis->bOptimizeUniProc)
+ pthread_yield(); /* see big comment in function header */
# endif
/* if we have a rate-limiter set for this worker pool, let's call it. Please
@@ -396,7 +404,7 @@ wtiWorker(wti_t *pThis)
/* if we reach this point, we are still protected by the mutex */
if(pWtp->pfIsIdle(pWtp->pUsr, MUTEX_ALREADY_LOCKED)) {
- dbgprintf("%s: worker IDLE, waiting for work.\n", wtiGetDbgHdr(pThis));
+ DBGPRINTF("%s: worker IDLE, waiting for work.\n", wtiGetDbgHdr(pThis));
pWtp->pfOnIdle(pWtp->pUsr, MUTEX_ALREADY_LOCKED);
if(pWtp->toWrkShutdown == -1) {
@@ -405,7 +413,7 @@ wtiWorker(wti_t *pThis)
} else {
timeoutComp(&t, pWtp->toWrkShutdown);/* get absolute timeout */
if(d_pthread_cond_timedwait(pWtp->pcondBusy, pWtp->pmutUsr, &t) != 0) {
- dbgprintf("%s: inactivity timeout, worker terminating...\n", wtiGetDbgHdr(pThis));
+ DBGPRINTF("%s: inactivity timeout, worker terminating...\n", wtiGetDbgHdr(pThis));
bInactivityTOOccured = 1; /* indicate we had a timeout */
}
}
@@ -471,6 +479,14 @@ finalize_it:
/* dummy */
rsRetVal wtiQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
+/* exit our class
+ */
+BEGINObjClassExit(wti, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(nsdsel_gtls)
+ /* release objects we no longer need */
+ objRelease(glbl, CORE_COMPONENT);
+ENDObjClassExit(wti)
+
/* Initialize the wti class. Must be called as the very first method
* before anything else is called inside this class.
@@ -478,6 +494,7 @@ rsRetVal wtiQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
*/
BEGINObjClassInit(wti, 1, OBJ_IS_CORE_MODULE) /* one is the object version (most important for persisting) */
/* request objects we use */
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
ENDObjClassInit(wti)
/*
diff --git a/runtime/wti.h b/runtime/wti.h
index b3d92473..6b60b833 100644
--- a/runtime/wti.h
+++ b/runtime/wti.h
@@ -31,11 +31,11 @@
/* the worker thread instance class */
typedef struct wti_s {
BEGINobjInstance;
+ int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
pthread_t thrdID; /* thread ID */
qWrkCmd_t tCurrCmd; /* current command to be carried out by worker */
obj_t *pUsrp; /* pointer to an object meaningful for current user pointer (e.g. queue pUsr data elemt) */
wtp_t *pWtp; /* my worker thread pool (important if only the work thread instance is passed! */
- pthread_cond_t condInitDone; /* signaled when the thread startup is done (once per thread existance) */
pthread_cond_t condExitDone; /* signaled when the thread exit is done (once per thread existance) */
pthread_mutex_t mut;
int bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */
diff --git a/runtime/wtp.c b/runtime/wtp.c
index fcefa1d8..9f54a9ab 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -40,15 +40,22 @@
#include <unistd.h>
#include <errno.h>
+#ifdef OS_SOLARIS
+# include <sched.h>
+# define pthread_yield() sched_yield()
+#endif
+
#include "rsyslog.h"
#include "stringbuf.h"
#include "srUtils.h"
#include "wtp.h"
#include "wti.h"
#include "obj.h"
+#include "glbl.h"
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
/* forward-definitions */
@@ -75,6 +82,7 @@ static rsRetVal NotImplementedDummy() { return RS_RET_OK; }
/* Standard-Constructor for the wtp object
*/
BEGINobjConstruct(wtp) /* be sure to specify the object type also in END macro! */
+ pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
pthread_mutex_init(&pThis->mut, NULL);
pthread_mutex_init(&pThis->mutThrdShutdwn, NULL);
pthread_cond_init(&pThis->condThrdTrm, NULL);
@@ -171,7 +179,9 @@ wtpWakeupAllWrkr(wtp_t *pThis)
DEFiRet;
ISOBJ_TYPE_assert(pThis, wtp);
+ d_pthread_mutex_lock(pThis->pmutUsr);
pthread_cond_broadcast(pThis->pcondBusy);
+ d_pthread_mutex_unlock(pThis->pmutUsr);
RETiRet;
}
@@ -316,11 +326,12 @@ wtpShutdownAll(wtp_t *pThis, wtpState_t tShutdownCmd, struct timespec *ptTimeout
rsRetVal wtpSignalWrkrTermination(wtp_t *pThis)
{
DEFiRet;
- /* I leave the mutex code here out as it give as deadlocks. I think it is not really
+ /* I leave the mutex code here out as it gives us deadlocks. I think it is not really
* needed and we are on the safe side. I leave this comment in if practice proves us
- * wrong. The whole thing should be removed after half a your or year if we see there
+ * wrong. The whole thing should be removed after half a year or year if we see there
* actually is no issue (or revisit it from a theoretical POV).
* rgerhards, 2008-01-28
+ * revisited 2008-09-30, still a bit unclear, leave in
*/
/*TODO: mutex or not mutex, that's the question ;)DEFVARS_mutexProtection;*/
@@ -467,7 +478,7 @@ wtpStartWrkr(wtp_t *pThis, int bLockMutex)
ISOBJ_TYPE_assert(pThis, wtp);
- wtpProcessThrdChanges(pThis);
+ wtpProcessThrdChanges(pThis); // TODO: Performance: this causes a lot of FUTEX calls
BEGIN_MTX_PROTECTED_OPERATIONS(&pThis->mut, bLockMutex);
@@ -495,7 +506,8 @@ wtpStartWrkr(wtp_t *pThis, int bLockMutex)
* hold the queue's mutex, but at least it has a chance to start on a single-CPU system.
*/
# if !defined(__hpux) /* pthread_yield is missing there! */
- pthread_yield();
+ if(pThis->bOptimizeUniProc)
+ pthread_yield();
# endif
/* indicate we just started a worker and would like to see it running */
@@ -628,12 +640,22 @@ finalize_it:
/* dummy */
rsRetVal wtpQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
+/* exit our class
+ */
+BEGINObjClassExit(wtp, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(nsdsel_gtls)
+ /* release objects we no longer need */
+ objRelease(glbl, CORE_COMPONENT);
+ENDObjClassExit(wtp)
+
+
/* Initialize the stream class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-01-09
*/
BEGINObjClassInit(wtp, 1, OBJ_IS_CORE_MODULE)
/* request objects we use */
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
ENDObjClassInit(wtp)
/*
diff --git a/runtime/wtp.h b/runtime/wtp.h
index 0f21ac11..b9cb07c5 100644
--- a/runtime/wtp.h
+++ b/runtime/wtp.h
@@ -52,6 +52,7 @@ typedef enum {
/* the worker thread pool (wtp) object */
typedef struct wtp_s {
BEGINobjInstance;
+ int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
wtpState_t wtpState;
int iNumWorkerThreads;/* number of worker threads to use */
int iCurNumWrkThrd;/* current number of active worker threads */