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 : : }