mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-16 20:38:48 +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 <glib.h>
|
||||||
|
|
||||||
|
#include "gtestutils.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_bitlocks (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
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
g_test_init (&argc, &argv, NULL);
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
g_test_add_func ("/bitlock/performance/uncontended", test_bitlocks);
|
g_test_add_func ("/bitlock/performance/uncontended", test_bitlocks);
|
||||||
|
g_test_add_func ("/bitlock/performance/parallel", test_parallel);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user