Back to index

glibc  2.9
lowlevellock.h
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Libr      \ary; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #ifndef _LOWLEVELLOCK_H
00020 #define _LOWLEVELLOCK_H     1
00021 
00022 #include <time.h>
00023 #include <sys/param.h>
00024 #include <bits/pthreadtypes.h>
00025 #include <atomic.h>
00026 #include <sysdep.h>
00027 #include <kernel-features.h>
00028 
00029 
00030 #define __NR_futex          394
00031 #define FUTEX_WAIT          0
00032 #define FUTEX_WAKE          1
00033 #define FUTEX_REQUEUE              3
00034 #define FUTEX_CMP_REQUEUE   4
00035 #define FUTEX_WAKE_OP              5
00036 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
00037 #define FUTEX_LOCK_PI              6
00038 #define FUTEX_UNLOCK_PI            7
00039 #define FUTEX_TRYLOCK_PI    8
00040 #define FUTEX_PRIVATE_FLAG  128
00041 
00042 /* Values for 'private' parameter of locking macros.  Yes, the
00043    definition seems to be backwards.  But it is not.  The bit will be
00044    reversed before passing to the system call.  */
00045 #define LLL_PRIVATE  0
00046 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
00047 
00048 
00049 #if !defined NOT_IN_libc || defined IS_IN_rtld
00050 /* In libc.so or ld.so all futexes are private.  */
00051 # ifdef __ASSUME_PRIVATE_FUTEX
00052 #  define __lll_private_flag(fl, private) \
00053   ((fl) | FUTEX_PRIVATE_FLAG)
00054 # else
00055 #  define __lll_private_flag(fl, private) \
00056   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
00057 # endif
00058 #else
00059 # ifdef __ASSUME_PRIVATE_FUTEX
00060 #  define __lll_private_flag(fl, private) \
00061   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
00062 # else
00063 #  define __lll_private_flag(fl, private) \
00064   (__builtin_constant_p (private)                                    \
00065    ? ((private) == 0                                                 \
00066       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))          \
00067       : (fl))                                                        \
00068    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                              \
00069              & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
00070 # endif             
00071 #endif
00072 
00073 
00074 #define lll_futex_wait(futexp, val, private) \
00075   lll_futex_timed_wait (futexp, val, NULL, private)
00076 
00077 #define lll_futex_timed_wait(futexp, val, timespec, private) \
00078   ({                                                                 \
00079     INTERNAL_SYSCALL_DECL (__err);                                   \
00080     long int __ret;                                                  \
00081     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                    \
00082                            __lll_private_flag (FUTEX_WAIT, private),        \
00083                            (val), (timespec));                       \
00084     INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;                \
00085   })
00086 
00087 #define lll_futex_wake(futexp, nr, private) \
00088   ({                                                                 \
00089     INTERNAL_SYSCALL_DECL (__err);                                   \
00090     long int __ret;                                                  \
00091     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                    \
00092                            __lll_private_flag (FUTEX_WAKE, private),        \
00093                            (nr), 0);                                        \
00094     INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;                \
00095   })
00096 
00097 #define lll_robust_dead(futexv, private) \
00098   do                                                                 \
00099     {                                                                \
00100       int *__futexp = &(futexv);                                     \
00101       atomic_or (__futexp, FUTEX_OWNER_DIED);                               \
00102       lll_futex_wake (__futexp, 1, private);                                \
00103     }                                                                \
00104   while (0)
00105 
00106 /* Returns non-zero if error happened, zero if success.  */
00107 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
00108   ({                                                                 \
00109     INTERNAL_SYSCALL_DECL (__err);                                   \
00110     long int __ret;                                                  \
00111     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00112                            __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
00113                            (nr_wake), (nr_move), (mutex), (val));           \
00114     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00115   })
00116 
00117 /* Returns non-zero if error happened, zero if success.  */
00118 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
00119   ({                                                                 \
00120     INTERNAL_SYSCALL_DECL (__err);                                   \
00121     long int __ret;                                                  \
00122     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00123                            __lll_private_flag (FUTEX_WAKE_OP, private),    \
00124                            (nr_wake), (nr_wake2), (futexp2),                \
00125                            FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                  \
00126     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00127   })
00128 
00129 
00130 
00131 
00132 static inline int __attribute__((always_inline))
00133 __lll_trylock(int *futex)
00134 {
00135   return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
00136 }
00137 #define lll_trylock(lock)   __lll_trylock (&(lock))
00138 
00139 
00140 static inline int __attribute__((always_inline))
00141 __lll_cond_trylock(int *futex)
00142 {
00143   return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
00144 }
00145 #define lll_cond_trylock(lock)     __lll_cond_trylock (&(lock))
00146 
00147 
00148 static inline int __attribute__((always_inline))
00149 __lll_robust_trylock(int *futex, int id)
00150 {
00151   return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
00152 }
00153 #define lll_robust_trylock(lock, id) \
00154   __lll_robust_trylock (&(lock), id)
00155 
00156 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00157 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00158 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00159 
00160 static inline void __attribute__((always_inline))
00161 __lll_lock(int *futex, int private)
00162 {
00163   if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
00164     {
00165       if (__builtin_constant_p (private) && private == LLL_PRIVATE)
00166        __lll_lock_wait_private (futex);
00167       else
00168        __lll_lock_wait (futex, private);
00169     }
00170 }
00171 #define lll_lock(futex, private) __lll_lock (&(futex), private)
00172 
00173 
00174 static inline int __attribute__ ((always_inline))
00175 __lll_robust_lock (int *futex, int id, int private)
00176 {
00177   int result = 0;
00178   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
00179     result = __lll_robust_lock_wait (futex, private);
00180   return result;
00181 }
00182 #define lll_robust_lock(futex, id, private) \
00183   __lll_robust_lock (&(futex), id, private)
00184 
00185 
00186 static inline void __attribute__ ((always_inline))
00187 __lll_cond_lock (int *futex, int private)
00188 {
00189   if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
00190     __lll_lock_wait (futex, private);
00191 }
00192 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00193 
00194 
00195 #define lll_robust_cond_lock(futex, id, private) \
00196   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
00197 
00198 
00199 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
00200                              int private) attribute_hidden;
00201 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
00202                                    int private) attribute_hidden;
00203 
00204 static inline int __attribute__ ((always_inline))
00205 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
00206 {
00207   int result = 0;
00208   if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
00209     result = __lll_timedlock_wait (futex, abstime, private);
00210   return result;
00211 }
00212 #define lll_timedlock(futex, abstime, private) \
00213   __lll_timedlock (&(futex), abstime, private)
00214 
00215 
00216 static inline int __attribute__ ((always_inline))
00217 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
00218                      int id, int private)
00219 {
00220   int result = 0;
00221   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
00222     result = __lll_robust_timedlock_wait (futex, abstime, private);
00223   return result;
00224 }
00225 #define lll_robust_timedlock(futex, abstime, id, private) \
00226   __lll_robust_timedlock (&(futex), abstime, id, private)
00227 
00228 
00229 #define __lll_unlock(futex, private) \
00230   (void)                                                \
00231     ({ int *__futex = (futex);                                 \
00232        int __oldval = atomic_exchange_rel (__futex, 0);        \
00233        if (__builtin_expect (__oldval > 1, 0))                 \
00234         lll_futex_wake (__futex, 1, private);                  \
00235     })
00236 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
00237 
00238 
00239 #define __lll_robust_unlock(futex, private) \
00240   (void)                                                \
00241     ({ int *__futex = (futex);                                 \
00242        int __oldval = atomic_exchange_rel (__futex, 0);        \
00243        if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))     \
00244         lll_futex_wake (__futex, 1, private);                  \
00245     })
00246 #define lll_robust_unlock(futex, private) \
00247   __lll_robust_unlock(&(futex), private)
00248 
00249 
00250 #define lll_islocked(futex) \
00251   (futex != 0)
00252 
00253 /* Initializers for lock.  */
00254 #define LLL_LOCK_INITIALIZER              (0)
00255 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00256 
00257 
00258 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
00259    wakeup when the clone terminates.  The memory location contains the
00260    thread ID while the clone is running and is reset to zero
00261    afterwards.       */
00262 #define lll_wait_tid(tid) \
00263   do {                                           \
00264     __typeof (tid) __tid;                        \
00265     while ((__tid = (tid)) != 0)                 \
00266       lll_futex_wait (&(tid), __tid, LLL_SHARED);       \
00267   } while (0)
00268 
00269 extern int __lll_timedwait_tid (int *, const struct timespec *)
00270      attribute_hidden;
00271 
00272 #define lll_timedwait_tid(tid, abstime) \
00273   ({                                             \
00274     int __res = 0;                               \
00275     if ((tid) != 0)                              \
00276       __res = __lll_timedwait_tid (&(tid), (abstime));  \
00277     __res;                                       \
00278   })
00279 
00280 #endif /* lowlevellock.h */