OSSP CVS Repository

ossp - Check-in [1073]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1073
Date: 2001-Oct-05 12:40:17 (local)
2001-Oct-05 10:40:17 (UTC)
User:ms
Branch:
Comment: Added untested code to implement alarm exceptions in the buffer channel. The buffer will auto-flush after a user specified timeout if it is even possible to do this with a c-style exception handler.
Tickets:
Inspections:
Files:
ossp-pkg/l2/TODO      1.27 -> 1.28     9 inserted, 0 deleted
ossp-pkg/l2/l2_ch_buffer.c      1.21 -> 1.22     90 inserted, 8 deleted
ossp-pkg/l2/l2_test.c      1.31 -> 1.32     1 inserted, 1 deleted

ossp-pkg/l2/TODO 1.27 -> 1.28

--- 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


ossp-pkg/l2/l2_ch_buffer.c 1.21 -> 1.22

--- 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)


ossp-pkg/l2/l2_test.c 1.31 -> 1.32

--- 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   */

CVSTrac 2.0.1