tevent: add tevent_queue_add_entry() and tevent_queue_add_optimize_empty()
authorStefan Metzmacher <metze@samba.org>
Thu, 28 Jul 2011 08:45:22 +0000 (10:45 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 9 Aug 2011 14:17:10 +0000 (16:17 +0200)
This adds more flexible handling for the add operation:

- It allows the caller to remove a tevent_req from the queue
  by calling talloc_free() on the returned tevent_queue_entry.
- It allows the caller to optimize for the empty queue case,
  where it the caller wants to avoid the delay caused by
  the immediate event.

metze

lib/tevent/tevent.h
lib/tevent/tevent_queue.c

index c96ca354f55e0366bd8118db223b7243bea32c8b..c5c7aa85bc20f9a5d2884ed509f6319cf9557231 100644 (file)
@@ -1347,6 +1347,7 @@ struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs);
  */
 
 struct tevent_queue;
+struct tevent_queue_entry;
 
 #ifdef DOXYGEN
 /**
@@ -1381,6 +1382,8 @@ struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
  *                          tevent_queue_add().
  *
  * @see tevent_queue_add()
+ * @see tevent_queue_add_entry()
+ * @see tevent_queue_add_optimize_empty()
  */
 typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
                                          void *private_data);
@@ -1410,6 +1413,79 @@ bool tevent_queue_add(struct tevent_queue *queue,
                      tevent_queue_trigger_fn_t trigger,
                      void *private_data);
 
+/**
+ * @brief Add a tevent request to the queue.
+ *
+ * The request can be removed from the queue by calling talloc_free()
+ * (or a similar function) on the returned queue entry. This
+ * is the only difference to tevent_queue_add().
+ *
+ * @param[in]  queue    The queue to add the request.
+ *
+ * @param[in]  ev       The event handle to use for the request.
+ *
+ * @param[in]  req      The tevent request to add to the queue.
+ *
+ * @param[in]  trigger  The function triggered by the queue when the request
+ *                      is called. Since tevent 0.9.14 it's possible to
+ *                      pass NULL, in order to just add a "blocker" to the
+ *                      queue.
+ *
+ * @param[in]  private_data The private data passed to the trigger function.
+ *
+ * @return              a pointer to the tevent_queue_entry if the request
+ *                      has been successfully added, NULL otherwise.
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_optimize_empty()
+ */
+struct tevent_queue_entry *tevent_queue_add_entry(
+                                       struct tevent_queue *queue,
+                                       struct tevent_context *ev,
+                                       struct tevent_req *req,
+                                       tevent_queue_trigger_fn_t trigger,
+                                       void *private_data);
+
+/**
+ * @brief Add a tevent request to the queue using a possible optimization.
+ *
+ * This tries to optimize for the empty queue case and may calls
+ * the trigger function directly. This is the only difference compared
+ * to tevent_queue_add_entry().
+ *
+ * The caller needs to be prepared that the trigger function has
+ * already called tevent_req_notify_callback(), tevent_req_error(),
+ * tevent_req_done() or a similar function.
+ *
+ * The request can be removed from the queue by calling talloc_free()
+ * (or a similar function) on the returned queue entry.
+ *
+ * @param[in]  queue    The queue to add the request.
+ *
+ * @param[in]  ev       The event handle to use for the request.
+ *
+ * @param[in]  req      The tevent request to add to the queue.
+ *
+ * @param[in]  trigger  The function triggered by the queue when the request
+ *                      is called. Since tevent 0.9.14 it's possible to
+ *                      pass NULL, in order to just add a "blocker" to the
+ *                      queue.
+ *
+ * @param[in]  private_data The private data passed to the trigger function.
+ *
+ * @return              a pointer to the tevent_queue_entry if the request
+ *                      has been successfully added, NULL otherwise.
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_entry()
+ */
+struct tevent_queue_entry *tevent_queue_add_optimize_empty(
+                                       struct tevent_queue *queue,
+                                       struct tevent_context *ev,
+                                       struct tevent_req *req,
+                                       tevent_queue_trigger_fn_t trigger,
+                                       void *private_data);
+
 /**
  * @brief Start a tevent queue.
  *
index 7737b3e814799dea0cc6e6da005978d3b4d19d17..4750675802f26f6548e9c76e9b1c13933078a220 100644 (file)
@@ -149,7 +149,8 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
                                        struct tevent_context *ev,
                                        struct tevent_req *req,
                                        tevent_queue_trigger_fn_t trigger,
-                                       void *private_data)
+                                       void *private_data,
+                                       bool allow_direct)
 {
        struct tevent_queue_entry *e;
 
@@ -171,6 +172,24 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
                e->triggered = true;
        }
 
+       if (queue->length > 0) {
+               /*
+                * if there are already entries in the
+                * queue do not optimize.
+                */
+               allow_direct = false;
+       }
+
+       if (req->async.fn != NULL) {
+               /*
+                * If the callers wants to optimize for the
+                * empty queue case, call the trigger only
+                * if there is no callback defined for the
+                * request yet.
+                */
+               allow_direct = false;
+       }
+
        DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *);
        queue->length++;
        talloc_set_destructor(e, tevent_queue_entry_destructor);
@@ -183,6 +202,18 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
                return e;
        }
 
+       /*
+        * If allowed we directly call the trigger
+        * avoiding possible delays caused by
+        * an immediate event.
+        */
+       if (allow_direct) {
+               queue->list->triggered = true;
+               queue->list->trigger(queue->list->req,
+                                    queue->list->private_data);
+               return e;
+       }
+
        tevent_schedule_immediate(queue->immediate,
                                  queue->list->ev,
                                  tevent_queue_immediate_trigger,
@@ -200,7 +231,7 @@ bool tevent_queue_add(struct tevent_queue *queue,
        struct tevent_queue_entry *e;
 
        e = tevent_queue_add_internal(queue, ev, req,
-                                     trigger, private_data);
+                                     trigger, private_data, false);
        if (e == NULL) {
                return false;
        }
@@ -208,6 +239,28 @@ bool tevent_queue_add(struct tevent_queue *queue,
        return true;
 }
 
+struct tevent_queue_entry *tevent_queue_add_entry(
+                                       struct tevent_queue *queue,
+                                       struct tevent_context *ev,
+                                       struct tevent_req *req,
+                                       tevent_queue_trigger_fn_t trigger,
+                                       void *private_data)
+{
+       return tevent_queue_add_internal(queue, ev, req,
+                                        trigger, private_data, false);
+}
+
+struct tevent_queue_entry *tevent_queue_add_optimize_empty(
+                                       struct tevent_queue *queue,
+                                       struct tevent_context *ev,
+                                       struct tevent_req *req,
+                                       tevent_queue_trigger_fn_t trigger,
+                                       void *private_data)
+{
+       return tevent_queue_add_internal(queue, ev, req,
+                                        trigger, private_data, true);
+}
+
 void tevent_queue_start(struct tevent_queue *queue)
 {
        if (queue->running) {