4 * Copyright (C) 2007 iptelorg GmbH
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * futex based lock (mutex) implementation (linux 2.6+ only)
20 * based on Ulrich Drepper implementation in "Futexes Are Tricky"
21 * (http://people.redhat.com/drepper/futex.pdf)
24 * void futex_get(futex_lock_t* lock); - mutex lock
25 * void futex_release(futex_lock_t* lock); - unlock
26 * int futex_try(futex_lock_t* lock); - tries to get lock, returns 0
27 * on success and !=0 on failure
35 * 2007-05-13 created by andrei
36 * 2007-06-12 added ADAPTIVE_WAIT busy waiting (andrei)
43 #include "atomic/atomic_common.h"
44 #include "atomic/atomic_native.h"
46 #ifdef HAVE_ASM_INLINE_ATOMIC_OPS
48 #include <sys/types.h> /* hack to workaround some type conflicts
49 between linux-libc-dev andlibc headers
50 in recent (6.08.2008) x86_64 debian sid
52 /* hack to work with old linux/futex.h versions, that depend on sched.h in
53 __KERNEL__ mode (futex.h < 2.6.20) */
54 #include <linux/types.h>
58 /* another hack this time for OpenSuse 10.2:
59 futex.h uses a __user attribute, which is defined in linux/compiler.h
60 However linux/compiler.h is not part of the kernel headers package in
61 most distributions. Instead they ship a modified linux/futex.h that does
62 not include <linux/compile.h> and does not user __user.
68 #include <linux/futex.h>
69 #include <sys/syscall.h>
71 #include "compiler_opt.h"
73 /* either syscall directly or #include <sys/linux/syscall.h> and use
74 * sys_futex directly */
75 #define sys_futex(addr, op, val, timeout, addr2, val3) \
76 syscall(__NR_futex , (addr), (op), (val), (timeout), (addr2), (val3))
78 typedef atomic_t futex_lock_t;
80 /* the mutex has 3 states: 0 - free/unlocked and nobody waiting
81 * 1 - locked and nobody waiting for it
82 * 2 - locked w/ 0 or more waiting processes/threads
85 inline static futex_lock_t* futex_init(futex_lock_t* lock)
92 inline static void futex_get(futex_lock_t* lock)
96 register int i=ADAPTIVE_WAIT_LOOPS;
101 v=atomic_cmpxchg(lock, 0, 1); /* lock if 0 */
102 if (likely(v==0)){ /* optimize for the uncontended case */
106 }else if (unlikely(v==2)){ /* if contended, optimize for the one waiter
108 /* waiting processes/threads => add ourselves to the queue */
110 sys_futex(&(lock)->val, FUTEX_WAIT, 2, 0, 0, 0);
111 v=atomic_get_and_set(lock, 2);
121 v=atomic_get_and_set(lock, 2);
123 sys_futex(&(lock)->val, FUTEX_WAIT, 2, 0, 0, 0);
124 v=atomic_get_and_set(lock, 2);
131 inline static void futex_release(futex_lock_t* lock)
136 v=atomic_get_and_set(lock, 0);
137 if (unlikely(v==2)){ /* optimize for the uncontended case */
138 sys_futex(&(lock)->val, FUTEX_WAKE, 1, 0, 0, 0);
143 static inline int futex_try(futex_lock_t* lock)
146 c=atomic_cmpxchg(lock, 0, 1);
153 #else /*HAVE_ASM_INLINE_ATOMIC_OPS*/
155 #endif /*HAVE_ASM_INLINE_ATOMIC_OPS*/
157 #endif /* _futexlocks_h*/