Blame glib/tests/1bit-mutex.c

Packit Service d3d246
/*
Packit Service d3d246
 * Copyright © 2008 Ryan Lortie
Packit Service d3d246
 * Copyright © 2010 Codethink Limited
Packit Service d3d246
 *
Packit Service d3d246
 * This program is free software; you can redistribute it and/or
Packit Service d3d246
 * modify it under the terms of the GNU Lesser General Public
Packit Service d3d246
 * License as published by the Free Software Foundation; either
Packit Service d3d246
 * version 2.1 of the License, or (at your option) any later version.
Packit Service d3d246
 *
Packit Service d3d246
 * See the included COPYING file for more information.
Packit Service d3d246
 */
Packit Service d3d246
Packit Service d3d246
#include "config.h"
Packit Service d3d246
Packit Service d3d246
/* LOCKS should be more than the number of contention
Packit Service d3d246
 * counters in gthread.c in order to ensure we exercise
Packit Service d3d246
 * the case where they overlap.
Packit Service d3d246
 */
Packit Service d3d246
#define LOCKS      48
Packit Service d3d246
#define ITERATIONS 10000
Packit Service d3d246
#define THREADS    100
Packit Service d3d246
Packit Service d3d246
#include <glib.h>
Packit Service d3d246
Packit Service d3d246
#if TEST_EMULATED_FUTEX
Packit Service d3d246
Packit Service d3d246
#pragma GCC diagnostic push
Packit Service d3d246
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
Packit Service d3d246
Packit Service d3d246
  /* this is defined for the 1bit-mutex-emufutex test.
Packit Service d3d246
   *
Packit Service d3d246
   * we want to test the emulated futex even if futex(2) is available.
Packit Service d3d246
   */
Packit Service d3d246
Packit Service d3d246
  /* side-step some glib build stuff */
Packit Service d3d246
  #define GLIB_COMPILATION
Packit Service d3d246
Packit Service d3d246
  /* rebuild gbitlock.c without futex support,
Packit Service d3d246
     defining our own version of the g_bit_*lock symbols
Packit Service d3d246
   */
Packit Service d3d246
  #undef g_pointer_bit_lock
Packit Service d3d246
  #undef g_pointer_bit_trylock
Packit Service d3d246
  #undef g_pointer_bit_unlock
Packit Service d3d246
Packit Service d3d246
  #define g_bit_lock            _emufutex_g_bit_lock
Packit Service d3d246
  #define g_bit_trylock         _emufutex_g_bit_trylock
Packit Service d3d246
  #define g_bit_unlock          _emufutex_g_bit_unlock
Packit Service d3d246
  #define g_pointer_bit_lock    _emufutex_g_pointer_bit_lock
Packit Service d3d246
  #define g_pointer_bit_trylock _emufutex_g_pointer_bit_trylock
Packit Service d3d246
  #define g_pointer_bit_unlock  _emufutex_g_pointer_bit_unlock
Packit Service d3d246
Packit Service d3d246
  #define G_BIT_LOCK_FORCE_FUTEX_EMULATION
Packit Service d3d246
Packit Service d3d246
  #include <glib/gbitlock.c>
Packit Service d3d246
Packit Service d3d246
#pragma GCC diagnostic pop
Packit Service d3d246
#endif
Packit Service d3d246
Packit Service d3d246
volatile GThread *owners[LOCKS];
Packit Service d3d246
volatile gint     locks[LOCKS];
Packit Service d3d246
volatile gpointer ptrs[LOCKS];
Packit Service d3d246
volatile gint     bits[LOCKS];
Packit Service d3d246
Packit Service d3d246
static void
Packit Service d3d246
acquire (int      nr,
Packit Service d3d246
         gboolean use_pointers)
Packit Service d3d246
{
Packit Service d3d246
  GThread *self;
Packit Service d3d246
Packit Service d3d246
  self = g_thread_self ();
Packit Service d3d246
Packit Service d3d246
  g_assert_cmpint (((gsize) ptrs) % sizeof(gint), ==, 0);
Packit Service d3d246
Packit Service d3d246
  if (!(use_pointers ?
Packit Service d3d246
          g_pointer_bit_trylock (&ptrs[nr], bits[nr])
Packit Service d3d246
        : g_bit_trylock (&locks[nr], bits[nr])))
Packit Service d3d246
    {
Packit Service d3d246
      if (g_test_verbose ())
Packit Service d3d246
        g_printerr ("thread %p going to block on lock %d\n", self, nr);
Packit Service d3d246
Packit Service d3d246
      if (use_pointers)
Packit Service d3d246
        g_pointer_bit_lock (&ptrs[nr], bits[nr]);
Packit Service d3d246
      else
Packit Service d3d246
        g_bit_lock (&locks[nr], bits[nr]);
Packit Service d3d246
    }
Packit Service d3d246
Packit Service d3d246
  g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
Packit Service d3d246
  owners[nr] = self;
Packit Service d3d246
Packit Service d3d246
  /* let some other threads try to ruin our day */
Packit Service d3d246
  g_thread_yield ();
Packit Service d3d246
  g_thread_yield ();
Packit Service d3d246
  g_thread_yield ();
Packit Service d3d246
Packit Service d3d246
  g_assert (owners[nr] == self);   /* hopefully this is still us... */
Packit Service d3d246
  owners[nr] = NULL;               /* make way for the next guy */
Packit Service d3d246
Packit Service d3d246
  if (use_pointers)
Packit Service d3d246
    g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
Packit Service d3d246
  else
Packit Service d3d246
    g_bit_unlock (&locks[nr], bits[nr]);
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static gpointer
Packit Service d3d246
thread_func (gpointer data)
Packit Service d3d246
{
Packit Service d3d246
  gboolean use_pointers = GPOINTER_TO_INT (data);
Packit Service d3d246
  gint i;
Packit Service d3d246
  GRand *rand;
Packit Service d3d246
Packit Service d3d246
  rand = g_rand_new ();
Packit Service d3d246
Packit Service d3d246
  for (i = 0; i < ITERATIONS; i++)
Packit Service d3d246
    acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
Packit Service d3d246
Packit Service d3d246
  g_rand_free (rand);
Packit Service d3d246
Packit Service d3d246
  return NULL;
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
static void
Packit Service d3d246
testcase (gconstpointer data)
Packit Service d3d246
{
Packit Service d3d246
  gboolean use_pointers = GPOINTER_TO_INT (data);
Packit Service d3d246
  GThread *threads[THREADS];
Packit Service d3d246
  int i;
Packit Service d3d246
Packit Service d3d246
#ifdef TEST_EMULATED_FUTEX
Packit Service d3d246
  #define SUFFIX "-emufutex"
Packit Service d3d246
Packit Service d3d246
  /* ensure that we are using the emulated futex by checking
Packit Service d3d246
   * (at compile-time) for the existance of 'g_futex_address_list'
Packit Service d3d246
   */
Packit Service d3d246
  g_assert (g_futex_address_list == NULL);
Packit Service d3d246
#else
Packit Service d3d246
  #define SUFFIX ""
Packit Service d3d246
#endif
Packit Service d3d246
Packit Service d3d246
  for (i = 0; i < LOCKS; i++)
Packit Service d3d246
    bits[i] = g_random_int () % 32;
Packit Service d3d246
Packit Service d3d246
  for (i = 0; i < THREADS; i++)
Packit Service d3d246
    threads[i] = g_thread_new ("foo", thread_func,
Packit Service d3d246
                               GINT_TO_POINTER (use_pointers));
Packit Service d3d246
Packit Service d3d246
  for (i = 0; i < THREADS; i++)
Packit Service d3d246
    g_thread_join (threads[i]);
Packit Service d3d246
Packit Service d3d246
  for (i = 0; i < LOCKS; i++)
Packit Service d3d246
    {
Packit Service d3d246
      g_assert (owners[i] == NULL);
Packit Service d3d246
      g_assert (locks[i] == 0);
Packit Service d3d246
    }
Packit Service d3d246
}
Packit Service d3d246
Packit Service d3d246
int
Packit Service d3d246
main (int argc, char **argv)
Packit Service d3d246
{
Packit Service d3d246
  g_test_init (&argc, &argv, NULL);
Packit Service d3d246
Packit Service d3d246
  g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/int", (gpointer) 0, testcase);
Packit Service d3d246
  g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/pointer", (gpointer) 1, testcase);
Packit Service d3d246
Packit Service d3d246
  return g_test_run ();
Packit Service d3d246
}