[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Help with progress thread



On Nov 9, 2010, at 9:03 PM, Nick Mathewson wrote:

> On Tue, Nov 9, 2010 at 3:28 PM, Ralph Castain <rhc@xxxxxxxxxxxx> wrote:
>> Hi folks
>> 
>> I'm running into a problem that probably results from my ignorance. So I figured I would ask if someone can tell me what I'm doing wrong.
>> 
>> I have a thread that loops the event library with the following call:
>> 
>>        events += event_loop(mca_oob_tcp_component.event_base, EVLOOP_ONCE);
>> 
>> In another thread, I create and add an event that is supposed to occur when a file descriptor is ready for "write":
>> 
>>         event_set(mca_oob_tcp_component.event_base,
>>                       &peer->peer_send_event,
>>                       peer->peer_sd,
>>                       EV_WRITE|EV_PERSIST,
>>                       mca_oob_tcp_peer_send_handler,
>>                       peer);
>>         event_add(&peer->peer_send_event, 0);
>> 
>> Note that the event_set and event_add can (and in this case, probably do) occur while I am in the event_loop function.
>> 
>> What I find is that this event never gets fired. However, events that are set and added -before- going into the loop do fire.
>> 
>> So my question is: given that this is a dynamic system, how do I get the event_loop to "see" new events? I want to block in the loop, so I don't really want to set NONBLOCK if I can avoid it (otherwise, I would have to add another blocking call somewhere to keep the thread from endlessly cycling).
> 
> So I'm assuming that you've got all the threading callbacks set up
> (probably via evthread_use_pthreads()) before you created the event
> base, so that evthread_make_base_notifiable() was called on the
> event_base when you created it.  If that's not the case, that's
> probably the problem there.

I missed that - this may well be my problem. Let me dig into this a little and get back to you.

FWIW: I don't see myself drop out of the event loop when I add the event. In fact, just the opposite - I'm stuck in the loop and can't get out. So I'm not sure the bug mentioned below is accurate.

Let me see what happens when I setup the event base for notification.

Thanks!

> 
> Otherwise, I think this one is an honest-to-goodness bug.
> 
> Here's what happens when you add an event from another thread.
> 
> The event_add locks the event_base's structures, makes the changes
> necessary to add the event, and then notices that it isn't running in
> the main thread, so it needs to "alert" the main thread to exit and
> re-enter the dispatch function[*].  It does this by calling
> evthread_notify_base(), which sends a byte down a pipe (on most Unix)
> or a socketpair (on Windows), or by using an eventfd (on Linux) [**].
> There's an (EVLIST_INTERNAL) event handler for this
> pipe/socketpair/eventfd that notices that we've been "notified" so we
> can drain the pipe/socketpair/eventfd.
> 
> Now here's where I think the bug is: that event counts as an active
> event, and processing it gets counted as processing an event, so if
> you're running the loop with EVLOOP_ONCE, the loop will exit right
> after it notices that it should wake up, even though no user callbacks
> were actually entered.
> 
> The logic is in event_base_loop():
> 
>    		if (N_ACTIVE_CALLBACKS(base)) {
> 			event_process_active(base);
> 			if (!base->event_count_active && (flags & EVLOOP_ONCE))
> 				done = 1;
>                } ...
> 
> I think that the second "if" might be wrong.  We maybe want to
> continue looping not only if there are active callbacks, but also if
> the only active events that we processed were internal events.
> 
> With the current behavior, with EVLOOP_ONCE, I think adding the event
> from another thread will exit the loop right away.  Is that consistent
> with the behavior you're seeing?  If not, then the bug is possibly in
> the notification stuff, though that part actually is fairly well
> tested.
> 
> It's also possible that I'm writing this too late at night for me, and
> I've deeply misanalyzed the code here.
> 
> (As an aside, we should probably also continue looping if
> N_ACTIVE_CALLBACKS(base) is nonzero.)
> 
> [*] For backends like poll and select, we need to re-enter the
> dispatch function after getting event changes so that we can call
> select/poll with their new arguments.  For stuff like epoll and
> kqueue, we need to process the changelist and re-enter the wait
> function.
> [**] Yes, I do indeed think that kqueue should use EVFILT_USER, but
> that's a 2.1 thing.
> 
> -- 
> Nick
> ***********************************************************************
> To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
> unsubscribe libevent-users    in the body.

***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.