mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
Fix a possible deadlock
the FdSource was calling g_cancellable_disconnect while holding the main context lock, which is bad news if the ::cancelled handler is trying to get that lock to wake up the mainloop... Bug 586432
This commit is contained in:
parent
5179d92e9c
commit
b2715bbc5e
@ -86,9 +86,13 @@ fd_source_finalize (GSource *source)
|
||||
{
|
||||
FDSource *fd_source = (FDSource *)source;
|
||||
|
||||
/* we don't use g_cancellable_disconnect() here, since we are holding
|
||||
* the main context lock here, and the ::disconnect signal handler
|
||||
* will try to grab that, and deadlock looms.
|
||||
*/
|
||||
if (fd_source->cancelled_tag)
|
||||
g_cancellable_disconnect (fd_source->cancellable,
|
||||
fd_source->cancelled_tag);
|
||||
g_signal_handler_disconnect (fd_source->cancellable,
|
||||
fd_source->cancelled_tag);
|
||||
|
||||
if (fd_source->cancellable)
|
||||
g_object_unref (fd_source->cancellable);
|
||||
|
@ -33,16 +33,6 @@ int writer_pipe[2], reader_pipe[2];
|
||||
GCancellable *writer_cancel, *reader_cancel, *main_cancel;
|
||||
GMainLoop *loop;
|
||||
|
||||
static gboolean
|
||||
cancel_main (gpointer data)
|
||||
{
|
||||
GCancellable *main_cancel = data;
|
||||
|
||||
g_cancellable_cancel (main_cancel);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gpointer
|
||||
writer_thread (gpointer user_data)
|
||||
@ -74,17 +64,7 @@ writer_thread (gpointer user_data)
|
||||
|
||||
if (g_cancellable_is_cancelled (writer_cancel))
|
||||
{
|
||||
/* FIXME: directly calling g_cancellable_cancel (main_cancel) here
|
||||
* leads to sporadic deadlock, because it will try to wake up the
|
||||
* main context, for which it needs to acquire the main context lock.
|
||||
* This lock may be held by the main loop running in the main thread,
|
||||
* and it may be held while the main thread is blocking in
|
||||
* fd_source_finalize -> g_cancellable_disconnect
|
||||
* until the ::cancelled callbacks have run.
|
||||
*
|
||||
* Work around by deferring the cancellation to a timeout.
|
||||
*/
|
||||
g_timeout_add (0, cancel_main, main_cancel);
|
||||
g_cancellable_cancel (main_cancel);
|
||||
g_object_unref (out);
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user