Back to index

glibc  2.9
lowlevellock.h
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004, 2005, 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 Library; 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 <sysdep.h>
00026 #include <atomic.h>
00027 #include <kernel-features.h>       /* Need __ASSUME_PRIVATE_FUTEX.  */
00028 #include <tls.h>            /* Need THREAD_*, and header.*.  */
00029 
00030 /* HPPA only has one atomic read and modify memory operation,
00031    load and clear, so hppa uses a kernel helper routine to implement
00032    compare_and_exchange. See atomic.h for the userspace calling
00033    sequence.  */
00034 
00035 #define FUTEX_WAIT          0
00036 #define FUTEX_WAKE          1
00037 #define FUTEX_REQUEUE              3
00038 #define FUTEX_CMP_REQUEUE   4
00039 #define FUTEX_WAKE_OP              5
00040 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
00041 #define FUTEX_LOCK_PI              6
00042 #define FUTEX_UNLOCK_PI            7
00043 #define FUTEX_TRYLOCK_PI    8
00044 #define FUTEX_PRIVATE_FLAG  128
00045 
00046 /* Bits used in robust mutex implementation.  */
00047 #define FUTEX_WAITERS              0x80000000
00048 #define FUTEX_OWNER_DIED    0x40000000
00049 #define FUTEX_TID_MASK             0x3fffffff
00050 
00051 /* Values for 'private' parameter of locking macros.  Yes, the
00052    definition seems to be backwards.  But it is not.  The bit will be
00053    reversed before passing to the system call.  */
00054 #define LLL_PRIVATE  0
00055 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
00056 
00057 /* Initialize locks to zero.  */
00058 #define LLL_MUTEX_LOCK_INITIALIZER (0)
00059 
00060 #if !defined NOT_IN_libc || defined IS_IN_rtld
00061 /* In libc.so or ld.so all futexes are private.  */
00062 # ifdef __ASSUME_PRIVATE_FUTEX
00063 #  define __lll_private_flag(fl, private) \
00064   ((fl) | FUTEX_PRIVATE_FLAG)
00065 # else
00066 #  define __lll_private_flag(fl, private) \
00067   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
00068 # endif
00069 #else
00070 # ifdef __ASSUME_PRIVATE_FUTEX
00071 #  define __lll_private_flag(fl, private) \
00072   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
00073 # else
00074 #  define __lll_private_flag(fl, private) \
00075   (__builtin_constant_p (private)                                    \
00076    ? ((private) == 0                                                 \
00077       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))          \
00078       : (fl))                                                        \
00079    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                              \
00080              & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
00081 # endif             
00082 #endif
00083 
00084 /* Type for lock object.  */
00085 typedef int lll_lock_t;
00086 
00087 #define lll_futex_wait(futexp, val, private) \
00088   lll_futex_timed_wait (futexp, val, 0, private)
00089 
00090 #define lll_futex_timed_wait(futexp, val, timespec, private) \
00091   ({                                                           \
00092     INTERNAL_SYSCALL_DECL (__err);                             \
00093     long int __ret;                                            \
00094     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),              \
00095                            __lll_private_flag (FUTEX_WAIT, private),  \
00096                            (val), (timespec));                 \
00097     __ret;                                                     \
00098   })
00099 
00100 #define lll_futex_wake(futexp, nr, private) \
00101   ({                                                           \
00102     INTERNAL_SYSCALL_DECL (__err);                             \
00103     long int __ret;                                            \
00104     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),              \
00105                            __lll_private_flag (FUTEX_WAKE, private),  \
00106                            (nr), 0);                                  \
00107     __ret;                                                     \
00108   })
00109 
00110 #define lll_private_futex_wait(futex, val) \
00111   lll_private_futex_timed_wait (futex, val, NULL)
00112 
00113 #ifdef __ASSUME_PRIVATE_FUTEX
00114 # define lll_private_futex_timed_wait(futexp, val, timespec) \
00115   ({                                                                 \
00116     INTERNAL_SYSCALL_DECL (__err);                                   \
00117     long int __ret;                                                  \
00118     __ret = INTERNAL_SYSCALL (futex, __err, 4,                              \
00119                            (futexp), FUTEX_WAIT | FUTEX_PRIVATE_FLAG,      \
00120                            (val), (timespec));                       \
00121     __ret;                                                           \
00122   })
00123 
00124 # define lll_private_futex_wake(futexp, nr) \
00125   ({                                                                 \
00126     INTERNAL_SYSCALL_DECL (__err);                                   \
00127     long int __ret;                                                  \
00128     __ret = INTERNAL_SYSCALL (futex, __err, 4,                              \
00129                            (futexp), FUTEX_WAKE | FUTEX_PRIVATE_FLAG,      \
00130                            (nr), 0);                                        \
00131     __ret;                                                           \
00132   })
00133 
00134 #else
00135 
00136 # define lll_private_futex_timed_wait(futexp, val, timespec) \
00137   ({                                                                 \
00138     INTERNAL_SYSCALL_DECL (__err);                                   \
00139     long int __ret, __op;                                            \
00140     __op = FUTEX_WAIT | THREAD_GETMEM (THREAD_SELF, header.private_futex);    \
00141     __ret = INTERNAL_SYSCALL (futex, __err, 4,                              \
00142                            (futexp), __op, (val), (timespec));       \
00143     __ret;                                                           \
00144   })
00145 
00146 # define lll_private_futex_wake(futexp, nr) \
00147   ({                                                                 \
00148     INTERNAL_SYSCALL_DECL (__err);                                   \
00149     long int __ret, __op;                                            \
00150     __op = FUTEX_WAKE | THREAD_GETMEM (THREAD_SELF, header.private_futex);    \
00151     __ret = INTERNAL_SYSCALL (futex, __err, 4,                              \
00152                            (futexp), __op, (nr), 0);                        \
00153     __ret;                                                           \
00154   })
00155 #endif
00156 
00157 /* Returns non-zero if error happened, zero if success.  */
00158 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
00159   ({                                                                 \
00160     INTERNAL_SYSCALL_DECL (__err);                                   \
00161     long int __ret;                                                  \
00162     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00163                            __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
00164                            (nr_wake), (nr_move), (mutex), (val));           \
00165     __ret;                                                           \
00166   })
00167 
00168 #define lll_robust_dead(futexv, private) \
00169   do                                                                 \
00170     {                                                                \
00171       int *__futexp = &(futexv);                                     \
00172       atomic_or (__futexp, FUTEX_OWNER_DIED);                               \
00173       lll_futex_wake (__futexp, 1, private);                                \
00174     }                                                                \
00175   while (0)
00176 
00177 /* Returns non-zero if error happened, zero if success.  */
00178 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
00179   ({                                                              \
00180     INTERNAL_SYSCALL_DECL (__err);                                \
00181     long int __ret;                                               \
00182     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                 \
00183                            __lll_private_flag (FUTEX_WAKE_OP, private), \
00184                            (nr_wake), (nr_wake2), (futexp2),             \
00185                            FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);               \
00186     __ret;                                                        \
00187   })
00188 
00189 static inline int
00190 __attribute__ ((always_inline))
00191 __lll_robust_trylock (int *futex, int id)
00192 {
00193   return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
00194 }
00195 #define lll_robust_trylock(futex, id) \
00196   __lll_robust_trylock (&(futex), id)
00197 
00198 static inline int
00199 __attribute__ ((always_inline))
00200 __lll_cond_trylock (int *futex)
00201 {
00202   return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
00203 }
00204 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
00205 
00206 static inline int
00207 __attribute__ ((always_inline))
00208 __lll_trylock (int *futex)
00209 {
00210   return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
00211 }
00212 #define lll_trylock(futex) __lll_trylock (&(futex))
00213 
00214 extern void __lll_lock_wait (lll_lock_t *futex, int private) attribute_hidden;
00215 extern void __lll_lock_wait_private (lll_lock_t *futex) attribute_hidden;
00216 
00217 static inline void __attribute__((always_inline))
00218 __lll_mutex_lock(lll_lock_t *futex, int private)
00219 {
00220   int val = atomic_compare_and_exchange_val_acq (futex, 1, 0);
00221 
00222   if (__builtin_expect (val != 0, 0))
00223     {
00224       if (__builtin_constant_p (private) && private == LLL_PRIVATE)
00225        __lll_lock_wait_private (futex);
00226       else
00227        __lll_lock_wait (futex, private);
00228     }
00229 }
00230 #define lll_mutex_lock(futex, private) __lll_mutex_lock (&(futex), private)
00231 #define lll_lock(lock, private)    lll_mutex_lock (lock, private)
00232 
00233 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00234 
00235 static inline int
00236 __attribute__ ((always_inline))
00237 __lll_robust_lock (int *futex, int id, int private)
00238 {
00239   int result = 0;
00240   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
00241     result = __lll_robust_lock_wait (futex, private);
00242   return result;
00243 }
00244 #define lll_robust_lock(futex, id, private) \
00245   __lll_robust_lock (&(futex), id, private)
00246 
00247 #define lll_robust_cond_lock(futex, id, private) \
00248   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
00249 
00250 static inline void
00251 __attribute__ ((always_inline))
00252 __lll_cond_lock (int *futex, int private)
00253 {
00254   int val = atomic_compare_and_exchange_val_acq (futex, 2, 0);
00255 
00256   if (__builtin_expect (val != 0, 0))
00257     __lll_lock_wait (futex, private);
00258 }
00259 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00260 
00261 extern int __lll_timedlock_wait (lll_lock_t *futex, const struct timespec *, 
00262                              int private) attribute_hidden;
00263 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
00264                              int private) attribute_hidden;
00265 
00266 static inline int
00267 __attribute__ ((always_inline))
00268 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
00269 {
00270   int val = atomic_compare_and_exchange_val_acq (futex, 1, 0);
00271   int result = 0;
00272 
00273   if (__builtin_expect (val != 0, 0))
00274     result = __lll_timedlock_wait (futex, abstime, private);
00275   return result;
00276 }
00277 #define lll_timedlock(futex, abstime, private) \
00278   __lll_timedlock (&(futex), abstime, private)
00279 
00280 static inline int __attribute__ ((always_inline))
00281 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
00282                            int id, int private)
00283 {
00284   int result = 0;
00285   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
00286     result = __lll_robust_timedlock_wait (futex, abstime, private);
00287   return result;
00288 }
00289 #define lll_robust_timedlock(futex, abstime, id, private) \
00290   __lll_robust_timedlock (&(futex), abstime, id, private)
00291 
00292 #define __lll_unlock(futex, private) \
00293   (void)                                  \
00294   ({ int val = atomic_exchange_rel (futex, 0);  \
00295      if (__builtin_expect (val > 1, 0))         \
00296        lll_futex_wake (futex, 1, private);      \
00297   })
00298 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
00299 
00300 #define  __lll_robust_unlock(futex,private) \
00301   (void)                                               \
00302     ({ int val = atomic_exchange_rel (futex, 0);       \
00303        if (__builtin_expect (val & FUTEX_WAITERS, 0))  \
00304          lll_futex_wake (futex, 1, private);           \
00305     })
00306 #define lll_robust_unlock(futex, private) \
00307   __lll_robust_unlock(&(futex), private)
00308 
00309 #define lll_islocked(futex) \
00310   (futex != 0)
00311 
00312 /* Our internal lock implementation is identical to the binary-compatible
00313    mutex implementation.  */
00314 #define LLL_LOCK_INITIALIZER (0)
00315 #define LLL_LOCK_INITIALIZER_CONST (0)
00316 #define LLL_LOCK_INITIALIZER_LOCKED (1)
00317 
00318 #define THREAD_INIT_LOCK(PD, LOCK) \
00319   (PD)->LOCK = LLL_LOCK_INITIALIZER
00320 
00321 extern int lll_unlock_wake_cb (lll_lock_t *__futex) attribute_hidden;
00322 
00323 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
00324    wakeup when the clone terminates.  The memory location contains the
00325    thread ID while the clone is running and is reset to zero
00326    afterwards.       */
00327 #define lll_wait_tid(tid) \
00328   do                                             \
00329     {                                            \
00330       __typeof (tid) __tid;                      \
00331       while ((__tid = (tid)) != 0)               \
00332         lll_futex_wait (&(tid), __tid, LLL_SHARED);     \
00333     }                                            \
00334   while (0)
00335 
00336 extern int __lll_timedwait_tid (int *, const struct timespec *)
00337      attribute_hidden;
00338 
00339 #define lll_timedwait_tid(tid, abstime) \
00340   ({                                             \
00341     int __res = 0;                               \
00342     if ((tid) != 0)                              \
00343       __res = __lll_timedwait_tid (&(tid), (abstime));  \
00344     __res;                                       \
00345   })
00346 
00347 #endif /* lowlevellock.h */