Re: [Libevent-users] [PATCH] event.c: make internal signal event count as active
Thank you. I applied this to trunk. Niels. On Nov 10, 2007 9:14 PM, Christopher Layne [EMAIL PROTECTED] wrote: On Sat, Nov 10, 2007 at 06:49:58PM -0800, Christopher Layne wrote: On Sat, Nov 10, 2007 at 06:44:12PM -0800, Christopher Layne wrote: 11. here's the funny part: evsignal_process() increments event_count_active - but since our Here's a better patch: This removes docount entirely. docount is used to determine if the event being added or removed from the queue should influence base-event_count. The internal signal event should not be counted as an event to wait for - such that when one deletes all their events the event loop will not count the internal signal event as something to wait around for (nothing changes here). However, based on the previous discussion, it still needs to be processed as a normal active event, hence we change base-event_count_active regardless of if it's internal or not. -cl Index: event.c === --- event.c (revision 507) +++ event.c (working copy) @@ -829,23 +829,17 @@ void event_queue_remove(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (!(ev-ev_flags queue)) event_errx(1, %s: %p(fd %d) not on queue %x, __func__, ev, ev-ev_fd, queue); - if (ev-ev_flags EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev-ev_flags EVLIST_INTERNAL) base-event_count--; ev-ev_flags = ~queue; switch (queue) { case EVLIST_ACTIVE: - if (docount) - base-event_count_active--; + base-event_count_active--; TAILQ_REMOVE(base-activequeues[ev-ev_pri], ev, ev_active_next); break; @@ -866,8 +860,6 @@ void event_queue_insert(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (ev-ev_flags queue) { /* Double insertion is possible for active events */ if (queue EVLIST_ACTIVE) @@ -877,17 +869,13 @@ ev, ev-ev_fd, queue); } - if (ev-ev_flags EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev-ev_flags EVLIST_INTERNAL) base-event_count++; ev-ev_flags |= queue; switch (queue) { case EVLIST_ACTIVE: - if (docount) - base-event_count_active++; + base-event_count_active++; TAILQ_INSERT_TAIL(base-activequeues[ev-ev_pri], ev,ev_active_next); break; ___ Libevent-users mailing list Libevent-users@monkey.org http://monkeymail.org/mailman/listinfo/libevent-users ___ Libevent-users mailing list Libevent-users@monkey.org http://monkeymail.org/mailman/listinfo/libevent-users
[Libevent-users] [PATCH] event.c: make internal signal event count as active
[ WARNING: Long and ardorous - difficult to trace behaviour ] Behaviour described is without EV_PERSIST on internal signal handler (as it's been for months): 1. signal comes in, we jump to our internal signal handler, it writes to pipe. 2. epoll_wait() returns -1/EINTR because a signal handler was called. 3. we do not process epoll events here, we call evsignal_process() and return from dispatch. 4. our user-side event is deleted from queues, marked active, and processed normally BY evsignal_process(). 5. user-side event then adds itself back normally to handle signals again. 6. we head back into epoll_dispatch(), where epoll_wait() immediately returns because signal pipe is ready for reading (from step 1). 7. we implicitly delete the internal signal event (remember, this is without EV_PERSIST on it) and mark is as active. however, since it is an internal event, we do not increment event_count_active. 8. we return to our main event loop within event.c, and do not call event_process_active() because event_count_active == 0. this is where the problems really start. 9. we head back into epoll_dispatch() and wait normally. however, since we previously deleted our internal signal pipe fd from the epoll set, and did NOT call it from event_process_active() in the previous step - the pipe never ends up being read. but since the user callback was executed properly, everything looks normal. 10. we send the same signal again. epoll_wait() returns, and we call evsignal_process() again. 11. here's the funny part: evsignal_process() increments event_count_active - but since our internal signal event is actually first on the active queue at this point, when we go to process events in the main loop - we actually end up processing our internal signal event here. it reads from the pipe, and then re-adds itself back into epoll's watch set. but since it's internal, we do not decrement event_count_active - guaranteeing we'll get to our user event when we process the active events from the main loop. this is the flip-flop. 12. repeat. Now with EV_PERSIST on the internal signal event, steps 7-12 do not happen the first time the signal is called. So not only is the bug still there, it's super bad when it happens as epoll_wait() returns immediately. By sending a signal again - we can flip it from spin to wait. So this is a bug that needs to be fixed anyways. The EV_PERSIST change just made it more visible. I'm not so sure how to make a regression test for this other than a specific test to make sure that our signal pipe is empty AFTER returning from event_process_active(). -- test case: #include signal.h #include stdlib.h #include unistd.h #include event.h void scb(int sig, short event, void *a) { write(2, .\n, 2); event_add(a, NULL); return; } int main(void) { struct event sig; event_init(); event_set(sig, SIGTSTP, EV_SIGNAL, scb, sig); event_add(sig, NULL); event_dispatch(); return 0; } -- debug log (unpatched): $ ./sigtest [debug] event_add: event: 0x7fff762c0500,call 0x400768 [debug] event_queue_insert: 0x7fff762c0500: docount == 1, event_count == 1, queue == 4 [debug] evsignal_add: evsignal sh_old_max, s == 20, max == 0 [debug] event_add: event: 0x602050, EV_READ call 0x2ac034a166d4 [debug] event_queue_insert: 0x602050: docount == 0, event_count == 1, queue == 2 wait, signal [debug] evsignal_handler: wake up [debug] epoll_dispatch: epoll_wait() res == -1, errno = 4 [debug] evsignal_process: processing signals, caught == 1 [debug] event_del: 0x7fff762c0500, callback 0x400768 [debug] evsignal_del: 0x7fff762c0500: restoring previous handler [debug] event_active: 0x7fff762c0500: adding to active queue, ev_res == 0, res == 8 [debug] event_queue_insert: 0x7fff762c0500: docount == 1, event_count == 1, queue == 8 [debug] event_base_loop: event_count_active == 1 . [debug] event_add: event: 0x7fff762c0500,call 0x400768 [debug] event_queue_insert: 0x7fff762c0500: docount == 1, event_count == 1, queue == 4 [debug] epoll_dispatch: epoll_wait reports 1 [debug] event_del: 0x602050, callback 0x2ac034a166d4 [debug] event_active: 0x602050: adding to active queue, ev_res == 0, res == 2 [debug] event_queue_insert: 0x602050: docount == 0, event_count == 1, queue == 8 [debug] event_base_loop: event_count_active == 0 wait, signal (notice how we immediately call our internal event from event_base_loop?) [debug] evsignal_handler: wake up [debug] epoll_dispatch: epoll_wait() res == -1, errno = 4 [debug] evsignal_process: processing signals, caught == 1 [debug] event_del: 0x7fff762c0500, callback 0x400768 [debug] evsignal_del: 0x7fff762c0500: restoring previous handler [debug] event_active: 0x7fff762c0500: adding to active queue, ev_res == 8, res == 8 [debug] event_queue_insert: 0x7fff762c0500: docount == 1, event_count == 1, queue == 8 [debug] event_base_loop: event_count_active == 1 [debug] evsignal_cb: n == 2
Re: [Libevent-users] [PATCH] event.c: make internal signal event count as active
On Sat, Nov 10, 2007 at 06:44:12PM -0800, Christopher Layne wrote: 11. here's the funny part: evsignal_process() increments event_count_active - but since our should be: evsignal_process() adds the internal event to the active queue as normal. before we call event_process_active(), event_count_active is 1 at that point (user event). but since our ... internal signal event is actually first on the active queue at this point, when we go to process events in the main loop - we actually end up processing our internal signal event here. it reads from the pipe, and then re-adds itself back into epoll's watch set. but since it's internal, we do not decrement event_count_active - guaranteeing we'll get to our user event when we process the active events from the main loop. this is the flip-flop. -cl ___ Libevent-users mailing list Libevent-users@monkey.org http://monkeymail.org/mailman/listinfo/libevent-users
Re: [Libevent-users] [PATCH] event.c: make internal signal event count as active
On Sat, Nov 10, 2007 at 06:49:58PM -0800, Christopher Layne wrote: On Sat, Nov 10, 2007 at 06:44:12PM -0800, Christopher Layne wrote: 11. here's the funny part: evsignal_process() increments event_count_active - but since our Here's a better patch: This removes docount entirely. docount is used to determine if the event being added or removed from the queue should influence base-event_count. The internal signal event should not be counted as an event to wait for - such that when one deletes all their events the event loop will not count the internal signal event as something to wait around for (nothing changes here). However, based on the previous discussion, it still needs to be processed as a normal active event, hence we change base-event_count_active regardless of if it's internal or not. -cl Index: event.c === --- event.c (revision 507) +++ event.c (working copy) @@ -829,23 +829,17 @@ void event_queue_remove(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (!(ev-ev_flags queue)) event_errx(1, %s: %p(fd %d) not on queue %x, __func__, ev, ev-ev_fd, queue); - if (ev-ev_flags EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev-ev_flags EVLIST_INTERNAL) base-event_count--; ev-ev_flags = ~queue; switch (queue) { case EVLIST_ACTIVE: - if (docount) - base-event_count_active--; + base-event_count_active--; TAILQ_REMOVE(base-activequeues[ev-ev_pri], ev, ev_active_next); break; @@ -866,8 +860,6 @@ void event_queue_insert(struct event_base *base, struct event *ev, int queue) { - int docount = 1; - if (ev-ev_flags queue) { /* Double insertion is possible for active events */ if (queue EVLIST_ACTIVE) @@ -877,17 +869,13 @@ ev, ev-ev_fd, queue); } - if (ev-ev_flags EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev-ev_flags EVLIST_INTERNAL) base-event_count++; ev-ev_flags |= queue; switch (queue) { case EVLIST_ACTIVE: - if (docount) - base-event_count_active++; + base-event_count_active++; TAILQ_INSERT_TAIL(base-activequeues[ev-ev_pri], ev,ev_active_next); break; ___ Libevent-users mailing list Libevent-users@monkey.org http://monkeymail.org/mailman/listinfo/libevent-users