summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-11-17 22:21:42 +0000
committerNick Mathewson <nickm@torproject.org>2007-11-17 22:21:42 +0000
commit1c23e219527b8342639f49e0884e209f7232502a (patch)
tree2092ac612d8e261b26976bf03b832ba7bf0bc289
parent70248ca8ad0dd426798d1e11328970b1f537e505 (diff)
downloadlibevent-1c23e219527b8342639f49e0884e209f7232502a.tar.gz
r14931@tombo: nickm | 2007-11-17 17:21:09 -0500
Patch from Scott Lamb: Implement event_{base_}loopbreak. Includes documentation and tests. From sf.net Feature Request 1826546. svn:r535
-rw-r--r--ChangeLog1
-rw-r--r--event-internal.h1
-rw-r--r--event.317
-rw-r--r--event.c26
-rw-r--r--event.h29
-rw-r--r--test/regress.c37
6 files changed, 109 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 7429c476..086a1df4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Changes in current version:
o provide event_base_new() that does not set the current_base global
o bufferevent_write now uses a const source argument; report from Charles Kerr
o improve documentation on event_base_loopexit; patch from Scott Lamb
+ o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
Changes in 1.4.0:
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
diff --git a/event-internal.h b/event-internal.h
index de9c7879..56ef877b 100644
--- a/event-internal.h
+++ b/event-internal.h
@@ -42,6 +42,7 @@ struct event_base {
int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */
+ int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues;
diff --git a/event.3 b/event.3
index d5717f22..5b33ec64 100644
--- a/event.3
+++ b/event.3
@@ -34,10 +34,12 @@
.Nm event_dispatch ,
.Nm event_loop ,
.Nm event_loopexit ,
+.Nm event_loopbreak ,
.Nm event_set ,
.Nm event_base_dispatch ,
.Nm event_base_loop ,
.Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
.Nm event_base_set ,
.Nm event_base_free ,
.Nm event_add ,
@@ -93,6 +95,8 @@
.Fn "event_loop" "int flags"
.Ft int
.Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
.Ft void
.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
.Ft int
@@ -102,6 +106,8 @@
.Ft int
.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
.Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
.Fn "event_base_set" "struct event_base *base" "struct event *"
.Ft void
.Fn "event_base_free" "struct event_base *base"
@@ -419,7 +425,16 @@ given timer expires will complete normally (handling all queued events) then
exit without blocking for events again. Subsequent invocations of
.Fn event_loop
will proceed normally.
-The parameter indicates the time after which the loop should terminate.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
.Pp
It is the responsibility of the caller to provide these functions with
pre-allocated event structures.
diff --git a/event.c b/event.c
index 3e6295cb..d0e8d670 100644
--- a/event.c
+++ b/event.c
@@ -330,7 +330,7 @@ event_process_active(struct event_base *base)
ncalls--;
ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
- if (event_gotsig)
+ if (event_gotsig || base->event_break)
return;
}
}
@@ -375,6 +375,25 @@ event_base_loopexit(struct event_base *event_base, struct timeval *tv)
}
/* not thread safe */
+int
+event_loopbreak(void)
+{
+ return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+ if (event_base == NULL)
+ return (-1);
+
+ event_base->event_break = 1;
+ return (0);
+}
+
+
+
+/* not thread safe */
int
event_loop(int flags)
@@ -405,6 +424,11 @@ event_base_loop(struct event_base *base, int flags)
break;
}
+ if (base->event_break) {
+ base->event_break = 0;
+ break;
+ }
+
/* You cannot use this interface for multi-threaded apps */
while (event_gotsig) {
event_gotsig = 0;
diff --git a/event.h b/event.h
index 4685e936..e2673086 100644
--- a/event.h
+++ b/event.h
@@ -407,6 +407,35 @@ int event_loopexit(struct timeval *);
*/
int event_base_loopexit(struct event_base *, struct timeval *);
+/**
+ Abort the active event_loop() immediately.
+
+ event_loop() will abort the loop after the next event is completed;
+ event_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+ Abort the active event_base_loop() immediately.
+
+ event_base_loop() will abort the loop after the next event is completed;
+ event_base_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
/**
Add a timer event.
diff --git a/test/regress.c b/test/regress.c
index a153da48..274f62cb 100644
--- a/test/regress.c
+++ b/test/regress.c
@@ -699,6 +699,42 @@ test_loopexit(void)
cleanup_test();
}
+static void
+break_cb(int fd, short events, void *arg)
+{
+ test_ok = 1;
+ event_loopbreak();
+}
+
+static void
+fail_cb(int fd, short events, void *arg)
+{
+ test_ok = 0;
+}
+
+void
+test_loopbreak(void)
+{
+ struct event ev1, ev2;
+ struct timeval tv;
+
+ setup_test("Loop break: ");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ evtimer_set(&ev1, break_cb, NULL);
+ evtimer_add(&ev1, &tv);
+ evtimer_set(&ev2, fail_cb, NULL);
+ evtimer_add(&ev2, &tv);
+
+ event_dispatch();
+
+ evtimer_del(&ev1);
+ evtimer_del(&ev2);
+
+ cleanup_test();
+}
+
void
test_evbuffer(void) {
@@ -1201,6 +1237,7 @@ main (int argc, char **argv)
test_immediatesignal();
#endif
test_loopexit();
+ test_loopbreak();
test_multiple_events_for_same_fd();