mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 23:16:14 +01:00
df0b208831
Based on a patch from Alexander Larsson. https://bugzilla.gnome.org/show_bug.cgi?id=651467
163 lines
4.0 KiB
C
163 lines
4.0 KiB
C
/*
|
|
* Copyright © 2008 Ryan Lortie
|
|
* Copyright © 2010 Codethink Limited
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* See the included COPYING file for more information.
|
|
*/
|
|
|
|
/* LOCKS should be more than the number of contention
|
|
* counters in gthread.c in order to ensure we exercise
|
|
* the case where they overlap.
|
|
*/
|
|
#define LOCKS 48
|
|
#define ITERATIONS 10000
|
|
#define THREADS 100
|
|
|
|
#include <glib.h>
|
|
|
|
#if TEST_EMULATED_FUTEX
|
|
/* this is defined for the 1bit-mutex-emufutex test.
|
|
*
|
|
* we want to test the emulated futex even if futex(2) is available.
|
|
*/
|
|
|
|
/* side-step some glib build stuff */
|
|
#define GLIB_COMPILATION
|
|
|
|
/* rebuild gbitlock.c without futex support,
|
|
defining our own version of the g_bit_*lock symbols
|
|
*/
|
|
#undef g_pointer_bit_lock
|
|
#undef g_pointer_bit_trylock
|
|
#undef g_pointer_bit_unlock
|
|
|
|
#define g_bit_lock _emufutex_g_bit_lock
|
|
#define g_bit_trylock _emufutex_g_bit_trylock
|
|
#define g_bit_unlock _emufutex_g_bit_unlock
|
|
#define g_pointer_bit_lock _emufutex_g_pointer_bit_lock
|
|
#define g_pointer_bit_trylock _emufutex_g_pointer_bit_trylock
|
|
#define g_pointer_bit_unlock _emufutex_g_pointer_bit_unlock
|
|
#define _g_futex_thread_init _emufutex_g_futex_thread_init
|
|
|
|
#define G_BIT_LOCK_FORCE_FUTEX_EMULATION
|
|
|
|
#include <glib/gbitlock.c>
|
|
#endif
|
|
|
|
volatile GThread *owners[LOCKS];
|
|
volatile gint locks[LOCKS];
|
|
volatile gpointer ptrs[LOCKS];
|
|
volatile gint bits[LOCKS];
|
|
|
|
static void
|
|
acquire (int nr,
|
|
gboolean use_pointers)
|
|
{
|
|
GThread *self;
|
|
|
|
self = g_thread_self ();
|
|
|
|
g_assert_cmpint (((gsize) ptrs) % 8, ==, 0);
|
|
|
|
if (!(use_pointers ?
|
|
g_pointer_bit_trylock (&ptrs[nr], bits[nr])
|
|
: g_bit_trylock (&locks[nr], bits[nr])))
|
|
{
|
|
if (g_test_verbose ())
|
|
g_print ("thread %p going to block on lock %d\n", self, nr);
|
|
|
|
if (use_pointers)
|
|
g_pointer_bit_lock (&ptrs[nr], bits[nr]);
|
|
else
|
|
g_bit_lock (&locks[nr], bits[nr]);
|
|
}
|
|
|
|
g_assert (owners[nr] == NULL); /* hopefully nobody else is here */
|
|
owners[nr] = self;
|
|
|
|
/* let some other threads try to ruin our day */
|
|
g_thread_yield ();
|
|
g_thread_yield ();
|
|
g_thread_yield ();
|
|
|
|
g_assert (owners[nr] == self); /* hopefully this is still us... */
|
|
owners[nr] = NULL; /* make way for the next guy */
|
|
|
|
if (use_pointers)
|
|
g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
|
|
else
|
|
g_bit_unlock (&locks[nr], bits[nr]);
|
|
}
|
|
|
|
static gpointer
|
|
thread_func (gpointer data)
|
|
{
|
|
gboolean use_pointers = GPOINTER_TO_INT (data);
|
|
gint i;
|
|
GRand *rand;
|
|
|
|
rand = g_rand_new ();
|
|
|
|
for (i = 0; i < ITERATIONS; i++)
|
|
acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
|
|
|
|
g_rand_free (rand);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
testcase (gconstpointer data)
|
|
{
|
|
gboolean use_pointers = GPOINTER_TO_INT (data);
|
|
GThread *threads[THREADS];
|
|
int i;
|
|
|
|
g_thread_init (NULL);
|
|
|
|
#ifdef TEST_EMULATED_FUTEX
|
|
_g_futex_thread_init ();
|
|
#define SUFFIX "-emufutex"
|
|
|
|
/* ensure that we are using the emulated futex by checking
|
|
* (at compile-time) for the existance of 'g_futex_mutex'
|
|
*/
|
|
g_assert (g_futex_mutex != NULL);
|
|
#else
|
|
#define SUFFIX ""
|
|
#endif
|
|
|
|
for (i = 0; i < LOCKS; i++)
|
|
bits[i] = g_random_int () % 32;
|
|
|
|
for (i = 0; i < THREADS; i++)
|
|
threads[i] = g_thread_create (thread_func,
|
|
GINT_TO_POINTER (use_pointers),
|
|
TRUE, NULL);
|
|
|
|
for (i = 0; i < THREADS; i++)
|
|
g_thread_join (threads[i]);
|
|
|
|
for (i = 0; i < LOCKS; i++)
|
|
{
|
|
g_assert (owners[i] == NULL);
|
|
g_assert (locks[i] == 0);
|
|
}
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/int", (gpointer) 0, testcase);
|
|
g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/pointer", (gpointer) 1, testcase);
|
|
|
|
return g_test_run ();
|
|
}
|