mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-08 11:53:00 -04:00
New EVLOOP_NO_EXIT_ON_EMPTY option to keep looping even when no events are pending
This can be useful if you want to start an event loop and then add or remove events to it from another thread.
This commit is contained in:
parent
9593a33fd1
commit
084e68f3f2
3
event.c
3
event.c
@ -1636,7 +1636,8 @@ event_base_loop(struct event_base *base, int flags)
|
||||
}
|
||||
|
||||
/* If we have no events, we just exit */
|
||||
if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
|
||||
if (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
|
||||
!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
|
||||
event_debug(("%s: no events registered.", __func__));
|
||||
retval = 1;
|
||||
goto done;
|
||||
|
@ -681,6 +681,11 @@ int event_base_set(struct event_base *, struct event *);
|
||||
/** Do not block: see which events are ready now, run the callbacks
|
||||
* of the highest-priority ones, then exit. */
|
||||
#define EVLOOP_NONBLOCK 0x02
|
||||
/** Do not exit the loop because we have no pending events. Instead, keep
|
||||
* running until event_base_loopexit() or event_base_loopbreak() makes us
|
||||
* stop.
|
||||
*/
|
||||
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
|
@ -493,6 +493,75 @@ end:
|
||||
THREAD_JOIN(load_threads[i]);
|
||||
}
|
||||
|
||||
static struct event time_events[5];
|
||||
static struct timeval times[5];
|
||||
static struct event_base *exit_base = NULL;
|
||||
static void
|
||||
note_time_cb(evutil_socket_t fd, short what, void *arg)
|
||||
{
|
||||
evutil_gettimeofday(arg, NULL);
|
||||
if (arg == ×[4]) {
|
||||
event_base_loopbreak(exit_base);
|
||||
}
|
||||
}
|
||||
static THREAD_FN
|
||||
register_events_subthread(void *arg)
|
||||
{
|
||||
struct timeval tv = {0,0};
|
||||
SLEEP_MS(100);
|
||||
event_active(&time_events[0], EV_TIMEOUT, 1);
|
||||
SLEEP_MS(100);
|
||||
event_active(&time_events[1], EV_TIMEOUT, 1);
|
||||
SLEEP_MS(100);
|
||||
tv.tv_usec = 100*1000;
|
||||
event_add(&time_events[2], &tv);
|
||||
tv.tv_usec = 150*1000;
|
||||
event_add(&time_events[3], &tv);
|
||||
SLEEP_MS(200);
|
||||
event_active(&time_events[4], EV_TIMEOUT, 1);
|
||||
|
||||
THREAD_RETURN();
|
||||
}
|
||||
|
||||
static void
|
||||
thread_no_events(void *arg)
|
||||
{
|
||||
THREAD_T thread;
|
||||
struct basic_test_data *data = arg;
|
||||
struct timeval starttime, endtime;
|
||||
int i;
|
||||
exit_base = data->base;
|
||||
|
||||
memset(times,0,sizeof(times));
|
||||
for (i=0;i<5;++i) {
|
||||
event_assign(&time_events[i], data->base,
|
||||
-1, 0, note_time_cb, ×[i]);
|
||||
}
|
||||
|
||||
evutil_gettimeofday(&starttime, NULL);
|
||||
THREAD_START(thread, register_events_subthread, data->base);
|
||||
event_base_loop(data->base, EVLOOP_NO_EXIT_ON_EMPTY);
|
||||
evutil_gettimeofday(&endtime, NULL);
|
||||
tt_assert(event_base_got_break(data->base));
|
||||
THREAD_JOIN(thread);
|
||||
for (i=0; i<5; ++i) {
|
||||
struct timeval diff;
|
||||
double sec;
|
||||
evutil_timersub(×[i], &starttime, &diff);
|
||||
sec = diff.tv_sec + diff.tv_usec/1.0e6;
|
||||
TT_BLATHER(("event %d at %.4f seconds", i, sec));
|
||||
}
|
||||
test_timeval_diff_eq(&starttime, ×[0], 100);
|
||||
test_timeval_diff_eq(&starttime, ×[1], 200);
|
||||
test_timeval_diff_eq(&starttime, ×[2], 400);
|
||||
test_timeval_diff_eq(&starttime, ×[3], 450);
|
||||
test_timeval_diff_eq(&starttime, ×[4], 500);
|
||||
test_timeval_diff_eq(&starttime, &endtime, 500);
|
||||
|
||||
end:
|
||||
;
|
||||
}
|
||||
|
||||
#define TEST(name) \
|
||||
{ #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \
|
||||
&basic_setup, NULL }
|
||||
@ -506,6 +575,7 @@ struct testcase_t thread_testcases[] = {
|
||||
#endif
|
||||
TEST(conditions_simple),
|
||||
TEST(deferred_cb_skew),
|
||||
TEST(no_events),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user