LCOV - code coverage report
Current view: top level - glib/glib/tests - 1bit-mutex.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 47 48 97.9 %
Date: 2024-03-26 05:16:46 Functions: 4 4 100.0 %
Branches: 19 20 95.0 %

           Branch data     Line data    Source code
       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_lock_and_get
      45                 :            :   #undef g_pointer_bit_trylock
      46                 :            :   #undef g_pointer_bit_unlock
      47                 :            :   #undef g_pointer_bit_unlock_and_set
      48                 :            : 
      49                 :            :   #define g_bit_lock                    _emufutex_g_bit_lock
      50                 :            :   #define g_bit_trylock                 _emufutex_g_bit_trylock
      51                 :            :   #define g_bit_unlock                  _emufutex_g_bit_unlock
      52                 :            :   #define g_pointer_bit_lock            _emufutex_g_pointer_bit_lock
      53                 :            :   #define g_pointer_bit_lock_and_get    _emufutex_g_pointer_bit_lock_and_get
      54                 :            :   #define g_pointer_bit_trylock         _emufutex_g_pointer_bit_trylock
      55                 :            :   #define g_pointer_bit_unlock          _emufutex_g_pointer_bit_unlock
      56                 :            :   #define g_pointer_bit_lock_mask_ptr   _emufutex_g_pointer_bit_lock_mask_ptr
      57                 :            :   #define g_pointer_bit_unlock_and_set  _emufutex_g_pointer_bit_unlock_and_set
      58                 :            : 
      59                 :            :   #define G_BIT_LOCK_FORCE_FUTEX_EMULATION
      60                 :            : 
      61                 :            :   #include <glib/gbitlock.c>
      62                 :            : 
      63                 :            : #pragma GCC diagnostic pop
      64                 :            : #endif
      65                 :            : 
      66                 :            : volatile GThread *owners[LOCKS];
      67                 :            : volatile gint     locks[LOCKS];
      68                 :            : volatile gpointer ptrs[LOCKS];
      69                 :            : volatile gint     bits[LOCKS];
      70                 :            : 
      71                 :            : static void
      72                 :    4000000 : acquire (int      nr,
      73                 :            :          gboolean use_pointers)
      74                 :            : {
      75                 :            :   GThread *self;
      76                 :            : 
      77                 :    4000000 :   self = g_thread_self ();
      78                 :            : 
      79                 :    4000000 :   g_assert_cmpint (((gsize) ptrs) % sizeof(gint), ==, 0);
      80                 :            : 
      81   [ +  +  +  + ]:    8000000 :   if (!(use_pointers ?
      82                 :    2000000 :           g_pointer_bit_trylock (&ptrs[nr], bits[nr])
      83                 :    2000000 :         : g_bit_trylock (&locks[nr], bits[nr])))
      84                 :            :     {
      85         [ -  + ]:    1638681 :       if (g_test_verbose ())
      86                 :          0 :         g_printerr ("thread %p going to block on lock %d\n", self, nr);
      87                 :            : 
      88         [ +  + ]:    1638681 :       if (use_pointers)
      89                 :     790635 :         g_pointer_bit_lock (&ptrs[nr], bits[nr]);
      90                 :            :       else
      91                 :     848046 :         g_bit_lock (&locks[nr], bits[nr]);
      92                 :            :     }
      93                 :            : 
      94                 :    4000000 :   g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
      95                 :    4000000 :   owners[nr] = self;
      96                 :            : 
      97                 :            :   /* let some other threads try to ruin our day */
      98                 :    4000000 :   g_thread_yield ();
      99                 :    4000000 :   g_thread_yield ();
     100                 :    4000000 :   g_thread_yield ();
     101                 :            : 
     102                 :    4000000 :   g_assert (owners[nr] == self);   /* hopefully this is still us... */
     103                 :    4000000 :   owners[nr] = NULL;               /* make way for the next guy */
     104                 :            : 
     105         [ +  + ]:    4000000 :   if (use_pointers)
     106                 :    2000000 :     g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
     107                 :            :   else
     108                 :    2000000 :     g_bit_unlock (&locks[nr], bits[nr]);
     109                 :    4000000 : }
     110                 :            : 
     111                 :            : static gpointer
     112                 :        400 : thread_func (gpointer data)
     113                 :            : {
     114                 :        400 :   gboolean use_pointers = GPOINTER_TO_INT (data);
     115                 :            :   gint i;
     116                 :            :   GRand *rand;
     117                 :            : 
     118                 :        400 :   rand = g_rand_new ();
     119                 :            : 
     120         [ +  + ]:    4000400 :   for (i = 0; i < ITERATIONS; i++)
     121                 :    4000000 :     acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
     122                 :            : 
     123                 :        400 :   g_rand_free (rand);
     124                 :            : 
     125                 :        400 :   return NULL;
     126                 :            : }
     127                 :            : 
     128                 :            : static void
     129                 :          4 : testcase (gconstpointer data)
     130                 :            : {
     131                 :          4 :   gboolean use_pointers = GPOINTER_TO_INT (data);
     132                 :            :   GThread *threads[THREADS];
     133                 :            :   int i;
     134                 :            : 
     135                 :            : #ifdef TEST_EMULATED_FUTEX
     136                 :            :   #define SUFFIX "-emufutex"
     137                 :            : 
     138                 :            :   /* ensure that we are using the emulated futex by checking
     139                 :            :    * (at compile-time) for the existence of 'g_futex_address_list'
     140                 :            :    */
     141                 :          2 :   g_assert (g_futex_address_list == NULL);
     142                 :            : #else
     143                 :            :   #define SUFFIX ""
     144                 :            : #endif
     145                 :            : 
     146         [ +  + ]:        196 :   for (i = 0; i < LOCKS; i++)
     147                 :        192 :     bits[i] = g_random_int () % 32;
     148                 :            : 
     149         [ +  + ]:        404 :   for (i = 0; i < THREADS; i++)
     150                 :        400 :     threads[i] = g_thread_new ("foo", thread_func,
     151                 :        400 :                                GINT_TO_POINTER (use_pointers));
     152                 :            : 
     153         [ +  + ]:        404 :   for (i = 0; i < THREADS; i++)
     154                 :        400 :     g_thread_join (threads[i]);
     155                 :            : 
     156         [ +  + ]:        196 :   for (i = 0; i < LOCKS; i++)
     157                 :            :     {
     158                 :        192 :       g_assert (owners[i] == NULL);
     159                 :        192 :       g_assert (locks[i] == 0);
     160                 :            :     }
     161                 :          4 : }
     162                 :            : 
     163                 :            : int
     164                 :          2 : main (int argc, char **argv)
     165                 :            : {
     166                 :          2 :   g_test_init (&argc, &argv, NULL);
     167                 :            : 
     168                 :          2 :   g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/int", (gpointer) 0, testcase);
     169                 :          2 :   g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/pointer", (gpointer) 1, testcase);
     170                 :            : 
     171                 :          2 :   return g_test_run ();
     172                 :            : }

Generated by: LCOV version 1.14