diff --git a/event.c b/event.c index eee150a4..c64a66de 100644 --- a/event.c +++ b/event.c @@ -1765,7 +1765,6 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events, void *arg, const struct timeval *tv) { struct event_once *eonce; - struct timeval etv; int res = 0; /* We cannot support signals that just fire once, or persistent @@ -1780,12 +1779,16 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events, eonce->arg = arg; if (events == EV_TIMEOUT) { - if (tv == NULL) { - evutil_timerclear(&etv); - tv = &etv; - } - evtimer_assign(&eonce->ev, base, event_once_cb, eonce); + + if (tv == NULL || ! evutil_timerisset(tv)) { + /* If the event is going to become active immediately, + * don't put it on the timeout queue. This is one + * idiom for scheduling a callback, so let's make + * it fast (and order-preserving). */ + event_active(&eonce->ev, EV_TIMEOUT, 1); + return 0; + } } else if (events & (EV_READ|EV_WRITE)) { events &= EV_READ|EV_WRITE; diff --git a/test/regress.c b/test/regress.c index 985c0938..1d2d2dcc 100644 --- a/test/regress.c +++ b/test/regress.c @@ -2018,6 +2018,15 @@ end: ; } +static void +immediate_called_twice_cb(evutil_socket_t fd, short event, void *arg) +{ + tt_int_op(event, ==, EV_TIMEOUT); + called += 1000; +end: + ; +} + static void test_event_once(void *ptr) { @@ -2036,6 +2045,14 @@ test_event_once(void *ptr) tt_int_op(r, ==, 0); r = event_base_once(data->base, -1, 0, NULL, NULL, NULL); tt_int_op(r, <, 0); + r = event_base_once(data->base, -1, EV_TIMEOUT, + immediate_called_twice_cb, NULL, NULL); + tt_int_op(r, ==, 0); + tv.tv_sec = 0; + tv.tv_usec = 0; + r = event_base_once(data->base, -1, EV_TIMEOUT, + immediate_called_twice_cb, NULL, &tv); + tt_int_op(r, ==, 0); if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); @@ -2045,7 +2062,7 @@ test_event_once(void *ptr) event_base_dispatch(data->base); - tt_int_op(called, ==, 101); + tt_int_op(called, ==, 2101); end: ; }