VCL IOEvent external API callback
[vpp.git] / src / vcl / vcl_event.c
index 64f55b9..dafa250 100644 (file)
@@ -59,10 +59,10 @@ vce_generate_event (vce_event_thread_t *evt, u32 ev_idx)
 }
 
 void
-vce_clear_event (vce_event_thread_t *evt, vce_event_t *ev)
+vce_clear_event (vce_event_thread_t *evt, u32 ev_idx)
 {
   clib_spinlock_lock (&(evt->events_lockp));
-  pool_put (evt->vce_events, ev);
+  pool_put_index (evt->vce_events, ev_idx);
   clib_spinlock_unlock (&(evt->events_lockp));
 }
 
@@ -70,11 +70,10 @@ vce_event_t *
 vce_get_event_from_index(vce_event_thread_t *evt, u32 ev_idx)
 {
   vce_event_t *ev = 0;
+  /* Assumes caller has obtained the spinlock (evt->events_lockp) */
 
-  clib_spinlock_lock (&(evt->events_lockp));
   if ( ! pool_is_free_index (evt->vce_events, ev_idx))
     ev = pool_elt_at_index (evt->vce_events, ev_idx);
-  clib_spinlock_unlock (&(evt->events_lockp));
 
   return ev;
 }
@@ -96,7 +95,7 @@ vce_get_event_handler (vce_event_thread_t *evt, vce_event_key_t *evk)
 
 vce_event_handler_reg_t *
 vce_register_handler (vce_event_thread_t *evt, vce_event_key_t *evk,
-                     vce_event_callback_t cb)
+                      vce_event_callback_t cb, void *cb_args)
 {
   vce_event_handler_reg_t *handler;
   vce_event_handler_reg_t *old_handler = 0;
@@ -115,26 +114,27 @@ vce_register_handler (vce_event_thread_t *evt, vce_event_key_t *evk,
       /* If we are just re-registering, ignore and move on
        * else store the old handler_fn for unregister to re-instate */
       if (old_handler->handler_fn == cb)
-       {
+        {
 
-         clib_spinlock_unlock (&evt->handlers_lockp);
+          clib_spinlock_unlock (&evt->handlers_lockp);
 
-         /* Signal event thread that a handler exists in case any
-          * recycled events requiring this handler are pending */
-         pthread_mutex_lock (&(evt->generator_lock));
-         pthread_cond_signal (&(evt->generator_cond));
-         pthread_mutex_unlock (&(evt->generator_lock));
-         return old_handler;
-       }
+          /* Signal event thread that a handler exists in case any
+           * recycled events requiring this handler are pending */
+          pthread_mutex_lock (&(evt->generator_lock));
+          pthread_cond_signal (&(evt->generator_cond));
+          pthread_mutex_unlock (&(evt->generator_lock));
+          return old_handler;
+        }
     }
 
   pool_get (evt->vce_event_handlers, handler);
   handler_index = (u32) (handler - evt->vce_event_handlers);
 
   handler->handler_fn = cb;
-  handler->replaced_handler_idx = (p) ? p[0] : ~0;
-  handler->ev_idx = ~0; //This will be set by the event thread if event happens
+  handler->replaced_handler_idx = (u32) ((p) ? p[0] : ~0);
+  handler->ev_idx = (u32) ~0; //This will be set by the event thread if event happens
   handler->evk = evk->as_u64;
+  handler->handler_fn_args = cb_args;
 
   hash_set (evt->handlers_index_by_event_key, evk->as_u64, handler_index);
 
@@ -209,55 +209,64 @@ vce_event_thread_fn (void *arg)
   u32 ev_idx;
   vce_event_handler_reg_t *handler;
   uword *p;
+  u32 recycle_count = 0;
 
-  evt->recycle_event = 1; // Used for recycling events with no handlers
-
-
-  do
+  pthread_mutex_lock (&(evt->generator_lock));
+  while (1)
     {
-      pthread_mutex_lock (&(evt->generator_lock));
-      while ( (clib_fifo_elts (evt->event_index_fifo) == 0) ||
-             evt->recycle_event)
-       {
-         evt->recycle_event = 0;
-         pthread_cond_wait (&(evt->generator_cond),
-                            &(evt->generator_lock));
-       }
+      uword fifo_depth = clib_fifo_elts (evt->event_index_fifo);
+      while ((fifo_depth == 0) || (recycle_count == fifo_depth))
+        {
+          recycle_count = 0;
+          pthread_cond_wait (&(evt->generator_cond), &(evt->generator_lock));
+          fifo_depth = clib_fifo_elts (evt->event_index_fifo);
+        }
 
       /* Remove event */
       clib_spinlock_lock (&(evt->events_lockp));
-
       clib_fifo_sub1 (evt->event_index_fifo, ev_idx);
-      ev = pool_elt_at_index (evt->vce_events, ev_idx);
-
-      clib_spinlock_unlock (&(evt->events_lockp));
-
+      ev = vce_get_event_from_index (evt, ev_idx);
       ASSERT(ev);
-
+      if (recycle_count && ev->recycle)
+        {
+          clib_fifo_add1 (evt->event_index_fifo, ev_idx);
+          clib_spinlock_unlock (&(evt->events_lockp));
+          continue;
+        }
       clib_spinlock_lock (&evt->handlers_lockp);
 
       p = hash_get (evt->handlers_index_by_event_key, ev->evk.as_u64);
       if (!p)
-       {
-         /* If an event falls in the woods, and there is no handler to hear it,
-          * does it make any sound?
-          * I don't know either, so lets try recycling the event */
-         clib_fifo_add1 (evt->event_index_fifo, ev_idx);
-         evt->recycle_event = 1;
-         clib_spinlock_unlock (&evt->handlers_lockp);
-         goto unlock;
-       }
-      handler = pool_elt_at_index (evt->vce_event_handlers, p[0]);
-      handler->ev_idx = ev_idx;
-
-      clib_spinlock_unlock (&evt->handlers_lockp);
-
-      (handler->handler_fn)(handler);
+        {
+          /* If an event falls in the woods, and there is no handler to hear it,
+           * does it make any sound?
+           * I don't know either, so lets biff the event */
+          pool_put(evt->vce_events, ev);
+          clib_spinlock_unlock (&(evt->events_lockp));
+          clib_spinlock_unlock (&evt->handlers_lockp);
+          pthread_mutex_unlock (&(evt->generator_lock));
+        }
+      else
+        {
+          u32 evt_recycle = ev->recycle;
+          handler = pool_elt_at_index (evt->vce_event_handlers, p[0]);
+          handler->ev_idx = ev_idx;
+          ev->recycle = 0;
+
+          clib_spinlock_unlock (&(evt->events_lockp));
+          clib_spinlock_unlock (&evt->handlers_lockp);
+          pthread_mutex_unlock (&(evt->generator_lock));
+
+          (handler->handler_fn)(handler);
+
+          clib_spinlock_lock (&(evt->events_lockp));
+          ev = vce_get_event_from_index (evt, ev_idx);
+          recycle_count += (!evt_recycle && ev && ev->recycle) ? 1 : 0;
+          clib_spinlock_unlock(&(evt->events_lockp));
+        }
 
-    unlock:
-      pthread_mutex_unlock (&(evt->generator_lock));
+      pthread_mutex_lock (&(evt->generator_lock));
     }
-  while (1);
   return NULL;
 }
 
@@ -274,5 +283,6 @@ vce_start_event_thread (vce_event_thread_t *evt, u8 max_events)
   clib_spinlock_init (&(evt->handlers_lockp));
 
   return pthread_create (&(evt->thread), NULL /* attr */ ,
-                        vce_event_thread_fn, evt);
-}
\ No newline at end of file
+                         vce_event_thread_fn, evt);
+}
+