Index: ossp-pkg/l2/TODO RCS File: /v/ossp/cvs/ossp-pkg/l2/TODO,v rcsdiff -q -kk '-r1.27' '-r1.28' -u '/v/ossp/cvs/ossp-pkg/l2/TODO,v' 2>/dev/null --- TODO 2001/09/28 14:30:49 1.27 +++ TODO 2001/10/05 10:40:17 1.28 @@ -48,6 +48,15 @@ erase, what happens to its data when it is over written or flushed... +o buffer timer + How on earth to use a C-style exception handler to flush + our buffer? We can't directly call ANY function from an + exception state, so this might not work at all. + + Depends on SIGALARM, only one handler of which may exist. + A more robust implementation would not use such a precious + resource, and guard against signal collision with other channels. + o syslog many options need docu, and we should mention to the user that more info is found in the man page Index: ossp-pkg/l2/l2_ch_buffer.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ch_buffer.c,v rcsdiff -q -kk '-r1.21' '-r1.22' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_buffer.c,v' 2>/dev/null --- l2_ch_buffer.c 2001/09/14 07:41:49 1.21 +++ l2_ch_buffer.c 2001/10/05 10:40:17 1.22 @@ -28,18 +28,30 @@ */ #include "l2.h" +#include "l2_p.h" /* for TRACE() */ #include +#include /* has setitime() in standard unix functions */ +#include /* for use of sigaction() and SIGALRM */ /* declare private channel configuration */ typedef struct { char *buf; int bufpos; int bufsize; + int bufinterval; + struct sigaction sigalrm; + struct itimerval valprev; int levelflush; l2_level_t level; } l2_ch_buffer_t; +static void catchsignal(int sig, ...) +{ + if (sig == SIGALRM) + TRACE("SIGALRM caught"); +} + /* create channel */ static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch) { @@ -50,11 +62,14 @@ return L2_ERR_MEM; /* initialize configuration with reasonable defaults */ - cfg->buf = NULL; - cfg->bufpos = 0; - cfg->bufsize = 4096; - cfg->levelflush = 0; - cfg->level = L2_LEVEL_NONE; + cfg->buf = NULL; + cfg->bufpos = 0; + cfg->bufsize = 4096; + cfg->bufinterval = 0; + cfg->levelflush = 0; + cfg->level = L2_LEVEL_NONE; + memset(&cfg->sigalrm, 0, sizeof(cfg->sigalrm)); + memset(&cfg->valprev, 0, sizeof(cfg->valprev)); /* link private channel configuration into channel context */ ctx->vp = cfg; @@ -66,13 +81,14 @@ static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap) { l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp; - l2_param_t pa[3]; + l2_param_t pa[4]; l2_result_t rv; /* feed and call generic parameter parsing engine */ L2_PARAM_SET(pa[0], size, INT, &cfg->bufsize); - L2_PARAM_SET(pa[1], levelflush, INT, &cfg->levelflush); - L2_PARAM_END(pa[2]); + L2_PARAM_SET(pa[1], interval, INT, &cfg->bufinterval); + L2_PARAM_SET(pa[2], levelflush, INT, &cfg->levelflush); + L2_PARAM_END(pa[3]); rv = l2_util_setparams(pa, fmt, ap); if (cfg->bufsize < 0) return L2_ERR_ARG; @@ -80,13 +96,66 @@ return rv; } +/************************************************************ + * set_alarm: Helper method to hook_open * + * Sets the VIRTUAL timer to preconfigured value in cfg * + ************************************************************/ +static int set_alarm(l2_ch_buffer_t *cfg) +{ + struct itimerval valnew; + + /* initialize auto vars before using them */ + memset(&valnew, 0, sizeof(valnew)); + + valnew.it_interval.tv_sec = cfg->bufinterval; + valnew.it_interval.tv_usec = 0; + valnew.it_value.tv_sec = cfg->bufinterval; + valnew.it_value.tv_usec = 0; + return setitimer(ITIMER_VIRTUAL, &valnew, &cfg->valprev); /* set flush timer */ +} + +/************************************************************ + * reset_alarm: Helper method to hook_flush * + * Resets the VIRTUAL timer to preconfigured value in cfg * + ************************************************************/ +static int reset_alarm(l2_ch_buffer_t *cfg) +{ + struct itimerval valnew; + + /* initialize auto vars before using them */ + memset(&valnew, 0, sizeof(valnew)); + + valnew.it_interval.tv_sec = cfg->bufinterval; + valnew.it_interval.tv_usec = 0; + valnew.it_value.tv_sec = cfg->bufinterval; + valnew.it_value.tv_usec = 0; + return setitimer(ITIMER_VIRTUAL, &valnew, 0); /* reset flush timer */ +} + /* open channel */ static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch) { l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp; l2_channel_t *downstream = l2_channel_downstream(ch); + struct sigaction locact; l2_result_t rv; + if (cfg->bufinterval != 0) { + /* initialize auto vars before using them */ + memset(&locact, 0, sizeof(locact)); + + locact.sa_handler = (void(*)())catchsignal; + sigemptyset(&locact.sa_mask); + locact.sa_flags = 0; + + /* save old signal context before replacing with our own */ + if (sigaction(SIGALRM, &locact, &cfg->sigalrm) < 0) + return L2_ERR_SYS; + + if (set_alarm(cfg)) + return L2_ERR_SYS; + } + /* open channel buffer */ if (cfg->bufsize > 0) { if ((cfg->buf = malloc(cfg->bufsize)) == NULL) @@ -156,6 +225,11 @@ cfg->level = L2_LEVEL_NONE; /* reset this->context->level */ } + /* reset the flush alarm timer to synchronize the buffer */ + if (cfg->bufinterval != 0) + if (reset_alarm(cfg)) + return L2_ERR_SYS; + /* optionally flush downstream channel, too */ if ((rv = l2_channel_flush(downstream)) != L2_OK) return rv; @@ -170,6 +244,14 @@ l2_channel_t *downstream = l2_channel_downstream(ch); l2_result_t rv; + if (cfg->bufinterval != 0) { + setitimer(ITIMER_VIRTUAL, &cfg->valprev, 0); /* restore timer values */ + /* restore previous signal context if previously saved & replaced */ + if (&cfg->sigalrm.sa_handler) + if (sigaction(SIGALRM, &cfg->sigalrm, 0) < 0) + rv = L2_ERR_SYS; + } + /* write pending data before closing down */ if (cfg->bufpos > 0) { if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK) Index: ossp-pkg/l2/l2_test.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_test.c,v rcsdiff -q -kk '-r1.31' '-r1.32' -u '/v/ossp/cvs/ossp-pkg/l2/l2_test.c,v' 2>/dev/null --- l2_test.c 2001/10/04 14:58:29 1.31 +++ l2_test.c 2001/10/05 10:40:17 1.32 @@ -99,7 +99,7 @@ if ((chBuf = l2_channel_create(&l2_handler_buffer)) == NULL) /* Buffer */ die("failed to create buffer channel"); - if (l2_channel_configure(chBuf, "size", 100) != L2_OK) + if (l2_channel_configure(chBuf, "size,interval", 100, 20) != L2_OK) die("failed to configure buffer channel"); if ((chFile = l2_channel_create(&l2_handler_file)) == NULL) /* File */