tevent: split out tevent_common_invoke_immediate_handler()
authorStefan Metzmacher <metze@samba.org>
Tue, 22 Jul 2014 11:08:42 +0000 (13:08 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 17 May 2018 07:51:48 +0000 (09:51 +0200)
We'll remove _PRIVATE_ with the next release.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
lib/tevent/tevent_immediate.c
lib/tevent/tevent_internal.h
lib/tevent/tevent_threads.c

index c640a565b08250b0269dddfb9c19a7e136c500ea..6d4a97f87746289da76e2841fa15b00a7712512f 100644 (file)
 static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 {
        const char *create_location = im->create_location;
+       bool busy = im->busy;
+
+       if (im->destroyed) {
+               tevent_abort(im->event_ctx, "tevent_immediate use after free");
+               return;
+       }
 
        if (!im->event_ctx) {
                return;
@@ -51,9 +57,12 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 
        *im = (struct tevent_immediate) {
                .create_location        = create_location,
+               .busy                   = busy,
        };
 
-       talloc_set_destructor(im, NULL);
+       if (!busy) {
+               talloc_set_destructor(im, NULL);
+       }
 }
 
 /*
@@ -61,7 +70,21 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
 */
 static int tevent_common_immediate_destructor(struct tevent_immediate *im)
 {
+       if (im->destroyed) {
+               tevent_common_check_double_free(im,
+                                               "tevent_immediate double free");
+               goto done;
+       }
+
        tevent_common_immediate_cancel(im);
+
+       im->destroyed = true;
+
+done:
+       if (im->busy) {
+               return -1;
+       }
+
        return 0;
 }
 
@@ -76,6 +99,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
                                      const char *location)
 {
        const char *create_location = im->create_location;
+       bool busy = im->busy;
 
        tevent_common_immediate_cancel(im);
 
@@ -90,6 +114,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
                .handler_name           = handler_name,
                .create_location        = create_location,
                .schedule_location      = location,
+               .busy                   = busy,
        };
 
        DLIST_ADD_END(ev->immediate_events, im);
@@ -100,18 +125,15 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
                     handler_name, im);
 }
 
-/*
-  trigger the first immediate event and return true
-  if no event was triggered return false
-*/
-bool tevent_common_loop_immediate(struct tevent_context *ev)
+_PRIVATE_
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+                                          bool *removed)
 {
-       struct tevent_immediate *im = ev->immediate_events;
-       tevent_immediate_handler_t handler;
-       void *private_data;
+       struct tevent_context *ev = im->event_ctx;
+       struct tevent_immediate cur = *im;
 
-       if (!im) {
-               return false;
+       if (removed != NULL) {
+               *removed = false;
        }
 
        tevent_debug(ev, TEVENT_DEBUG_TRACE,
@@ -122,21 +144,43 @@ bool tevent_common_loop_immediate(struct tevent_context *ev)
         * remember the handler and then clear the event
         * the handler might reschedule the event
         */
-       handler = im->handler;
-       private_data = im->private_data;
 
-       DLIST_REMOVE(im->event_ctx->immediate_events, im);
-       im->event_ctx           = NULL;
-       im->handler             = NULL;
-       im->private_data        = NULL;
-       im->handler_name        = NULL;
-       im->schedule_location   = NULL;
-       im->cancel_fn           = NULL;
-       im->additional_data     = NULL;
+       im->busy = true;
+       im->handler_name = NULL;
+       tevent_common_immediate_cancel(im);
+       cur.handler(ev, im, cur.private_data);
+       im->busy = false;
+       if (im->handler == NULL) {
+               talloc_set_destructor(im, NULL);
+       }
+       if (im->destroyed) {
+               talloc_set_destructor(im, NULL);
+               TALLOC_FREE(im);
+               if (removed != NULL) {
+                       *removed = true;
+               }
+       }
+
+       return 0;
+}
+
+/*
+  trigger the first immediate event and return true
+  if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+       struct tevent_immediate *im = ev->immediate_events;
+       int ret;
 
-       talloc_set_destructor(im, NULL);
+       if (!im) {
+               return false;
+       }
 
-       handler(ev, im, private_data);
+       ret = tevent_common_invoke_immediate_handler(im, NULL);
+       if (ret != 0) {
+               tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
+       }
 
        return true;
 }
index bd1c2a0370a3b118e0a30be9605357efd8709702..a590a5bb3b756aaa88e6f2a93dccf71501b9fc41 100644 (file)
@@ -203,6 +203,8 @@ struct tevent_timer {
 struct tevent_immediate {
        struct tevent_immediate *prev, *next;
        struct tevent_context *event_ctx;
+       bool busy;
+       bool destroyed;
        tevent_immediate_handler_t handler;
        /* this is private for the specific handler */
        void *private_data;
@@ -367,6 +369,8 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
                                      void *private_data,
                                      const char *handler_name,
                                      const char *location);
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+                                          bool *removed);
 bool tevent_common_loop_immediate(struct tevent_context *ev);
 void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
 
index f8efb57a68d99d9131ac1a520db9b210f1a3fba9..f50f42146089fefb3c0b458893419a9956770dfd 100644 (file)
@@ -482,6 +482,12 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
        if ((im->event_ctx != NULL) || (handler == NULL)) {
                abort();
        }
+       if (im->destroyed) {
+               abort();
+       }
+       if (im->busy) {
+               abort();
+       }
 
        *im = (struct tevent_immediate) {
                .event_ctx              = ev,