2 * Copyright © 2008 Ryan Lortie
3 * Copyright © 2010 Codethink Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the licence, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
25 #include <glib/gmessages.h>
26 #include <glib/gatomic.h>
27 #include <glib/gslist.h>
28 #include <glib/gthread.h>
29 #include <glib/gslice.h>
31 #include "gthreadprivate.h"
33 #ifdef G_BIT_LOCK_FORCE_FUTEX_EMULATION
38 static GMutex g_futex_mutex;
39 static GSList *g_futex_address_list = NULL;
44 * We have headers for futex(2) on the build machine. This does not
45 * imply that every system that ever runs the resulting glib will have
46 * kernel support for futex, but you'd have to have a pretty old
47 * kernel in order for that not to be the case.
49 * If anyone actually gets bit by this, please file a bug. :)
51 #include <linux/futex.h>
52 #include <sys/syscall.h>
57 * @address: a pointer to an integer
58 * @value: the value that should be at @address
60 * Atomically checks that the value stored at @address is equal to
61 * @value and then blocks. If the value stored at @address is not
62 * equal to @value then this function returns immediately.
64 * To unblock, call g_futex_wake() on @address.
66 * This call may spuriously unblock (for example, in response to the
67 * process receiving a signal) but this is not guaranteed. Unlike the
68 * Linux system call of a similar name, there is no guarantee that a
69 * waiting process will unblock due to a g_futex_wake() call in a
73 g_futex_wait (const volatile gint *address,
76 syscall (__NR_futex, address, (gsize) FUTEX_WAIT, (gsize) value, NULL);
81 * @address: a pointer to an integer
83 * Nominally, wakes one thread that is blocked in g_futex_wait() on
84 * @address (if any thread is currently waiting).
86 * As mentioned in the documention for g_futex_wait(), spurious
87 * wakeups may occur. As such, this call may result in more than one
88 * thread being woken up.
91 g_futex_wake (const volatile gint *address)
93 syscall (__NR_futex, address, (gsize) FUTEX_WAKE, (gsize) 1, NULL);
98 /* emulate futex(2) */
101 const volatile gint *address;
107 g_futex_find_address (const volatile gint *address)
111 for (node = g_futex_address_list; node; node = node->next)
113 WaitAddress *waiter = node->data;
115 if (waiter->address == address)
123 g_futex_wait (const volatile gint *address,
126 g_mutex_lock (&g_futex_mutex);
127 if G_LIKELY (g_atomic_int_get (address) == value)
131 if ((waiter = g_futex_find_address (address)) == NULL)
133 waiter = g_slice_new (WaitAddress);
134 waiter->address = address;
135 g_cond_init (&waiter->wait_queue);
136 waiter->ref_count = 0;
137 g_futex_address_list =
138 g_slist_prepend (g_futex_address_list, waiter);
142 g_cond_wait (&waiter->wait_queue, &g_futex_mutex);
144 if (!--waiter->ref_count)
146 g_futex_address_list =
147 g_slist_remove (g_futex_address_list, waiter);
148 g_cond_clear (&waiter->wait_queue);
149 g_slice_free (WaitAddress, waiter);
152 g_mutex_unlock (&g_futex_mutex);
156 g_futex_wake (const volatile gint *address)
160 /* need to lock here for two reasons:
161 * 1) need to acquire/release lock to ensure waiter is not in
162 * the process of registering a wait
163 * 2) need to -stay- locked until the end to ensure a wake()
164 * in another thread doesn't cause 'waiter' to stop existing
166 g_mutex_lock (&g_futex_mutex);
167 if ((waiter = g_futex_find_address (address)))
168 g_cond_signal (&waiter->wait_queue);
169 g_mutex_unlock (&g_futex_mutex);
173 #define CONTENTION_CLASSES 11
174 static volatile gint g_bit_lock_contended[CONTENTION_CLASSES];
176 #if (defined (i386) || defined (__amd64__))
177 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
178 #define USE_ASM_GOTO 1
184 * @address: a pointer to an integer
185 * @lock_bit: a bit value between 0 and 31
187 * Sets the indicated @lock_bit in @address. If the bit is already
188 * set, this call will block until g_bit_unlock() unsets the
191 * Attempting to lock on two different bits within the same integer is
192 * not supported and will very probably cause deadlocks.
194 * The value of the bit that is set is (1u << @bit). If @bit is not
195 * between 0 and 31 then the result is undefined.
197 * This function accesses @address atomically. All other accesses to
198 * @address must be atomic in order for this function to work
204 g_bit_lock (volatile gint *address,
209 __asm__ volatile goto ("lock bts %1, (%0)\n"
212 : "r" (address), "r" (lock_bit)
219 guint mask = 1u << lock_bit;
222 v = g_atomic_int_get (address);
225 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
227 g_atomic_int_add (&g_bit_lock_contended[class], +1);
228 g_futex_wait (address, v);
229 g_atomic_int_add (&g_bit_lock_contended[class], -1);
234 guint mask = 1u << lock_bit;
238 v = g_atomic_int_or (address, mask);
242 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
244 g_atomic_int_add (&g_bit_lock_contended[class], +1);
245 g_futex_wait (address, v);
246 g_atomic_int_add (&g_bit_lock_contended[class], -1);
255 * @address: a pointer to an integer
256 * @lock_bit: a bit value between 0 and 31
258 * Sets the indicated @lock_bit in @address, returning %TRUE if
259 * successful. If the bit is already set, returns %FALSE immediately.
261 * Attempting to lock on two different bits within the same integer is
264 * The value of the bit that is set is (1u << @bit). If @bit is not
265 * between 0 and 31 then the result is undefined.
267 * This function accesses @address atomically. All other accesses to
268 * @address must be atomic in order for this function to work
271 * Returns: %TRUE if the lock was acquired
276 g_bit_trylock (volatile gint *address,
282 __asm__ volatile ("lock bts %2, (%1)\n"
286 : "r" (address), "r" (lock_bit)
291 guint mask = 1u << lock_bit;
294 v = g_atomic_int_or (address, mask);
302 * @address: a pointer to an integer
303 * @lock_bit: a bit value between 0 and 31
305 * Clears the indicated @lock_bit in @address. If another thread is
306 * currently blocked in g_bit_lock() on this same bit then it will be
309 * This function accesses @address atomically. All other accesses to
310 * @address must be atomic in order for this function to work
316 g_bit_unlock (volatile gint *address,
320 asm volatile ("lock btr %1, (%0)"
322 : "r" (address), "r" (lock_bit)
325 guint mask = 1u << lock_bit;
327 g_atomic_int_and (address, ~mask);
331 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
333 if (g_atomic_int_get (&g_bit_lock_contended[class]))
334 g_futex_wake (address);
339 /* We emulate pointer-sized futex(2) because the kernel API only
342 * We assume that the 'interesting' part is always the lower order bits.
343 * This assumption holds because pointer bitlocks are restricted to
344 * using the low order bits of the pointer as the lock.
346 * On 32 bits, there is nothing to do since the pointer size is equal to
347 * the integer size. On little endian the lower-order bits don't move,
348 * so do nothing. Only on 64bit big endian do we need to do a bit of
349 * pointer arithmetic: the low order bits are shifted by 4 bytes. We
350 * have a helper function that always does the right thing here.
352 * Since we always consider the low-order bits of the integer value, a
353 * simple cast from (gsize) to (guint) always takes care of that.
355 * After that, pointer-sized futex becomes as simple as:
357 * g_futex_wait (g_futex_int_address (address), (guint) value);
361 * g_futex_wake (g_futex_int_address (int_address));
363 static const volatile gint *
364 g_futex_int_address (const volatile void *address)
366 const volatile gint *int_address = address;
368 /* this implementation makes these (reasonable) assumptions: */
369 G_STATIC_ASSERT (G_BYTE_ORDER == G_LITTLE_ENDIAN ||
370 (G_BYTE_ORDER == G_BIG_ENDIAN &&
372 (sizeof (gpointer) == 4 || sizeof (gpointer) == 8)));
374 #if G_BYTE_ORDER == G_BIG_ENDIAN && GLIB_SIZEOF_VOID_P == 8
382 * g_pointer_bit_lock:
383 * @address: a pointer to a #gpointer-sized value
384 * @lock_bit: a bit value between 0 and 31
386 * This is equivalent to g_bit_lock, but working on pointers (or other
387 * pointer-sized values).
389 * For portability reasons, you may only lock on the bottom 32 bits of
395 (g_pointer_bit_lock) (volatile void *address,
398 g_return_if_fail (lock_bit < 32);
403 asm volatile goto ("lock bts %1, (%0)\n"
406 : "r" (address), "r" ((gsize) lock_bit)
413 volatile gsize *pointer_address = address;
414 gsize mask = 1u << lock_bit;
417 v = (gsize) g_atomic_pointer_get (pointer_address);
420 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
422 g_atomic_int_add (&g_bit_lock_contended[class], +1);
423 g_futex_wait (g_futex_int_address (address), v);
424 g_atomic_int_add (&g_bit_lock_contended[class], -1);
429 volatile gsize *pointer_address = address;
430 gsize mask = 1u << lock_bit;
434 v = g_atomic_pointer_or (pointer_address, mask);
438 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
440 g_atomic_int_add (&g_bit_lock_contended[class], +1);
441 g_futex_wait (g_futex_int_address (address), (guint) v);
442 g_atomic_int_add (&g_bit_lock_contended[class], -1);
451 * g_pointer_bit_trylock:
452 * @address: a pointer to a #gpointer-sized value
453 * @lock_bit: a bit value between 0 and 31
455 * This is equivalent to g_bit_trylock, but working on pointers (or
456 * other pointer-sized values).
458 * For portability reasons, you may only lock on the bottom 32 bits of
461 * Returns: %TRUE if the lock was acquired
466 (g_pointer_bit_trylock) (volatile void *address,
469 g_return_val_if_fail (lock_bit < 32, FALSE);
475 asm volatile ("lock bts %2, (%1)\n"
479 : "r" (address), "r" ((gsize) lock_bit)
484 volatile gsize *pointer_address = address;
485 gsize mask = 1u << lock_bit;
488 g_return_val_if_fail (lock_bit < 32, FALSE);
490 v = g_atomic_pointer_or (pointer_address, mask);
498 * g_pointer_bit_unlock:
499 * @address: a pointer to a #gpointer-sized value
500 * @lock_bit: a bit value between 0 and 31
502 * This is equivalent to g_bit_unlock, but working on pointers (or other
503 * pointer-sized values).
505 * For portability reasons, you may only lock on the bottom 32 bits of
511 (g_pointer_bit_unlock) (volatile void *address,
514 g_return_if_fail (lock_bit < 32);
518 asm volatile ("lock btr %1, (%0)"
520 : "r" (address), "r" ((gsize) lock_bit)
523 volatile gsize *pointer_address = address;
524 gsize mask = 1u << lock_bit;
526 g_atomic_pointer_and (pointer_address, ~mask);
530 guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
531 if (g_atomic_int_get (&g_bit_lock_contended[class]))
532 g_futex_wake (g_futex_int_address (address));