port-probe: avoid deadlock trying to disconnect cancellable

We cannot in any way try to disconnect a GCancellable from within a
cancellation handler, or we'll deadlock.

    Thread 1 (Thread 0x7fe98bf25700 (LWP 12079)):
    #0  0x00007fe98a355f36 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0
    #1  0x00007fe98a7f5ac0 in g_cond_wait () from /usr/lib/libglib-2.0.so.0
    #2  0x00007fe98ad14650 in g_cancellable_disconnect () from /usr/lib/libgio-2.0.so.0
    #3  0x000000000045be5d in port_probe_run_context_free ()
    #4  0x00007fe98ad519ed in g_task_finalize () from /usr/lib/libgio-2.0.so.0
    #5  0x00007fe98aaaa7b3 in g_object_unref () from /usr/lib/libgobject-2.0.so.0
    #6  0x000000000045b5f8 in port_probe_task_return_error_if_cancelled ()
    #7  0x000000000045c57d in serial_probe_at_parse_response ()
    #8  0x00007fe98ad42ed2 in g_simple_async_result_complete () from /usr/lib/libgio-2.0.so.0
    #9  0x0000000000485c7d in serial_command_ready ()
    #10 0x00007fe98ad42ed2 in g_simple_async_result_complete () from /usr/lib/libgio-2.0.so.0
    #11 0x0000000000482345 in command_context_complete_and_free ()
    #12 0x0000000000482fa5 in port_serial_got_response ()
    #13 0x00000000004830f5 in port_serial_response_wait_cancelled ()
    #14 0x00007fe98aaa70c5 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
    #15 0x00007fe98aab47ce in signal_emit_unlocked_R () from /usr/lib/libgobject-2.0.so.0
    #16 0x00007fe98aabb595 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
    #17 0x00007fe98aabb662 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
    #18 0x00007fe98ad144c5 in g_cancellable_cancel () from /usr/lib/libgio-2.0.so.0
    #19 0x00007fe98aaa70c5 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
    #20 0x00007fe98aab47ce in signal_emit_unlocked_R () from /usr/lib/libgobject-2.0.so.0
    #21 0x00007fe98aabb595 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
    #22 0x00007fe98aabb662 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
    #23 0x00007fe98ad144c5 in g_cancellable_cancel () from /usr/lib/libgio-2.0.so.0
    #24 0x000000000042e9f6 in port_context_cancel ()
    #25 0x00007fe989b99a4c in ffi_call_unix64 () at ../src/x86/unix64.S:75
    #26 0x00007fe989b994b9 in ffi_call (cif=0x7fffc41dcdb0, fn=0x42ea40 <device_context_port_released>, rvalue=<optimized out>, avalue=0x7fffc41dccd0) at ../src/x86/ffi64.c:492
    #27 0x00007fe98aaa7700 in g_cclosure_marshal_generic () from /usr/lib/libgobject-2.0.so.0
    #28 0x00007fe98aaa70c5 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
    #29 0x00007fe98aab47ce in signal_emit_unlocked_R () from /usr/lib/libgobject-2.0.so.0
    #30 0x00007fe98aabb595 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
    #31 0x00007fe98aabb662 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
    #32 0x000000000042c8f0 in mm_device_release_port ()
    #33 0x000000000042a6cb in device_removed ()
    #34 0x000000000042af94 in handle_kernel_event ()
    #35 0x000000000042b356 in report_kernel_event_auth_ready ()
    #36 0x00007fe98ad51783 in g_task_return_now () from /usr/lib/libgio-2.0.so.0
    #37 0x00007fe98ad517b9 in complete_in_idle_cb () from /usr/lib/libgio-2.0.so.0
    #38 0x00007fe98a7bda5e in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
    #39 0x00007fe98a7bddb8 in g_main_context_iterate.isra () from /usr/lib/libglib-2.0.so.0
    #40 0x00007fe98a7be042 in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
    #41 0x0000000000428dc4 in main ()

So, just clear the cancellation id before going on with the handler logic.
This commit is contained in:
Aleksander Morgado
2017-10-05 12:37:12 +02:00
parent 3e15dc15ef
commit 71730509ee
+7 -5
View File
@@ -1285,10 +1285,12 @@ serial_open_at (MMPortProbe *self)
}
static void
at_cancellable_cancel (GCancellable *main_cancellable,
GCancellable *at_cancellable)
at_cancellable_cancel (GCancellable *cancellable,
PortProbeRunContext *ctx)
{
g_cancellable_cancel (at_cancellable);
/* Avoid trying to disconnect cancellable on the handler, or we'll deadlock */
ctx->at_probing_cancellable_linked = 0;
g_cancellable_cancel (ctx->at_probing_cancellable);
}
gboolean
@@ -1405,8 +1407,8 @@ mm_port_probe_run (MMPortProbe *self,
if (cancellable)
ctx->at_probing_cancellable_linked = g_cancellable_connect (cancellable,
(GCallback) at_cancellable_cancel,
g_object_ref (ctx->at_probing_cancellable),
g_object_unref);
ctx,
NULL);
ctx->source_id = g_idle_add ((GSourceFunc) serial_open_at, self);
return;
}