(root)/
glib-2.79.0/
glib/
tests/
1bit-mutex.c
       1  /*
       2   * Copyright © 2008 Ryan Lortie
       3   * Copyright © 2010 Codethink Limited
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This program is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * See the included COPYING file for more information.
      13   */
      14  
      15  #include "config.h"
      16  
      17  /* LOCKS should be more than the number of contention
      18   * counters in gthread.c in order to ensure we exercise
      19   * the case where they overlap.
      20   */
      21  #define LOCKS      48
      22  #define ITERATIONS 10000
      23  #define THREADS    100
      24  
      25  #include <glib.h>
      26  
      27  #if TEST_EMULATED_FUTEX
      28  
      29  #pragma GCC diagnostic push
      30  #pragma GCC diagnostic ignored "-Wmissing-prototypes"
      31  
      32    /* this is defined for the 1bit-mutex-emufutex test.
      33     *
      34     * we want to test the emulated futex even if futex(2) is available.
      35     */
      36  
      37    /* side-step some glib build stuff */
      38    #define GLIB_COMPILATION
      39  
      40    /* rebuild gbitlock.c without futex support,
      41       defining our own version of the g_bit_*lock symbols
      42     */
      43    #undef g_pointer_bit_lock
      44    #undef g_pointer_bit_trylock
      45    #undef g_pointer_bit_unlock
      46  
      47    #define g_bit_lock            _emufutex_g_bit_lock
      48    #define g_bit_trylock         _emufutex_g_bit_trylock
      49    #define g_bit_unlock          _emufutex_g_bit_unlock
      50    #define g_pointer_bit_lock    _emufutex_g_pointer_bit_lock
      51    #define g_pointer_bit_trylock _emufutex_g_pointer_bit_trylock
      52    #define g_pointer_bit_unlock  _emufutex_g_pointer_bit_unlock
      53  
      54    #define G_BIT_LOCK_FORCE_FUTEX_EMULATION
      55  
      56    #include <glib/gbitlock.c>
      57  
      58  #pragma GCC diagnostic pop
      59  #endif
      60  
      61  volatile GThread *owners[LOCKS];
      62  volatile gint     locks[LOCKS];
      63  volatile gpointer ptrs[LOCKS];
      64  volatile gint     bits[LOCKS];
      65  
      66  static void
      67  acquire (int      nr,
      68           gboolean use_pointers)
      69  {
      70    GThread *self;
      71  
      72    self = g_thread_self ();
      73  
      74    g_assert_cmpint (((gsize) ptrs) % sizeof(gint), ==, 0);
      75  
      76    if (!(use_pointers ?
      77            g_pointer_bit_trylock (&ptrs[nr], bits[nr])
      78          : g_bit_trylock (&locks[nr], bits[nr])))
      79      {
      80        if (g_test_verbose ())
      81          g_printerr ("thread %p going to block on lock %d\n", self, nr);
      82  
      83        if (use_pointers)
      84          g_pointer_bit_lock (&ptrs[nr], bits[nr]);
      85        else
      86          g_bit_lock (&locks[nr], bits[nr]);
      87      }
      88  
      89    g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
      90    owners[nr] = self;
      91  
      92    /* let some other threads try to ruin our day */
      93    g_thread_yield ();
      94    g_thread_yield ();
      95    g_thread_yield ();
      96  
      97    g_assert (owners[nr] == self);   /* hopefully this is still us... */
      98    owners[nr] = NULL;               /* make way for the next guy */
      99  
     100    if (use_pointers)
     101      g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
     102    else
     103      g_bit_unlock (&locks[nr], bits[nr]);
     104  }
     105  
     106  static gpointer
     107  thread_func (gpointer data)
     108  {
     109    gboolean use_pointers = GPOINTER_TO_INT (data);
     110    gint i;
     111    GRand *rand;
     112  
     113    rand = g_rand_new ();
     114  
     115    for (i = 0; i < ITERATIONS; i++)
     116      acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
     117  
     118    g_rand_free (rand);
     119  
     120    return NULL;
     121  }
     122  
     123  static void
     124  testcase (gconstpointer data)
     125  {
     126    gboolean use_pointers = GPOINTER_TO_INT (data);
     127    GThread *threads[THREADS];
     128    int i;
     129  
     130  #ifdef TEST_EMULATED_FUTEX
     131    #define SUFFIX "-emufutex"
     132  
     133    /* ensure that we are using the emulated futex by checking
     134     * (at compile-time) for the existence of 'g_futex_address_list'
     135     */
     136    g_assert (g_futex_address_list == NULL);
     137  #else
     138    #define SUFFIX ""
     139  #endif
     140  
     141    for (i = 0; i < LOCKS; i++)
     142      bits[i] = g_random_int () % 32;
     143  
     144    for (i = 0; i < THREADS; i++)
     145      threads[i] = g_thread_new ("foo", thread_func,
     146                                 GINT_TO_POINTER (use_pointers));
     147  
     148    for (i = 0; i < THREADS; i++)
     149      g_thread_join (threads[i]);
     150  
     151    for (i = 0; i < LOCKS; i++)
     152      {
     153        g_assert (owners[i] == NULL);
     154        g_assert (locks[i] == 0);
     155      }
     156  }
     157  
     158  int
     159  main (int argc, char **argv)
     160  {
     161    g_test_init (&argc, &argv, NULL);
     162  
     163    g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/int", (gpointer) 0, testcase);
     164    g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/pointer", (gpointer) 1, testcase);
     165  
     166    return g_test_run ();
     167  }