summaryrefslogtreecommitdiffstats
path: root/source3/lib/events.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-02-05 19:14:45 -0800
committerJeremy Allison <jra@samba.org>2010-02-05 22:17:54 -0800
commit5dbf175c75bd6139f3238f36665000641f7f7f79 (patch)
tree8d2d22ebed4f78f75bce96491efc8b1edf8ae3ab /source3/lib/events.c
parentdd498d2eecf124a03b6117ddab892a1112f9e9db (diff)
downloadsamba-5dbf175c75bd6139f3238f36665000641f7f7f79.tar.gz
samba-5dbf175c75bd6139f3238f36665000641f7f7f79.tar.xz
samba-5dbf175c75bd6139f3238f36665000641f7f7f79.zip
s3-events: make the old timed events compatible with tevent
tevent ensures that a timed event is only called once. The old events code relied on the called handler removing the event itself. If the handler removed the event after calling a function which invoked the event loop then the timed event could loop forever. This change makes the two timed event systems more compatible, by allowing the handler to free the te if it wants to, but ensuring it is off the linked list of events before the handler is called, and ensuring it is freed even if the handler doesn't free it.
Diffstat (limited to 'source3/lib/events.c')
-rw-r--r--source3/lib/events.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/source3/lib/events.c b/source3/lib/events.c
index 7a06ad08299..75aa2507266 100644
--- a/source3/lib/events.c
+++ b/source3/lib/events.c
@@ -105,12 +105,29 @@ bool run_events(struct tevent_context *ev,
if ((ev->timer_events != NULL)
&& (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
+ /* this older events system did not auto-free timed
+ events on running them, and had a race condition
+ where the event could be called twice if the
+ talloc_free of the te happened after the callback
+ made a call which invoked the event loop. To avoid
+ this while still allowing old code which frees the
+ te, we need to create a temporary context which
+ will be used to ensure the te is freed. We also
+ remove the te from the timed event list before we
+ call the handler, to ensure we can't loop */
+
+ struct tevent_timer *te = ev->timer_events;
+ TALLOC_CTX *tmp_ctx = talloc_new(ev);
DEBUG(10, ("Running timed event \"%s\" %p\n",
ev->timer_events->handler_name, ev->timer_events));
- ev->timer_events->handler(ev, ev->timer_events, now,
- ev->timer_events->private_data);
+ DLIST_REMOVE(ev->timer_events, te);
+ talloc_steal(tmp_ctx, te);
+
+ te->handler(ev, te, now, te->private_data);
+
+ talloc_free(tmp_ctx);
return true;
}