]> granicus.if.org Git - libevent/commitdiff
Add function to check referential integrity of an event_base
authorNick Mathewson <nickm@torproject.org>
Sat, 21 Jan 2012 17:55:15 +0000 (12:55 -0500)
committerNick Mathewson <nickm@torproject.org>
Sat, 21 Jan 2012 17:55:15 +0000 (12:55 -0500)
event-internal.h
event.c
evmap-internal.h
evmap.c
test/regress.c

index a361cf3b6eb4d95db36c26286e3edc3057724d86..43beaf3be6f63b02ab15c81681a7f980a8bf41b2 100644 (file)
@@ -347,6 +347,14 @@ void event_active_nolock(struct event *ev, int res, short count);
 void event_base_add_virtual(struct event_base *base);
 void event_base_del_virtual(struct event_base *base);
 
+/** For debugging: unless assertions are disabled, verify the referential
+    integrity of the internal data structures of 'base'.  This operation can
+    be expensive.
+
+    Returns on success; aborts on failure.
+*/
+void event_base_assert_ok(struct event_base *base);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/event.c b/event.c
index a17635669878bf7c6fb30249c26d581c1fe56d0f..14322e50deeb8072bc6f6f3c2a13f49607f0ee2f 100644 (file)
--- a/event.c
+++ b/event.c
@@ -2849,3 +2849,38 @@ event_global_setup_locks_(const int enable_locks)
        return 0;
 }
 #endif
+
+void
+event_base_assert_ok(struct event_base *base)
+{
+       int i;
+       EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+       evmap_check_integrity(base);
+
+       /* Check the heap property */
+       for (i = 1; i < (int)base->timeheap.n; ++i) {
+               int parent = (i - 1) / 2;
+               struct event *ev, *p_ev;
+               ev = base->timeheap.p[i];
+               p_ev = base->timeheap.p[parent];
+               EVUTIL_ASSERT(ev->ev_flags & EV_TIMEOUT);
+               EVUTIL_ASSERT(evutil_timercmp(&p_ev->ev_timeout, &ev->ev_timeout, <=));
+               EVUTIL_ASSERT(ev->ev_timeout_pos.min_heap_idx == i);
+       }
+
+       /* Check that the common timeouts are fine */
+       for (i = 0; i < base->n_common_timeouts; ++i) {
+               struct common_timeout_list *ctl = base->common_timeout_queues[i];
+               struct event *last=NULL, *ev;
+               TAILQ_FOREACH(ev, &ctl->events, ev_timeout_pos.ev_next_with_common_timeout) {
+                       if (last)
+                               EVUTIL_ASSERT(evutil_timercmp(&last->ev_timeout, &ev->ev_timeout, <=));
+                       EVUTIL_ASSERT(ev->ev_flags & EV_TIMEOUT);
+                       EVUTIL_ASSERT(is_common_timeout(&ev->ev_timeout,base));
+                       EVUTIL_ASSERT(COMMON_TIMEOUT_IDX(&ev->ev_timeout) == i);
+                       last = ev;
+               }
+       }
+
+       EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
index fde661d13623ca102ae9d4ca07e6255c4ca88d45..8bf655fd25c13c3b92f0255b2b5d05da231e3b2f 100644 (file)
@@ -87,4 +87,6 @@ void evmap_signal_active(struct event_base *base, evutil_socket_t signum, int nc
 
 void *evmap_io_get_fdinfo(struct event_io_map *ctx, evutil_socket_t fd);
 
+void evmap_check_integrity(struct event_base *base);
+
 #endif /* _EVMAP_H_ */
diff --git a/evmap.c b/evmap.c
index 36103a0bb4615c65bfe444dfbb6751c6b69e1c2c..829a73e2a4cff0d28c340b37870fef0f02baa007 100644 (file)
--- a/evmap.c
+++ b/evmap.c
@@ -725,3 +725,66 @@ event_changelist_del(struct event_base *base, evutil_socket_t fd, short old, sho
        return (0);
 }
 
+void
+evmap_check_integrity(struct event_base *base)
+{
+#define EVLIST_X_SIGFOUND 0x1000
+#define EVLIST_X_IOFOUND 0x2000
+
+       int i;
+       struct event *ev;
+       struct event_io_map *io = &base->io;
+       struct event_signal_map *sigmap = &base->sigmap;
+       int nsignals, ntimers, nio;
+       nsignals = ntimers = nio = 0;
+
+       TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+               EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
+               EVUTIL_ASSERT(ev->ev_flags & EVLIST_INIT);
+               ev->ev_flags &= ~(EVLIST_X_SIGFOUND|EVLIST_X_IOFOUND);
+       }
+
+
+       for (i = 0; i < io->nentries; ++i) {
+               struct evmap_io *ctx = io->entries[i];
+               if (!ctx)
+                       continue;
+
+               TAILQ_FOREACH(ev, &ctx->events, ev_io_next) {
+                       EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_IOFOUND));
+                       EVUTIL_ASSERT(ev->ev_fd == i);
+                       ev->ev_flags |= EVLIST_X_IOFOUND;
+                       nio++;
+               }
+       }
+
+       for (i = 0; i < sigmap->nentries; ++i) {
+               struct evmap_signal *ctx = sigmap->entries[i];
+               if (!ctx)
+                       continue;
+
+               TAILQ_FOREACH(ev, &ctx->events, ev_signal_next) {
+                       EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_SIGFOUND));
+                       EVUTIL_ASSERT(ev->ev_fd == i);
+                       ev->ev_flags |= EVLIST_X_SIGFOUND;
+                       nsignals++;
+               }
+       }
+
+       TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+               if (ev->ev_events & (EV_READ|EV_WRITE)) {
+                       EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_IOFOUND);
+                       --nio;
+               }
+               if (ev->ev_events & EV_SIGNAL) {
+                       EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_SIGFOUND);
+                       --nsignals;
+               }
+       }
+
+       EVUTIL_ASSERT(nio == 0);
+       EVUTIL_ASSERT(nsignals == 0);
+       /* There is no "EVUTIL_ASSERT(ntimers == 0)": eventqueue is only for
+        * pending signals and io events.
+        */
+}
index 683303db104c04b10f29f6a346a5020929bedfe1..6ad332e1be53ae80fdee5d894655671ce4af4304 100644 (file)
@@ -677,9 +677,11 @@ test_persistent_active_timeout(void *ptr)
        tv_exit.tv_usec = 600 * 1000;
        event_base_loopexit(base, &tv_exit);
 
+       event_base_assert_ok(base);
        evutil_gettimeofday(&start, NULL);
 
        event_base_dispatch(base);
+       event_base_assert_ok(base);
 
        tt_int_op(res.n, ==, 3);
        tt_int_op(res.events[0], ==, EV_READ);
@@ -748,9 +750,11 @@ test_common_timeout(void *ptr)
                }
        }
 
+       event_base_assert_ok(base);
        event_base_dispatch(base);
 
        evutil_gettimeofday(&now, NULL);
+       event_base_assert_ok(base);
 
        for (i=0; i<10; ++i) {
                struct timeval tmp;
@@ -824,12 +828,19 @@ test_fork(void)
        evsignal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld);
        evsignal_add(&sig_ev, NULL);
 
+       event_base_assert_ok(current_base);
+       TT_BLATHER(("Before fork"));
        if ((pid = fork()) == 0) {
                /* in the child */
+               TT_BLATHER(("In child, before reinit"));
+               event_base_assert_ok(current_base);
                if (event_reinit(current_base) == -1) {
                        fprintf(stdout, "FAILED (reinit)\n");
                        exit(1);
                }
+               TT_BLATHER(("After reinit"));
+               event_base_assert_ok(current_base);
+               TT_BLATHER(("After assert-ok"));
 
                evsignal_del(&sig_ev);
 
@@ -852,10 +863,12 @@ test_fork(void)
                tt_fail_perror("write");
        }
 
+       TT_BLATHER(("Before waitpid"));
        if (waitpid(pid, &status, 0) == -1) {
                fprintf(stdout, "FAILED (fork)\n");
                exit(1);
        }
+       TT_BLATHER(("After waitpid"));
 
        if (WEXITSTATUS(status) != 76) {
                fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status));