--- 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 <string.h>
+#include <unistd.h> /* has setitime() in standard unix functions */
+#include <signal.h> /* 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)
|