First thread : void osync_client_unref(OSyncClient *client) { osync_assert(client); if (g_atomic_int_dec_and_test(&(client->ref_count))) { osync_trace(TRACE_ENTRY, "%s(%p)", __func__, client); if (client->incoming) { if (osync_queue_is_connected(client->incoming)) osync_queue_disconnect(client->incoming, NULL); osync_queue_remove(client->incoming, NULL); osync_queue_free(client->incoming); } if (client->outgoing) { if (osync_queue_is_connected(client->outgoing)) osync_queue_disconnect(client->outgoing, NULL); osync_queue_free(client->outgoing); } if (client->plugin) osync_plugin_unref(client->plugin); if (client->thread) osync_thread_free(client->thread); g_free(client); osync_trace(TRACE_EXIT, "%s", __func__); } } Second thread : static gboolean osyncClientDisconnectCallback(gpointer data) { OSyncClient *client = data; osync_trace(TRACE_INTERNAL, "client disconnect callback %p", client); /* First, we disconnect our incoming queue. This will generate a HUP on the remote * side. We dont disconnect our outgoing queue yet, since we have to make sure that * all data is read. Only the listener should disconnect a pipe! */ if(client->incoming && osync_queue_is_connected(client->incoming)) osync_queue_disconnect(client->incoming, NULL); if (client->outgoing) { osync_trace(TRACE_INTERNAL, "waiting for client outgoing queue"); /* We now wait until the other side disconnect our outgoing queue */ while (osync_queue_is_connected(client->outgoing)) { g_usleep(100); } /* Gives some time if anyone wants to grab the HUP message from the outgoing part of the pipe */ g_usleep(200); /* Now we can safely disconnect our outgoing queue */ //FIXME : find proper condition those are only tests if( (client->syncloop && g_main_loop_is_running(client->syncloop)) || client->thread ) if(client->outgoing) osync_queue_disconnect(client->outgoing, NULL); } osync_trace(TRACE_INTERNAL, "waiting for client outgoing queue DONE"); return FALSE; } gdb showing the context switch : #1 0xb7f4a566 in osync_client_unref (client=0x8095ec8) at /home/prahal/tmp/opensync/opensync/opensync/client/opensync_client.c:1277 1277 osync_queue_free(client->incoming); (gdb) next 560 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, queue); (gdb) next [New Thread 0xb400cb90 (LWP 23823)] 563 GMutex * freeLock = g_mutex_new(); (gdb) next 565 g_mutex_lock(freeLock); (gdb) next 566 g_mutex_free(queue->pendingLock); (gdb) next 568 g_mutex_free(queue->disconnectLock); (gdb) next [Switching to Thread 0xb400cb90 (LWP 23823)] Breakpoint 3, osyncClientDisconnectCallback (data=0x8095ec8) at /home/prahal/tmp/opensync/opensync/opensync/client/opensync_client.c:1382 1382 { (gdb) list 1377 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 1378 return FALSE; 1379 } 1380 1381 static gboolean osyncClientDisconnectCallback(gpointer data) 1382 { 1383 OSyncClient *client = data; 1384 1385 osync_trace(TRACE_INTERNAL, "client disconnect callback %p", client); 1386 /* First, we disconnect our incoming queue. This will generate a HUP on the remote Function called: void osync_queue_free(OSyncQueue *queue) { osync_trace(TRACE_ENTRY, "%s(%p)", __func__, queue); OSyncMessage *message = NULL; OSyncPendingMessage *pending = NULL; g_mutex_free(queue->pendingLock); g_mutex_free(queue->disconnectLock); g_main_context_unref(queue->context); _osync_queue_stop_incoming(queue); while ((message = g_async_queue_try_pop(queue->incoming))) { osync_message_unref(message); } g_async_queue_unref(queue->incoming); while ((message = g_async_queue_try_pop(queue->outgoing))) { osync_message_unref(message); } g_async_queue_unref(queue->outgoing); while (queue->pendingReplies) { pending = queue->pendingReplies->data; g_free(pending); queue->pendingReplies = g_list_remove(queue->pendingReplies, pending); } if (queue->name) g_free(queue->name); g_free(queue); queue = NULL; osync_trace(TRACE_EXIT, "%s", __func__); } osync_bool osync_queue_disconnect(OSyncQueue *queue, OSyncError **error) { osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, queue, error); osync_assert(queue); g_mutex_lock(queue->disconnectLock); (...) queue->fd = -1; queue->connected = FALSE; g_mutex_unlock(queue->disconnectLock); osync_trace(TRACE_EXIT, "%s", __func__); return TRUE; }