mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Bypass event_add when using event_base_once() for a 0-sec timeout
Some people use event_base_once(EV_TIMEOUT) to make a callback get called "immediately". But this is pretty roundabout: it uses the timeout heap to immediately put the event onto the active queue, when it could just use event_active. Additionally, it can lead to surprising re-ordering behavior. This patch changes event_base_once so it bypasses event_add() and called event_active() directly on a pure-timeout event with an empty timeout.
This commit is contained in:
parent
748a0d2794
commit
35c5c9558a
15
event.c
15
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;
|
||||
|
||||
|
@ -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:
|
||||
;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user