mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-14 03:33:06 +02:00
bitlock/tests: add test for using bit lock API in parallel
Add a test that runs a few threads, which take a bit lock and collectively increment a counter.
This commit is contained in:
parent
5b7280c368
commit
dd5e9af181
@ -1,5 +1,7 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "gtestutils.h"
|
||||
|
||||
static void
|
||||
test_bitlocks (void)
|
||||
{
|
||||
@ -28,12 +30,148 @@ test_bitlocks (void)
|
||||
}
|
||||
}
|
||||
|
||||
#define PARALLEL_N_THREADS 5
|
||||
#define PARALLEL_LOCKBIT 31
|
||||
#define PARALLEL_TOGGLEBIT 30
|
||||
#define PARALLEL_SETBIT 29
|
||||
#define PARALLEL_LOCKMASK (1 << PARALLEL_LOCKBIT)
|
||||
#define PARALLEL_TOGGLEMASK (1 << PARALLEL_TOGGLEBIT)
|
||||
#define PARALLEL_SETMASK (1 << PARALLEL_SETBIT)
|
||||
#define PARALLEL_MAX_COUNT_SELF 500
|
||||
#define PARALLEL_MAX_COUNT_ALL (10 * PARALLEL_MAX_COUNT_SELF)
|
||||
static int parallel_thread_ready = 0;
|
||||
static int parallel_atomic = 0;
|
||||
|
||||
static void
|
||||
_test_parallel_randomly_toggle (void)
|
||||
{
|
||||
if (g_random_boolean ())
|
||||
g_atomic_int_or (¶llel_atomic, PARALLEL_TOGGLEMASK);
|
||||
else
|
||||
g_atomic_int_and (¶llel_atomic, ~PARALLEL_TOGGLEMASK);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_test_parallel_run (gpointer thread_arg)
|
||||
{
|
||||
const int IDX = GPOINTER_TO_INT (thread_arg);
|
||||
int count_self = 0;
|
||||
|
||||
g_atomic_int_inc (¶llel_thread_ready);
|
||||
while (g_atomic_int_get (¶llel_thread_ready) != PARALLEL_N_THREADS)
|
||||
g_usleep (10);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
gint val;
|
||||
gint val2;
|
||||
gint new_val;
|
||||
gint count_all;
|
||||
|
||||
_test_parallel_randomly_toggle ();
|
||||
|
||||
/* take a lock. */
|
||||
if (g_random_boolean ())
|
||||
{
|
||||
g_bit_lock (¶llel_atomic, PARALLEL_LOCKBIT);
|
||||
val = g_atomic_int_get (¶llel_atomic);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_bit_lock_and_get (¶llel_atomic, PARALLEL_LOCKBIT, &val);
|
||||
}
|
||||
|
||||
_test_parallel_randomly_toggle ();
|
||||
|
||||
/* the toggle bit is random. Clear it. */
|
||||
val &= ~PARALLEL_TOGGLEMASK;
|
||||
|
||||
/* these bits must be set. */
|
||||
g_assert_true (val & PARALLEL_LOCKMASK);
|
||||
g_assert_true (val & PARALLEL_SETMASK);
|
||||
|
||||
/* If we fetch again, we must get the same value. Nobody changes the
|
||||
* value while we hold the lock, except for the toggle bit. */
|
||||
val2 = g_atomic_int_get (¶llel_atomic);
|
||||
val2 &= ~PARALLEL_TOGGLEMASK;
|
||||
g_assert_cmpint (val, ==, val2);
|
||||
|
||||
count_all = (val & ~(PARALLEL_LOCKMASK | PARALLEL_SETMASK));
|
||||
|
||||
if (!TRUE)
|
||||
g_print ("th[%d] : self-count=%d, all-count=%d\n", IDX, count_self, count_all);
|
||||
|
||||
if ((g_random_int () % 5) == 0)
|
||||
{
|
||||
/* regular unlock without any changes. */
|
||||
g_bit_unlock (¶llel_atomic, PARALLEL_LOCKBIT);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* unlock-and-set with an increased counter. */
|
||||
new_val = MIN (count_all + 1, PARALLEL_MAX_COUNT_ALL);
|
||||
if (g_random_boolean ())
|
||||
new_val |= PARALLEL_SETMASK;
|
||||
if (g_random_boolean ())
|
||||
new_val |= PARALLEL_TOGGLEMASK;
|
||||
|
||||
g_bit_unlock_and_set (¶llel_atomic, PARALLEL_LOCKBIT, new_val, ((new_val & PARALLEL_SETMASK) && g_random_boolean ()) ? 0 : PARALLEL_SETMASK);
|
||||
|
||||
count_self++;
|
||||
|
||||
if (count_self < PARALLEL_MAX_COUNT_SELF)
|
||||
continue;
|
||||
if (count_all < PARALLEL_MAX_COUNT_ALL)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* To indicate success, we return a pointer to ¶llel_atomic. */
|
||||
return ¶llel_atomic;
|
||||
}
|
||||
|
||||
static void
|
||||
test_parallel (void)
|
||||
{
|
||||
GThread *threads[PARALLEL_N_THREADS];
|
||||
gpointer ptr;
|
||||
int i;
|
||||
gint val;
|
||||
|
||||
g_atomic_int_or (¶llel_atomic, PARALLEL_SETMASK);
|
||||
|
||||
for (i = 0; i < PARALLEL_N_THREADS; i++)
|
||||
{
|
||||
threads[i] = g_thread_new ("bitlock-parallel", _test_parallel_run, GINT_TO_POINTER (i));
|
||||
}
|
||||
|
||||
for (i = 0; i < PARALLEL_N_THREADS; i++)
|
||||
{
|
||||
ptr = g_thread_join (threads[i]);
|
||||
g_assert_true (ptr == ¶llel_atomic);
|
||||
|
||||
/* After we join the first thread, we already expect that the resulting
|
||||
* atomic's counter is set to PARALLEL_MAX_COUNT_ALL. This stays until
|
||||
* the end. */
|
||||
val = g_atomic_int_get (¶llel_atomic);
|
||||
if (i == PARALLEL_N_THREADS - 1)
|
||||
{
|
||||
/* at last, the atomic must be unlocked. */
|
||||
g_assert_true (!(val & PARALLEL_LOCKMASK));
|
||||
}
|
||||
val &= ~(PARALLEL_LOCKMASK | PARALLEL_TOGGLEMASK | PARALLEL_SETMASK);
|
||||
g_assert_cmpint (val, ==, PARALLEL_MAX_COUNT_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/bitlock/performance/uncontended", test_bitlocks);
|
||||
g_test_add_func ("/bitlock/performance/parallel", test_parallel);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user