[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [Libevent-users] bufferevent openssl deadlock
Hi
FWIW in my experience your second idea would be a common solution
(queuing a new event to move the free on to the dispatch thread where it
can be guaranteed the event's callbacks are all done).
On Fri, Feb 24, 2012 at 09:34:12PM -0500, Nick Mathewson wrote:
> On Fri, Feb 24, 2012 at 8:14 PM, Amarin Phaosawasdi
> <amarinph@xxxxxxxxxxxx> wrote:
> > Hello,
> >
> > About a year ago, there was a thread about deadlocking in
> > bufferevent_openssl in multi-threaded mode
> > (http://archives.seul.org/libevent/users/Jan-2011/msg00019.html).
> >
> > We've run into the same problem.
> >
> > Our minimal fix?(as opposed to the patch mentioned, which adds atomic
> > operations to evthread)?for our specific use case was this :
> > - expose event_base_lock() and event_base_unlock() to library users
> > - in the user code make sure to lock the event_base before writing to an
> > openssl bufferevent, so no callbacks can be fired during that write (which
> > results in a deadlock).
> >
> > Does anybody have feedback on better ways to workaround this?
>
> So, this wants a general fix, not just a workaround. Right now, I am
> not sure what the general fix is. I started writing up some notes,
> but I don't think they actually point to an obvious conclusion yet.
> More insight would be welcome!
>
> First off, the bufferevents are a red herring: the problem is the way
> that Libevent handles attempts to event_del an event whose callback is
> currently running in a different thread. Right now, Libevent makes
> the thread that is not running the callback wait until the callback is
> done running. (This same behavior happens with event_add and
> event_active on signal events.)
>
> The problem shows up when we have other locks, like those used by
> bufferevents. If the thread calling event_del() holds a lock on some
> resource that the callback wants, then we wind up in a deadlock where
> the event_del() thread is waiting for the callback to finish, and the
> callback is waiting for the lock.
>
> So why do this? Why wait at all? When I wrote that code (back in
> 6b4b77a26), I think the rationale was this: there is lots of code
> where you want to event_del() an event, free it, and free the data
> structure that was in the event's callback_arg. When using Libevent
> in a single-threaded mode, this is completely safe, since either the
> event is not running, or you are
> doing all of this from the event's callback and you presumably know
> not to use the callback_arg after it's freed. But if your program is
> multithreaded, you run into a problem: the callback might be running
> at the time, merrily using the callback_arg and event you're about to
> free. So the thread doing the event_del() might free a callback_arg
> or an event that was in use.
>
> Here are all the fixes I can think of quickly, in brainstorming order:
>
> - Remove the wait entirely: make it the responsibility of the
> multithreaded program to ensure that the event callback is not
> running before you free the event's callback_arg. But the
> problem here is, how can you do that? You can event_del() the
> event to make sure that it is not pending or not active, but if the
> callback is running, it's running.
>
> - Remove the wait, and give multithreaded programs a way to make
> their cleanup happen _after_ the event is done running (if it's
> running). One sketch interface would make event_free() detect
> whether the event is running. If so, event_free() might return
> without freeing the event. Once the callback was finished,
> another callback would run to do whatever it was that the
> deleting thread hoped to do.
>
> We'd need a corresponding event_unassign() for events not created
> with event_new().
>
> - What else?
>
> Obviously, anything here that would place a new requirement on
> multithreaded programs should be written in a way so that currently
> working programs won't break because of it.
>
> yrs,
> --
> 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.