mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-11 11:56:16 +01:00
gthread-posix: Use named states to manage the mutex states
We used to use raw numbers to control the mutex state, we can use a nicer enum to avoid dealing with pure numbers.
This commit is contained in:
parent
15d2053122
commit
8d98617297
@ -1449,9 +1449,16 @@ g_system_thread_set_name (const gchar *name)
|
|||||||
*
|
*
|
||||||
* 1: acquired by one thread only, no contention
|
* 1: acquired by one thread only, no contention
|
||||||
*
|
*
|
||||||
* > 1: contended
|
* 2: contended
|
||||||
*
|
*/
|
||||||
*
|
|
||||||
|
typedef enum {
|
||||||
|
G_MUTEX_STATE_EMPTY = 0,
|
||||||
|
G_MUTEX_STATE_OWNED,
|
||||||
|
G_MUTEX_STATE_CONTENDED,
|
||||||
|
} GMutexState;
|
||||||
|
|
||||||
|
/*
|
||||||
* As such, attempting to acquire the lock should involve an increment.
|
* As such, attempting to acquire the lock should involve an increment.
|
||||||
* If we find that the previous value was 0 then we can return
|
* If we find that the previous value was 0 then we can return
|
||||||
* immediately.
|
* immediately.
|
||||||
@ -1470,13 +1477,13 @@ g_system_thread_set_name (const gchar *name)
|
|||||||
void
|
void
|
||||||
g_mutex_init (GMutex *mutex)
|
g_mutex_init (GMutex *mutex)
|
||||||
{
|
{
|
||||||
mutex->i[0] = 0;
|
mutex->i[0] = G_MUTEX_STATE_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_mutex_clear (GMutex *mutex)
|
g_mutex_clear (GMutex *mutex)
|
||||||
{
|
{
|
||||||
if G_UNLIKELY (mutex->i[0] != 0)
|
if G_UNLIKELY (mutex->i[0] != G_MUTEX_STATE_EMPTY)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "g_mutex_clear() called on uninitialised or locked mutex\n");
|
fprintf (stderr, "g_mutex_clear() called on uninitialised or locked mutex\n");
|
||||||
g_abort ();
|
g_abort ();
|
||||||
@ -1486,13 +1493,16 @@ g_mutex_clear (GMutex *mutex)
|
|||||||
static void __attribute__((noinline))
|
static void __attribute__((noinline))
|
||||||
g_mutex_lock_slowpath (GMutex *mutex)
|
g_mutex_lock_slowpath (GMutex *mutex)
|
||||||
{
|
{
|
||||||
/* Set to 2 to indicate contention. If it was zero before then we
|
/* Set to contended. If it was empty before then we
|
||||||
* just acquired the lock.
|
* just acquired the lock.
|
||||||
*
|
*
|
||||||
* Otherwise, sleep for as long as the 2 remains...
|
* Otherwise, sleep for as long as the contended state remains...
|
||||||
*/
|
*/
|
||||||
while (exchange_acquire (&mutex->i[0], 2) != 0)
|
while (exchange_acquire (&mutex->i[0], G_MUTEX_STATE_CONTENDED) != G_MUTEX_STATE_EMPTY)
|
||||||
syscall (__NR_futex, &mutex->i[0], (gsize) FUTEX_WAIT_PRIVATE, (gsize) 2, NULL);
|
{
|
||||||
|
syscall (__NR_futex, &mutex->i[0], (gsize) FUTEX_WAIT_PRIVATE,
|
||||||
|
G_MUTEX_STATE_CONTENDED, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((noinline))
|
static void __attribute__((noinline))
|
||||||
@ -1502,7 +1512,7 @@ g_mutex_unlock_slowpath (GMutex *mutex,
|
|||||||
/* We seem to get better code for the uncontended case by splitting
|
/* We seem to get better code for the uncontended case by splitting
|
||||||
* this out...
|
* this out...
|
||||||
*/
|
*/
|
||||||
if G_UNLIKELY (prev == 0)
|
if G_UNLIKELY (prev == G_MUTEX_STATE_EMPTY)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Attempt to unlock mutex that was not locked\n");
|
fprintf (stderr, "Attempt to unlock mutex that was not locked\n");
|
||||||
g_abort ();
|
g_abort ();
|
||||||
@ -1514,8 +1524,10 @@ g_mutex_unlock_slowpath (GMutex *mutex,
|
|||||||
void
|
void
|
||||||
g_mutex_lock (GMutex *mutex)
|
g_mutex_lock (GMutex *mutex)
|
||||||
{
|
{
|
||||||
/* 0 -> 1 and we're done. Anything else, and we need to wait... */
|
/* empty -> owned and we're done. Anything else, and we need to wait... */
|
||||||
if G_UNLIKELY (g_atomic_int_add (&mutex->i[0], 1) != 0)
|
if G_UNLIKELY (!g_atomic_int_compare_and_exchange (&mutex->i[0],
|
||||||
|
G_MUTEX_STATE_EMPTY,
|
||||||
|
G_MUTEX_STATE_OWNED))
|
||||||
g_mutex_lock_slowpath (mutex);
|
g_mutex_lock_slowpath (mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,22 +1536,22 @@ g_mutex_unlock (GMutex *mutex)
|
|||||||
{
|
{
|
||||||
guint prev;
|
guint prev;
|
||||||
|
|
||||||
prev = exchange_release (&mutex->i[0], 0);
|
prev = exchange_release (&mutex->i[0], G_MUTEX_STATE_EMPTY);
|
||||||
|
|
||||||
/* 1-> 0 and we're done. Anything else and we need to signal... */
|
/* 1-> 0 and we're done. Anything else and we need to signal... */
|
||||||
if G_UNLIKELY (prev != 1)
|
if G_UNLIKELY (prev != G_MUTEX_STATE_OWNED)
|
||||||
g_mutex_unlock_slowpath (mutex, prev);
|
g_mutex_unlock_slowpath (mutex, prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
g_mutex_trylock (GMutex *mutex)
|
g_mutex_trylock (GMutex *mutex)
|
||||||
{
|
{
|
||||||
guint zero = 0;
|
GMutexState empty = G_MUTEX_STATE_EMPTY;
|
||||||
|
|
||||||
/* We don't want to touch the value at all unless we can move it from
|
/* We don't want to touch the value at all unless we can move it from
|
||||||
* exactly 0 to 1.
|
* exactly empty to owned.
|
||||||
*/
|
*/
|
||||||
return compare_exchange_acquire (&mutex->i[0], &zero, 1);
|
return compare_exchange_acquire (&mutex->i[0], &empty, G_MUTEX_STATE_OWNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Condition variables are implemented in a rather simple way as well.
|
/* Condition variables are implemented in a rather simple way as well.
|
||||||
|
Loading…
Reference in New Issue
Block a user