Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

sfeventq.c

Go to the documentation of this file.
00001 /**
00002 **  @file       sfeventq.c
00003 **
00004 **  @author     Daniel Roelker <droelker@sourcefire.com>
00005 **
00006 **  @brief      This provides generic functions for queuing events and
00007 **              inserting the events with a provided function.  All
00008 **              memory management for events is provided here.
00009 **
00010 **  Copyright (C) 2004, Daniel Roelker and Sourcefire, Inc.
00011 **
00012 **  The sfeventq functions provide a generic way for handling events,
00013 **  prioritizing those events, and acting on the highest ranked events
00014 **  with a user function.
00015 **
00016 **  Example on using sfeventq:
00017 **
00018 **  1. Initialize event queue
00019 **       sfeventq_init()
00020 **
00021 **  2. Add events to queue
00022 **       sfeventq_event_alloc() allocates the memory for storing the event.
00023 **       sfeventq_add() adds the event and prioritizes the event in the queue.
00024 **       You should only allocate and add one event at a time.  Otherwise,
00025 **       event_alloc() will return NULL on memory exhaustion.
00026 **
00027 **  3. Event actions
00028 **       sfeventq_action() will call the provided function on the initialized
00029 **       number of events to log.
00030 */
00031 
00032 #include <stdlib.h>
00033 
00034 typedef struct s_SF_EVENTQ_NODE
00035 {
00036     void   *event;
00037 
00038     struct s_SF_EVENTQ_NODE *prev;
00039     struct s_SF_EVENTQ_NODE *next;
00040 
00041 }  SF_EVENTQ_NODE;
00042 
00043 typedef struct s_SF_EVENTQ
00044 {
00045     /*
00046     **  Handles the actual ordering and memory
00047     **  of the event queue and it's nodes.
00048     */
00049     SF_EVENTQ_NODE *head;
00050     SF_EVENTQ_NODE *last;
00051 
00052     SF_EVENTQ_NODE *node_mem;
00053     char           *event_mem;
00054 
00055     /*
00056     **  The reserve event allows us to allocate one extra node
00057     **  and compare against the last event in the queue to determine
00058     **  if the incoming event is a higher priority than the last 
00059     **  event in the queue.
00060     */
00061     char           *reserve_event;
00062     
00063     /*
00064     **  Queue configuration
00065     */
00066     int max_nodes;
00067     int log_nodes;
00068     int event_size;
00069 
00070     /*
00071     **  This function orders the events as they
00072     **  arrive.
00073     */
00074     int (*sort)(void *event1, void *event2);
00075 
00076     /*
00077     **  This element tracks the current number of
00078     **  nodes in the event queue.
00079     */
00080     int cur_nodes;
00081     int cur_events;
00082 
00083 }  SF_EVENTQ;
00084 
00085 static SF_EVENTQ s_eventq;
00086 
00087 /*
00088 **  NAME
00089 **    sfeventq_init::
00090 */
00091 /**
00092 **  Initialize the event queue.  Provide the max number of nodes that this
00093 **  queue will support, the number of top nodes to log in the queue, the
00094 **  size of the event structure that the user will fill in, and the function
00095 **  to determine where to insert the incoming events in the queue.
00096 **
00097 **  @return integer
00098 **
00099 **  @retval -1 failure
00100 **  @retval  0 success
00101 */
00102 int sfeventq_init(int max_nodes, int log_nodes, int event_size, 
00103                   int (*sort)(void *, void *))
00104 {
00105     if(max_nodes <= 0 || log_nodes <= 0 || event_size <= 0 || !sort)
00106         return -1;
00107 
00108     /*
00109     **  Initialize the memory for the nodes that we are going to use.
00110     */
00111     s_eventq.node_mem  = 
00112         (SF_EVENTQ_NODE *)malloc(sizeof(SF_EVENTQ_NODE)*max_nodes);
00113     if(!s_eventq.node_mem)
00114         return -1;
00115 
00116     s_eventq.event_mem = (char *)malloc(event_size*(max_nodes+1));
00117     if(!s_eventq.event_mem)
00118         return -1;
00119 
00120     s_eventq.max_nodes  = max_nodes;
00121     s_eventq.log_nodes  = log_nodes;
00122     s_eventq.event_size = event_size;
00123     s_eventq.sort       = sort;
00124     s_eventq.cur_nodes  = 0;
00125     s_eventq.cur_events = 0;
00126     s_eventq.reserve_event = 
00127         (void *)(&s_eventq.event_mem[max_nodes*s_eventq.event_size]);
00128 
00129     return 0;
00130 }
00131 
00132 /*
00133 **  NAME
00134 **    sfeventq_event_alloc::
00135 */
00136 /**
00137 **  Allocate the memory for an event to add to the event queue.  This
00138 **  function is meant to be called first, the event structure filled in,
00139 **  and then added to the queue.  While you can allocate several times before
00140 **  adding to the queue, this is not recommended as you may get a NULL ptr
00141 **  if you allocate more than the max node number.
00142 **
00143 **  @return  void *
00144 **
00145 **  @retval  NULL unable to allocate memory.
00146 **  @retval !NULL ptr to memory.
00147 */
00148 void *sfeventq_event_alloc(void)
00149 {
00150     void *event;
00151 
00152     if(s_eventq.cur_events >= s_eventq.max_nodes)
00153     {
00154         if(!s_eventq.reserve_event)
00155             return NULL;
00156         
00157         event = (void *)s_eventq.reserve_event;
00158         s_eventq.reserve_event = NULL;
00159 
00160         return event;
00161     }
00162 
00163     event = 
00164         (void *)(&s_eventq.event_mem[s_eventq.cur_events*s_eventq.event_size]);
00165 
00166     s_eventq.cur_events++;
00167 
00168 
00169     return event;
00170 }
00171 
00172 /*
00173 **  NAME
00174 **    sfeventq_reset::
00175 */
00176 /**
00177 **  Resets the event queue.  We also set the reserve event back
00178 **  to the last event in the queue.
00179 **
00180 **  @return void
00181 */
00182 void sfeventq_reset(void)
00183 {
00184     s_eventq.head       = NULL;
00185     s_eventq.cur_nodes  = 0;
00186     s_eventq.cur_events = 0;
00187     s_eventq.reserve_event = 
00188         (void *)(&s_eventq.event_mem[s_eventq.max_nodes*s_eventq.event_size]);
00189 
00190     return;
00191 }
00192 
00193 /*
00194 **  NAME
00195 **    get_eventq_node::
00196 */
00197 /**
00198 **  This function returns a ptr to the node to use.  We allocate the last
00199 **  event node if we have exhausted the event queue.  Before we allocate
00200 **  the last node, we determine if the incoming event has a higher
00201 **  priority than the last node.  If it does, we allocate the node, otherwise
00202 **  we drop it because it is lower priority.
00203 **
00204 **  If the last node is allocated, we have to point the reserve_event to
00205 **  the allocated event memory, since the reserved_event memory was used
00206 **  for the incoming event.
00207 **
00208 **  @return SF_EVENTQ_NODE *
00209 **
00210 **  @retval NULL resource exhaustion and event is lower priority than last node
00211 **  @retval !NULL ptr to node memory.
00212 */
00213 static SF_EVENTQ_NODE *get_eventq_node(void *event)
00214 {
00215     SF_EVENTQ_NODE *node;
00216 
00217     if(s_eventq.cur_nodes >= s_eventq.max_nodes)
00218     {
00219         /*
00220         **  If this event does not have a higher priority than
00221         **  the last one, we don't won't it.
00222         */
00223         if(!s_eventq.sort(event, s_eventq.last->event))
00224         {
00225             s_eventq.reserve_event = event;
00226             return NULL;
00227         }
00228 
00229         node = s_eventq.last;
00230 
00231         /*
00232         **  Set up new reserve event.
00233         */
00234         s_eventq.reserve_event = node->event;
00235         node->event = event;
00236 
00237         if(s_eventq.last->prev)
00238         {
00239             s_eventq.last       = s_eventq.last->prev;
00240             s_eventq.last->next = NULL;
00241         }
00242 
00243         /*
00244         **  Grab the last node for processing.
00245         */
00246         return node;
00247     }
00248 
00249     /*
00250     **  We grab the next node from the node memory.
00251     */
00252     return &s_eventq.node_mem[s_eventq.cur_nodes++];
00253 }
00254 
00255 /*
00256 **  NAME
00257 **    sfeventq_add:
00258 */
00259 /**
00260 **  Add this event to the queue using the supplied ordering
00261 **  function.  If the queue is exhausted, then we compare the
00262 **  event to be added with the last event, and decide whether
00263 **  it is a higher priority than the last node.
00264 **
00265 **  @return integer
00266 **
00267 **  @retval -1 add event failed
00268 **  @retval  0 add event succeeded
00269 */
00270 int sfeventq_add(void *event)
00271 {
00272     SF_EVENTQ_NODE *node;
00273     SF_EVENTQ_NODE *tmp;
00274     
00275     if(!event)
00276         return -1;
00277 
00278     /*
00279     **  If get_eventq_node() returns NULL, this means that
00280     **  we have exhausted the eventq and the incoming event
00281     **  is lower in priority then the last ranked event.
00282     **  So we just drop it.
00283     */
00284     node = get_eventq_node(event);
00285     if(!node)
00286         return 0;
00287 
00288     node->event = event;
00289     node->next  = NULL;
00290     node->prev  = NULL;
00291 
00292     /*
00293     **  This is the first node
00294     */
00295     if(s_eventq.cur_nodes == 1)
00296     {
00297         s_eventq.head = s_eventq.last = node;
00298         return 0;
00299     }
00300 
00301     /*
00302     **  Now we search for where to insert this node.
00303     */
00304     for(tmp = s_eventq.head; tmp; tmp = tmp->next)
00305     {
00306         if(s_eventq.sort(event, tmp->event))
00307         {
00308             /*
00309             **  Put node here.
00310             */
00311             if(tmp->prev)
00312                 tmp->prev->next = node;
00313             else
00314                 s_eventq.head   = node;
00315                 
00316             node->prev = tmp->prev;
00317             node->next = tmp;
00318 
00319             tmp->prev  = node;
00320 
00321             return 0;
00322         }
00323     }
00324 
00325     /*
00326     **  This means we are the last node.
00327     */
00328     node->prev          = s_eventq.last;
00329 
00330     s_eventq.last->next = node;
00331     s_eventq.last       = node;
00332 
00333     return 0;
00334 }
00335 
00336 /*
00337 **  NAME
00338 **    sfeventq_action::
00339 */
00340 /** 
00341 **  Call the supplied user action function on the highest priority
00342 **  events.
00343 **
00344 **  @return integer
00345 **
00346 **  @retval -1 action function failed on an event
00347 **  @retval  0 no events logged
00348 **  @retval  1 events logged
00349 */
00350 int sfeventq_action(int (*action_func)(void *, void *), void *user)
00351 {
00352     SF_EVENTQ_NODE *node;
00353     int             logged = 0;
00354 
00355     if(!action_func)
00356         return -1;
00357 
00358     if(!(s_eventq.head))
00359         return 0;
00360     
00361     for(node = s_eventq.head; node; node = node->next)
00362     {
00363         if(logged >= s_eventq.log_nodes)
00364             return 1;
00365 
00366         if(action_func(node->event, user))
00367             return -1;
00368 
00369         logged++;
00370     }
00371 
00372     return 1;
00373 }
00374 
00375 //#define I_WANT_MY_MAIN
00376 #ifdef  I_WANT_MY_MAIN
00377 
00378 #include <stdio.h>
00379 #include <time.h>
00380 
00381 int mysort(void *event1, void *event2)
00382 {
00383     int *e1;
00384     int *e2;
00385 
00386     if(!event1 || !event2)
00387         return 0;
00388 
00389     e1 = (int *)event1;
00390     e2 = (int *)event2;
00391 
00392     if(*e1 < *e2)
00393         return 1;
00394 
00395     return 0;
00396 }
00397 
00398 int myaction(void *event, void *user)
00399 {
00400     int *e;
00401 
00402     if(!event)
00403         return 1;
00404 
00405     e = (int *)event;
00406 
00407     printf("-- EVENT: %d\n", *e);
00408 
00409     return 0;
00410 }
00411 
00412 int main(int argc, char **argv)
00413 {
00414     int  max_events;
00415     int  log_events;
00416     int  add_events;
00417     int *event;
00418     int  iCtr;
00419 
00420     if(argc < 4)
00421     {
00422         printf("-- Not enough args\n");
00423         return 1;
00424     }
00425 
00426     max_events = atoi(argv[1]);
00427     if(max_events <= 0)
00428     {
00429         printf("-- max_events invalid.\n");
00430         return 1;
00431     }
00432 
00433     log_events = atoi(argv[2]);
00434     if(log_events <= 0)
00435     {
00436         printf("-- log_events invalid.\n");
00437         return 1;
00438     }
00439 
00440     add_events = atoi(argv[3]);
00441     if(add_events <= 0)
00442     {
00443         printf("-- add_events invalid.\n");
00444         return 1;
00445     }
00446 
00447     if(max_events < log_events)
00448     {
00449         printf("-- log_events greater than max_events\n");
00450         return 1;
00451     }
00452 
00453     srandom(time(NULL));
00454 
00455     sfeventq_init(max_events, log_events, sizeof(int), mysort);
00456 
00457     do
00458     {
00459         printf("-- Event Queue Test --\n\n");
00460 
00461         for(iCtr = 0; iCtr < add_events; iCtr++)
00462         {
00463             event  = (int *)sfeventq_event_alloc();
00464             if(!event)
00465             {
00466                 printf("-- event allocation failed\n");
00467                 return 1;
00468             }
00469 
00470             *event = (int)(random()%3);
00471 
00472             sfeventq_add(event);
00473             printf("-- added %d\n", *event);
00474         }
00475 
00476         printf("\n-- Logging\n\n");
00477 
00478         if(sfeventq_action(myaction, NULL))
00479         {
00480             printf("-- There was a problem.\n");
00481             return 1;
00482         }
00483 
00484         sfeventq_reset();
00485 
00486     } while(getc(stdin) < 14);
00487     
00488     return 0;
00489 }
00490 #endif

Generated on Sun May 14 14:51:18 2006 by  doxygen 1.4.2