From: Stefan Metzmacher Date: Thu, 28 Jul 2011 08:45:22 +0000 (+0200) Subject: tevent: add tevent_queue_add_entry() and tevent_queue_add_optimize_empty() X-Git-Url: http://git.samba.org/?p=metze%2Fsamba%2Fwip.git;a=commitdiff_plain;h=88bc3f3d56bc8d60940dbc340630fbb08245cf84 tevent: add tevent_queue_add_entry() and tevent_queue_add_optimize_empty() 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 --- diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index c96ca354f55e..c5c7aa85bc20 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -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. * diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c index 7737b3e81479..4750675802f2 100644 --- a/lib/tevent/tevent_queue.c +++ b/lib/tevent/tevent_queue.c @@ -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) {