mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
gio: Prevent hang when finalizing GThreadedSocketService
If all users of a GThreadedSocketService release their references to the service while a connection thread is running, the thread function will release the last reference to the service which causes the finalize to deadlock waiting for all threads to finish (because it's called from the thread function). To fix this, don't wait for all threads to finish in the service's finalize method. Since the threads hold a reference to the service, finalize should only be called when all threads are finished running (or have unrefed the service and are about to finish). https://bugzilla.gnome.org/show_bug.cgi?id=712570
This commit is contained in:
parent
91802bbf2b
commit
9a6e01ea5b
@ -72,7 +72,6 @@ G_LOCK_DEFINE_STATIC(job_count);
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GThreadedSocketService *service;
|
|
||||||
GSocketConnection *connection;
|
GSocketConnection *connection;
|
||||||
GObject *source_object;
|
GObject *source_object;
|
||||||
} GThreadedSocketServiceData;
|
} GThreadedSocketServiceData;
|
||||||
@ -85,10 +84,9 @@ g_threaded_socket_service_func (gpointer _data,
|
|||||||
GThreadedSocketServiceData *data = _data;
|
GThreadedSocketServiceData *data = _data;
|
||||||
gboolean result;
|
gboolean result;
|
||||||
|
|
||||||
g_signal_emit (data->service, g_threaded_socket_service_run_signal,
|
g_signal_emit (threaded, g_threaded_socket_service_run_signal,
|
||||||
0, data->connection, data->source_object, &result);
|
0, data->connection, data->source_object, &result);
|
||||||
|
|
||||||
g_object_unref (data->service);
|
|
||||||
g_object_unref (data->connection);
|
g_object_unref (data->connection);
|
||||||
if (data->source_object)
|
if (data->source_object)
|
||||||
g_object_unref (data->source_object);
|
g_object_unref (data->source_object);
|
||||||
@ -98,6 +96,8 @@ g_threaded_socket_service_func (gpointer _data,
|
|||||||
if (threaded->priv->job_count-- == threaded->priv->max_threads)
|
if (threaded->priv->job_count-- == threaded->priv->max_threads)
|
||||||
g_socket_service_start (G_SOCKET_SERVICE (threaded));
|
g_socket_service_start (G_SOCKET_SERVICE (threaded));
|
||||||
G_UNLOCK (job_count);
|
G_UNLOCK (job_count);
|
||||||
|
|
||||||
|
g_object_unref (threaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -111,7 +111,10 @@ g_threaded_socket_service_incoming (GSocketService *service,
|
|||||||
threaded = G_THREADED_SOCKET_SERVICE (service);
|
threaded = G_THREADED_SOCKET_SERVICE (service);
|
||||||
|
|
||||||
data = g_slice_new (GThreadedSocketServiceData);
|
data = g_slice_new (GThreadedSocketServiceData);
|
||||||
data->service = g_object_ref (service);
|
|
||||||
|
/* Ref the socket service for the thread */
|
||||||
|
g_object_ref (service);
|
||||||
|
|
||||||
data->connection = g_object_ref (connection);
|
data->connection = g_object_ref (connection);
|
||||||
if (source_object)
|
if (source_object)
|
||||||
data->source_object = g_object_ref (source_object);
|
data->source_object = g_object_ref (source_object);
|
||||||
@ -156,7 +159,7 @@ g_threaded_socket_service_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
|
GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
|
||||||
|
|
||||||
g_thread_pool_free (service->priv->thread_pool, FALSE, TRUE);
|
g_thread_pool_free (service->priv->thread_pool, FALSE, FALSE);
|
||||||
|
|
||||||
G_OBJECT_CLASS (g_threaded_socket_service_parent_class)
|
G_OBJECT_CLASS (g_threaded_socket_service_parent_class)
|
||||||
->finalize (object);
|
->finalize (object);
|
||||||
|
Loading…
Reference in New Issue
Block a user