gcancellable: Synchronize access to cancelled flag

Synchronize access to cancelled flag of cancellable, which was
previously access without synchronization in g_cancellable_is_cancelled.
Use atomic operations instead of existing global mutex, to avoid
serializing calls to g_cancellable_is_cancelled across all threads.
This commit is contained in:
Tomasz Miąsko 2019-02-25 00:00:00 +00:00 committed by Tomasz Miąsko
parent 6336864171
commit f975858e86

View File

@ -43,7 +43,9 @@ enum {
struct _GCancellablePrivate struct _GCancellablePrivate
{ {
guint cancelled : 1; /* Atomic so that g_cancellable_is_cancelled does not require holding the mutex. */
gboolean cancelled;
/* Access to fields below is protected by cancellable_mutex. */
guint cancelled_running : 1; guint cancelled_running : 1;
guint cancelled_running_waiting : 1; guint cancelled_running_waiting : 1;
@ -269,12 +271,12 @@ g_cancellable_reset (GCancellable *cancellable)
g_cond_wait (&cancellable_cond, &cancellable_mutex); g_cond_wait (&cancellable_cond, &cancellable_mutex);
} }
if (priv->cancelled) if (g_atomic_int_get (&priv->cancelled))
{ {
if (priv->wakeup) if (priv->wakeup)
GLIB_PRIVATE_CALL (g_wakeup_acknowledge) (priv->wakeup); GLIB_PRIVATE_CALL (g_wakeup_acknowledge) (priv->wakeup);
priv->cancelled = FALSE; g_atomic_int_set (&priv->cancelled, FALSE);
} }
g_mutex_unlock (&cancellable_mutex); g_mutex_unlock (&cancellable_mutex);
@ -292,7 +294,7 @@ g_cancellable_reset (GCancellable *cancellable)
gboolean gboolean
g_cancellable_is_cancelled (GCancellable *cancellable) g_cancellable_is_cancelled (GCancellable *cancellable)
{ {
return cancellable != NULL && cancellable->priv->cancelled; return cancellable != NULL && g_atomic_int_get (&cancellable->priv->cancelled);
} }
/** /**
@ -404,7 +406,7 @@ g_cancellable_make_pollfd (GCancellable *cancellable, GPollFD *pollfd)
{ {
cancellable->priv->wakeup = GLIB_PRIVATE_CALL (g_wakeup_new) (); cancellable->priv->wakeup = GLIB_PRIVATE_CALL (g_wakeup_new) ();
if (cancellable->priv->cancelled) if (g_atomic_int_get (&cancellable->priv->cancelled))
GLIB_PRIVATE_CALL (g_wakeup_signal) (cancellable->priv->wakeup); GLIB_PRIVATE_CALL (g_wakeup_signal) (cancellable->priv->wakeup);
} }
@ -440,11 +442,11 @@ g_cancellable_release_fd (GCancellable *cancellable)
return; return;
g_return_if_fail (G_IS_CANCELLABLE (cancellable)); g_return_if_fail (G_IS_CANCELLABLE (cancellable));
g_return_if_fail (cancellable->priv->fd_refcount > 0);
priv = cancellable->priv; priv = cancellable->priv;
g_mutex_lock (&cancellable_mutex); g_mutex_lock (&cancellable_mutex);
g_assert (priv->fd_refcount > 0);
priv->fd_refcount--; priv->fd_refcount--;
if (priv->fd_refcount == 0) if (priv->fd_refcount == 0)
@ -482,21 +484,20 @@ g_cancellable_cancel (GCancellable *cancellable)
{ {
GCancellablePrivate *priv; GCancellablePrivate *priv;
if (cancellable == NULL || if (g_cancellable_is_cancelled (cancellable))
cancellable->priv->cancelled)
return; return;
priv = cancellable->priv; priv = cancellable->priv;
g_mutex_lock (&cancellable_mutex); g_mutex_lock (&cancellable_mutex);
if (priv->cancelled) if (g_atomic_int_get (&priv->cancelled))
{ {
g_mutex_unlock (&cancellable_mutex); g_mutex_unlock (&cancellable_mutex);
return; return;
} }
priv->cancelled = TRUE; g_atomic_int_set (&priv->cancelled, TRUE);
priv->cancelled_running = TRUE; priv->cancelled_running = TRUE;
if (priv->wakeup) if (priv->wakeup)
@ -562,7 +563,7 @@ g_cancellable_connect (GCancellable *cancellable,
g_mutex_lock (&cancellable_mutex); g_mutex_lock (&cancellable_mutex);
if (cancellable->priv->cancelled) if (g_atomic_int_get (&cancellable->priv->cancelled))
{ {
void (*_callback) (GCancellable *cancellable, void (*_callback) (GCancellable *cancellable,
gpointer user_data); gpointer user_data);