tevent: add a test that frees wrapper_ev with pending events
authorRalph Boehme <slow@samba.org>
Sat, 16 Jun 2018 14:55:44 +0000 (16:55 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 11 Jul 2018 21:04:22 +0000 (23:04 +0200)
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/tevent/testsuite.c

index 946dea53532ba769b8fda99de19dcfdf39d67ce9..b0f58efd0938bb33512860db0efa224887bf2111 100644 (file)
@@ -1048,6 +1048,159 @@ pop_use:
        goto done;
 }
 
+static void test_free_wrapper_signal_handler(struct tevent_context *ev,
+                                       struct tevent_signal *se,
+                                       int signum,
+                                       int count,
+                                       void *siginfo,
+                                       void *private_data)
+{
+       struct torture_context *tctx =
+               talloc_get_type_abort(private_data,
+               struct torture_context);
+
+       torture_comment(tctx, "signal handler\n");
+
+       talloc_free(se);
+
+       /*
+        * signal handlers have highest priority in tevent, so this signal
+        * handler will always be started before the other handlers
+        * below. Freeing the (wrapper) event context here tests that the
+        * wrapper implementation correclty handles the wrapper ev going away
+        * with pending events.
+        */
+       talloc_free(ev);
+       return;
+}
+
+static void test_free_wrapper_fd_handler(struct tevent_context *ev,
+                                        struct tevent_fd *fde,
+                                        unsigned short fd_flags,
+                                        void *private_data)
+{
+       /*
+        * This should never be called as
+        * test_free_wrapper_signal_handler()
+        * already destroyed the wrapper tevent_context.
+        */
+       abort();
+}
+
+static void test_free_wrapper_immediate_handler(struct tevent_context *ev,
+                                          struct tevent_immediate *im,
+                                          void *private_data)
+{
+       /*
+        * This should never be called as
+        * test_free_wrapper_signal_handler()
+        * already destroyed the wrapper tevent_context.
+        */
+       abort();
+}
+
+static void test_free_wrapper_timer_handler(struct tevent_context *ev,
+                                      struct tevent_timer *te,
+                                      struct timeval tv,
+                                      void *private_data)
+{
+       /*
+        * This should never be called as
+        * test_free_wrapper_signal_handler()
+        * already destroyed the wrapper tevent_context.
+        */
+       abort();
+}
+
+static bool test_free_wrapper(struct torture_context *tctx,
+                             const void *test_data)
+{
+       struct test_wrapper_state *state = NULL;
+       int sock[2] = { -1, -1};
+       uint8_t c = 0;
+       const char *backend = (const char *)test_data;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev = NULL;
+       struct tevent_context *wrap_ev = NULL;
+       struct tevent_fd *fde = NULL;
+       struct tevent_timer *te = NULL;
+       struct tevent_signal *se = NULL;
+       struct tevent_immediate *im = NULL;
+       int ret;
+       bool ok = false;
+
+       ev = tevent_context_init_byname(frame, backend);
+       if (ev == NULL) {
+               torture_skip(tctx, talloc_asprintf(tctx,
+                            "event backend '%s' not supported\n",
+                            backend));
+               return true;
+       }
+
+       tevent_set_debug_stderr(ev);
+       torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+       wrap_ev = tevent_context_wrapper_create(
+               ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
+       torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+                                    "tevent_context_wrapper_create failed\n");
+       *state = (struct test_wrapper_state) {
+               .tctx = tctx,
+       };
+
+       ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+       torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+       fde = tevent_add_fd(wrap_ev, frame,
+                           sock[1],
+                           TEVENT_FD_READ,
+                           test_free_wrapper_fd_handler,
+                           NULL);
+       torture_assert_not_null_goto(tctx, fde, ok, done,
+                                    "tevent_add_fd failed\n");
+
+       te = tevent_add_timer(wrap_ev, frame,
+                             timeval_current_ofs(0, 0),
+                             test_free_wrapper_timer_handler, NULL);
+       torture_assert_not_null_goto(tctx, te, ok, done,
+                                    "tevent_add_timer failed\n");
+
+       im = tevent_create_immediate(frame);
+       torture_assert_not_null_goto(tctx, im, ok, done,
+                                    "tevent_create_immediate failed\n");
+
+       se = tevent_add_signal(wrap_ev, frame,
+                              SIGUSR1,
+                              0,
+                              test_free_wrapper_signal_handler,
+                              tctx);
+       torture_assert_not_null_goto(tctx, se, ok, done,
+                                    "tevent_add_signal failed\n");
+
+       do_write(sock[0], &c, 1);
+       kill(getpid(), SIGUSR1);
+       tevent_schedule_immediate(im,
+                                 wrap_ev,
+                                 test_free_wrapper_immediate_handler,
+                                 NULL);
+
+       ret = tevent_loop_wait(ev);
+       torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
+
+       ok = true;
+
+done:
+       TALLOC_FREE(frame);
+
+       if (sock[0] != -1) {
+               close(sock[0]);
+       }
+       if (sock[1] != -1) {
+               close(sock[1]);
+       }
+       return ok;
+}
+
 #ifdef HAVE_PTHREAD
 
 static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1636,6 +1789,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
                                               "wrapper",
                                               test_wrapper,
                                               (const void *)list[i]);
+               torture_suite_add_simple_tcase_const(backend_suite,
+                                              "free_wrapper",
+                                              test_free_wrapper,
+                                              (const void *)list[i]);
 
                torture_suite_add_suite(suite, backend_suite);
        }