diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | runtime/Makefile.am | 1 | ||||
-rw-r--r-- | runtime/atomic-posix-sem.c | 70 | ||||
-rw-r--r-- | runtime/atomic.h | 120 | ||||
-rw-r--r-- | runtime/rsyslog.c | 14 | ||||
-rw-r--r-- | solaris/README | 34 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rwxr-xr-x | tests/complex1.sh | 5 | ||||
-rwxr-xr-x | tests/diag.sh | 13 | ||||
-rw-r--r-- | tests/msleep.c | 50 | ||||
-rw-r--r-- | tests/tcpflood.c | 14 | ||||
-rw-r--r-- | tools/ompipe.c | 1 | ||||
-rw-r--r-- | tools/syslogd.c | 6 |
14 files changed, 328 insertions, 9 deletions
@@ -2,6 +2,8 @@ Version 4.6.2 [v4-stable] (rgerhards), 2010-03-?? - new feature: "." action type added to support writing files to relative pathes (this is primarily meant as a debug aid) +- added replacements for atomic instructions on systems that do not + support them. [backport of Stefen Sledz' patch for v5) - new feature: $OMFileAsyncWriting directive added it permits to specifiy if asynchronous writing should be done or not - bugfix(temporary): message-induced off-by-one error (potential segfault) diff --git a/configure.ac b/configure.ac index b059fe75..fcd70c30 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,7 @@ AC_TYPE_UINT8_T AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE +AC_C_TYPEOF sa_includes="\ $ac_includes_default @@ -126,6 +127,9 @@ AC_TRY_COMPILE([ # check for availability of atomic operations RS_ATOMIC_OPERATIONS +# fall back to POSIX sems for atomic operations (cpu expensive) +AC_CHECK_HEADERS([semaphore.h]) + # Additional module directories AC_ARG_WITH(moddirs, diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 14abe722..e5b3ccdf 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -9,6 +9,7 @@ librsyslog_la_SOURCES = \ rsyslog.h \ unicode-helper.h \ atomic.h \ + atomic-posix-sem.c \ syslogd-types.h \ module-template.h \ obj-types.h \ diff --git a/runtime/atomic-posix-sem.c b/runtime/atomic-posix-sem.c new file mode 100644 index 00000000..979fae02 --- /dev/null +++ b/runtime/atomic-posix-sem.c @@ -0,0 +1,70 @@ +/* atomic_posix_sem.c: This file supplies an emulation for atomic operations using + * POSIX semaphores. + * + * Copyright 2010 DResearch Digital Media Systems 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" +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H +#include <semaphore.h> +#include <errno.h> + +#include "atomic.h" +#include "rsyslog.h" +#include "srUtils.h" + +sem_t atomicSem; + +rsRetVal +atomicSemInit(void) +{ + DEFiRet; + + dbgprintf("init posix semaphore for atomics emulation\n"); + if(sem_init(&atomicSem, 0, 1) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("init posix semaphore for atomics emulation failed: %s\n", errStr); + iRet = RS_RET_SYS_ERR; /* the right error code ??? */ + } + + RETiRet; +} + +void +atomicSemExit(void) +{ + dbgprintf("destroy posix semaphore for atomics emulation\n"); + if(sem_destroy(&atomicSem) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("destroy posix semaphore for atomics emulation failed: %s\n", errStr); + } +} + +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + +/* vim:set ai: + */ diff --git a/runtime/atomic.h b/runtime/atomic.h index d5aaf56b..ea3be37a 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -53,6 +53,122 @@ # define ATOMIC_CAS(data, oldVal, newVal) __sync_bool_compare_and_swap(&(data), (oldVal), (newVal)); # define ATOMIC_CAS_VAL(data, oldVal, newVal) __sync_val_compare_and_swap(&(data), (oldVal), (newVal)); #else +#ifdef HAVE_SEMAPHORE_H + /* we use POSIX semaphores instead */ + +#include "rsyslog.h" +#include <semaphore.h> + +extern sem_t atomicSem; +rsRetVal atomicSemInit(void); +void atomicSemExit(void); + +#if HAVE_TYPEOF +#define my_typeof(x) typeof(x) +#else /* sorry, can't determine types, using 'int' */ +#define my_typeof(x) int +#endif + +# define ATOMIC_SUB(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data -= val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_ADD(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC_AND_FETCH(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC(data) ((void) ATOMIC_INC_AND_FETCH(data)) + +# define ATOMIC_DEC_AND_FETCH(data) \ +({ \ + sem_wait(&atomicSem); \ + data -= 1; \ + sem_post(&atomicSem); \ + data; \ +}) + +# define ATOMIC_DEC(data) ((void) ATOMIC_DEC_AND_FETCH(data)) + +# define ATOMIC_FETCH_32BIT(data) ((unsigned) ATOMIC_ADD((data), 0xffffffff)) + +# define ATOMIC_STORE_1_TO_32BIT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_0_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 0; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_1_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_CAS(data, oldVal, newVal) \ +({ \ + int ret; \ + sem_wait(&atomicSem); \ + if(data != oldVal) ret = 0; \ + else \ + { \ + data = newVal; \ + ret = 1; \ + } \ + sem_post(&atomicSem); \ + ret; \ +}) + +# define ATOMIC_CAS_VAL(data, oldVal, newVal) \ +({ \ + sem_wait(&atomicSem); \ + if(data == oldVal) \ + { \ + data = newVal; \ + } \ + sem_post(&atomicSem); \ + data; \ +}) + +#else /* not HAVE_SEMAPHORE_H */ /* 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 @@ -66,6 +182,10 @@ # define ATOMIC_DEC_AND_FETCH(data) (--(data)) # define ATOMIC_FETCH_32BIT(data) (data) # define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 +# define ATOMIC_STORE_1_TO_INT(data) (data) = 1 +# define ATOMIC_STORE_0_TO_INT(data) (data) = 0 +# define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) +#endif #endif #endif /* #ifndef INCLUDED_ATOMIC_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 443d0f41..5750ca76 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -80,6 +80,7 @@ #include "prop.h" #include "rule.h" #include "ruleset.h" +#include "atomic.h" /* forward definitions */ static rsRetVal dfltErrLogger(int, uchar *errMsg); @@ -139,6 +140,12 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */ CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */ +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + CHKiRet(atomicSemInit()); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + /* initialize core classes. We must be very careful with the order of events. Some * classes use others and if we do not initialize them in the right order, we may end * up with an invalid call. The most important thing that can happen is that an error @@ -215,6 +222,13 @@ rsrtExit(void) glblClassExit(); rulesetClassExit(); ruleClassExit(); + +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + atomicSemExit(); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ } diff --git a/solaris/README b/solaris/README new file mode 100644 index 00000000..0700642e --- /dev/null +++ b/solaris/README @@ -0,0 +1,34 @@ +Notes for Solaris + +Rsyslog will be fully supported on Solaris in the future. To build it, the GNU build +tools (and most of the GNU environment) is needed. This software can be +found at the excellent http://www.blastwave.org site. + +PREQUISITES +It is strongly recommended to use GCC4 with support for +atomic instructions (if available for the platform). While rsyslog can +be built without atomic instructin support (and will work well then), +it then falls back to POSIX semaphores, which require much more CPU +time than atomic instructions. Note that even on intel platforms the +(current, as of 2010-03-25) blastwave gcc4 version targets too-old +processors by default. To change that, use "-imarch=I686" in your +CFLAGS. + +CONFIGURE OPTIONS +A number of GNU tools are renamed g* so that they not conflict with +the native Solaris tools. As we need the GNU replacements, this +must be specified on the ./configure line. +Also, we must tell the linker where to find the glibc library when +building the plugins. This is done via the LDFLAGS variable as +shown below (based on the good information availabe at +http://prefetch.net/articles/linkers.badldlibrary.html + +The working sample configure sequence I use is: + +export LDFLAGS="-R/usr/local/lib" +./configure AR=gar ...other options... + + +NOT YET SUPPORTED +* local log socket +* kernel log diff --git a/tests/Makefile.am b/tests/Makefile.am index 0b1ccb4b..41b13a18 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -199,6 +199,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ cfg.sh ourtail_SOURCES = ourtail.c +msleep_SOURCES = msleep.c chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c diff --git a/tests/complex1.sh b/tests/complex1.sh index b5dc2c9d..7395bf21 100755 --- a/tests/complex1.sh +++ b/tests/complex1.sh @@ -10,12 +10,13 @@ source $srcdir/diag.sh init export RSYSLOG_DEBUG="debug nostdout" export RSYSLOG_DEBUGLOG="log" source $srcdir/diag.sh startup complex1.conf -# send 30,000 messages of 400 bytes plus header max, via three dest ports +# send 40,000 messages of 400 bytes plus header max, via three dest ports source $srcdir/diag.sh tcpflood -m40000 -rd400 -P129 -f5 -n3 -c15 -i1 sleep 2 # due to large messages, we need this time for the tcp receiver to settle... source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh wait-shutdown # and wait for it to terminate ls rsyslog.out.*.log -zcat rsyslog.out.*.log > rsyslog.out.log +source $srcdir/diag.sh setzcat # find out which zcat to use +$ZCAT rsyslog.out.*.log > rsyslog.out.log source $srcdir/diag.sh seq-check 1 40000 -E source $srcdir/diag.sh exit diff --git a/tests/diag.sh b/tests/diag.sh index 8f268a5e..c0f736b8 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -38,16 +38,14 @@ case $1 in ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) while test ! -f rsyslogd$2.started; do - #true - sleep 0.1 # if this is not supported by all platforms, use above! + ./msleep 100 # wait 100 milliseconds done echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid` ;; 'wait-shutdown') # actually, we wait for rsyslog.pid to be deleted. $2 is the # instance while test -f rsyslog$2.pid; do - #true - sleep 0.1 # if this is not supported by all platforms, use above! + ./msleep 100 # wait 100 milliseconds done ;; 'wait-queueempty') # wait for main message queue to be empty. $2 is the instance. @@ -131,5 +129,12 @@ case $1 in exit 1 fi ;; + 'setzcat') # find out name of zcat tool + if [ `uname` == SunOS ]; then + ZCAT=gzcat + else + ZCAT=zcat + fi + ;; *) echo "invalid argument" $1 esac diff --git a/tests/msleep.c b/tests/msleep.c new file mode 100644 index 00000000..6fa57b79 --- /dev/null +++ b/tests/msleep.c @@ -0,0 +1,50 @@ +/* sleeps for the specified number of MILLIseconds. + * Primarily meant as a portable tool available everywhere for the + * testbench (sleep 0.1 does not work on all platforms). + * + * Part of the testbench for rsyslog. + * + * Copyright 2010 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) +{ + struct timeval tvSelectTimeout; + long sleepTime; + + if(argc != 2) { + fprintf(stderr, "usage: msleep <milliseconds>\n"); + exit(1); + } + + sleepTime = atoi(argv[1]); + tvSelectTimeout.tv_sec = sleepTime / 1000; + tvSelectTimeout.tv_usec = (sleepTime % 1000) * 1000; /* micro seconds */ + if(select(0, NULL, NULL, NULL, &tvSelectTimeout) == -1) { + perror("select"); + exit(1); + } + + return 0; +} + diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 32bf959d..259b84b3 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -370,6 +370,20 @@ int main(int argc, char *argv[]) } } + if(numConnections > 20) { + /* if we use many (whatever this means, 20 is randomly picked) + * connections, we need to make sure we have a high enough + * limit. -- rgerhards, 2010-03-25 + */ + struct rlimit maxFiles; + maxFiles.rlim_cur = numConnections + 20; + maxFiles.rlim_max = numConnections + 20; + if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { + perror("setrlimit to increase file handles failed"); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); diff --git a/tools/ompipe.c b/tools/ompipe.c index 5fb9b27e..7cf61822 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -39,6 +39,7 @@ #include <string.h> #include <assert.h> #include <errno.h> +#include <fcntl.h> #include <sys/file.h> #include "syslogd.h" diff --git a/tools/syslogd.c b/tools/syslogd.c index 64b23566..a61d1e5d 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -3174,6 +3174,7 @@ int realMain(int argc, char **argv) uchar *LocalHostName; uchar *LocalDomain; uchar *LocalFQDNName; + char cwdbuf[128]; /* buffer to obtain/display current working directory */ /* first, parse the command line options. We do not carry out any actual work, just * see what we should do. This relieves us from certain anomalies and we can process @@ -3260,8 +3261,9 @@ int realMain(int argc, char **argv) if ((argc -= optind)) usage(); - DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s'\n", - VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath); + DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n", + VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath, + getcwd(cwdbuf, sizeof(cwdbuf))); /* we are done with the initial option parsing and processing. Now we init the system. */ |