Back to index

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