from trunk:

Patch from Scott Lamb: Implement event_{base_}loopbreak.  Includes documentation and tests.  From sf.net Feature Request 1826546.


svn:r584
This commit is contained in:
Niels Provos 2007-12-12 06:26:07 +00:00
parent d582000e37
commit eecd6932c7
6 changed files with 109 additions and 2 deletions

View File

@ -10,6 +10,7 @@ Changes in current version:
o small improvements to evhttp documentation o small improvements to evhttp documentation
o always generate Date and Content-Length headers for HTTP/1.1 replies o always generate Date and Content-Length headers for HTTP/1.1 replies
o set the correct event base for HTTP close events o set the correct event base for HTTP close events
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-beta: Changes in 1.4.0-beta:

View File

@ -54,6 +54,7 @@ struct event_base {
int event_count_active; /* counts number of active events */ int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */ int event_gotterm; /* Set to terminate loop */
int event_break; /* Set to terminate loop immediately */
/* active event management */ /* active event management */
struct event_list **activequeues; struct event_list **activequeues;

17
event.3
View File

@ -34,10 +34,12 @@
.Nm event_dispatch , .Nm event_dispatch ,
.Nm event_loop , .Nm event_loop ,
.Nm event_loopexit , .Nm event_loopexit ,
.Nm event_loopbreak ,
.Nm event_set , .Nm event_set ,
.Nm event_base_dispatch , .Nm event_base_dispatch ,
.Nm event_base_loop , .Nm event_base_loop ,
.Nm event_base_loopexit , .Nm event_base_loopexit ,
.Nm event_base_loopbreak ,
.Nm event_base_set , .Nm event_base_set ,
.Nm event_base_free , .Nm event_base_free ,
.Nm event_add , .Nm event_add ,
@ -93,6 +95,8 @@
.Fn "event_loop" "int flags" .Fn "event_loop" "int flags"
.Ft int .Ft int
.Fn "event_loopexit" "struct timeval *tv" .Fn "event_loopexit" "struct timeval *tv"
.Ft int
.Fn "event_loopbreak" "void"
.Ft void .Ft void
.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
.Ft int .Ft int
@ -102,6 +106,8 @@
.Ft int .Ft int
.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv" .Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
.Ft int .Ft int
.Fn "event_base_loopbreak" "struct event_base *base"
.Ft int
.Fn "event_base_set" "struct event_base *base" "struct event *" .Fn "event_base_set" "struct event_base *base" "struct event *"
.Ft void .Ft void
.Fn "event_base_free" "struct event_base *base" .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 exit without blocking for events again. Subsequent invocations of
.Fn event_loop .Fn event_loop
will proceed normally. 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 .Pp
It is the responsibility of the caller to provide these functions with It is the responsibility of the caller to provide these functions with
pre-allocated event structures. pre-allocated event structures.

26
event.c
View File

@ -358,7 +358,7 @@ event_process_active(struct event_base *base)
ncalls--; ncalls--;
ev->ev_ncalls = ncalls; ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
if (event_gotsig) if (event_gotsig || base->event_break)
return; return;
} }
} }
@ -402,6 +402,25 @@ event_base_loopexit(struct event_base *event_base, struct timeval *tv)
event_base, tv)); event_base, 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 */ /* not thread safe */
int int
@ -433,6 +452,11 @@ event_base_loop(struct event_base *base, int flags)
break; break;
} }
if (base->event_break) {
base->event_break = 0;
break;
}
/* You cannot use this interface for multi-threaded apps */ /* You cannot use this interface for multi-threaded apps */
while (event_gotsig) { while (event_gotsig) {
event_gotsig = 0; event_gotsig = 0;

29
event.h
View File

@ -408,6 +408,35 @@ int event_loopexit(struct timeval *);
*/ */
int event_base_loopexit(struct event_base *, 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. Add a timer event.

View File

@ -769,6 +769,42 @@ test_loopexit(void)
cleanup_test(); 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 void
test_evbuffer(void) { test_evbuffer(void) {
@ -1275,6 +1311,7 @@ main (int argc, char **argv)
test_immediatesignal(); test_immediatesignal();
#endif #endif
test_loopexit(); test_loopexit();
test_loopbreak();
test_multiple_events_for_same_fd(); test_multiple_events_for_same_fd();