Back to index

glibc  2.9
lowlevellock.h
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004, 2005, 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 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 <atomic.h>
00026 #include <sysdep.h>
00027 #include <kernel-features.h>
00028 
00029 #define FUTEX_WAIT          0
00030 #define FUTEX_WAKE          1
00031 #define FUTEX_REQUEUE              3
00032 #define FUTEX_CMP_REQUEUE   4
00033 #define FUTEX_WAKE_OP              5
00034 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
00035 #define FUTEX_LOCK_PI              6
00036 #define FUTEX_UNLOCK_PI            7
00037 #define FUTEX_TRYLOCK_PI    8
00038 #define FUTEX_PRIVATE_FLAG  128
00039 
00040 /* Values for 'private' parameter of locking macros.  Yes, the
00041    definition seems to be backwards.  But it is not.  The bit will be
00042    reversed before passing to the system call.  */
00043 #define LLL_PRIVATE  0
00044 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
00045 
00046 
00047 #if !defined NOT_IN_libc || defined IS_IN_rtld
00048 /* In libc.so or ld.so all futexes are private.  */
00049 # ifdef __ASSUME_PRIVATE_FUTEX
00050 #  define __lll_private_flag(fl, private) \
00051   ((fl) | FUTEX_PRIVATE_FLAG)
00052 # else
00053 #  define __lll_private_flag(fl, private) \
00054   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
00055 # endif
00056 #else
00057 # ifdef __ASSUME_PRIVATE_FUTEX
00058 #  define __lll_private_flag(fl, private) \
00059   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
00060 # else
00061 #  define __lll_private_flag(fl, private) \
00062   (__builtin_constant_p (private)                                    \
00063    ? ((private) == 0                                                 \
00064       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))          \
00065       : (fl))                                                        \
00066    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                              \
00067              & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
00068 # endif             
00069 #endif
00070 
00071 
00072 #define lll_futex_wait(futexp, val, private) \
00073   lll_futex_timed_wait(futexp, val, NULL, private)
00074 
00075 #define lll_futex_timed_wait(futexp, val, timespec, private) \
00076   ({                                                                 \
00077     INTERNAL_SYSCALL_DECL (__err);                                   \
00078     long int __ret;                                                  \
00079     __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),                    \
00080                            __lll_private_flag (FUTEX_WAIT, private),        \
00081                            (val), (timespec));                       \
00082     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;               \
00083   })
00084 
00085 #define lll_futex_wake(futexp, nr, private) \
00086   ({                                                                 \
00087     INTERNAL_SYSCALL_DECL (__err);                                   \
00088     long int __ret;                                                  \
00089     __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),                    \
00090                            __lll_private_flag (FUTEX_WAKE, private),        \
00091                            (nr), 0);            \
00092     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;               \
00093   })
00094 
00095 #define lll_robust_dead(futexv, private) \
00096   do                                                                 \
00097     {                                                                \
00098       int *__futexp = &(futexv);                                     \
00099       atomic_or (__futexp, FUTEX_OWNER_DIED);                               \
00100       lll_futex_wake (__futexp, 1, private);                                \
00101     }                                                                \
00102   while (0)
00103 
00104 /* Returns non-zero if error happened, zero if success.  */
00105 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
00106   ({                                                                 \
00107     INTERNAL_SYSCALL_DECL (__err);                                   \
00108     long int __ret;                                                  \
00109     __ret = INTERNAL_SYSCALL (futex, __err, 6, (long) (futexp),                    \
00110                            __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
00111                            (nr_wake), (nr_move), (mutex), (val));           \
00112     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00113   })
00114 
00115 /* Returns non-zero if error happened, zero if success.  */
00116 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
00117   ({                                                                 \
00118     INTERNAL_SYSCALL_DECL (__err);                                   \
00119     long int __ret;                                                  \
00120                                                                      \
00121     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00122                            __lll_private_flag (FUTEX_WAKE_OP, private),    \
00123                            (nr_wake), (nr_wake2), (futexp2),                \
00124                            FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                  \
00125     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00126   })
00127 
00128 static inline int __attribute__((always_inline))
00129 __lll_trylock(int *futex)
00130 {
00131   return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
00132 }
00133 #define lll_trylock(lock)   __lll_trylock (&(lock))
00134 
00135 
00136 static inline int __attribute__((always_inline))
00137 __lll_cond_trylock(int *futex)
00138 {
00139   return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
00140 }
00141 #define lll_cond_trylock(lock)     __lll_cond_trylock (&(lock))
00142 
00143 
00144 static inline int __attribute__((always_inline))
00145 __lll_robust_trylock(int *futex, int id)
00146 {
00147   return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
00148 }
00149 #define lll_robust_trylock(lock, id) \
00150   __lll_robust_trylock (&(lock), id)
00151 
00152 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00153 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00154 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00155 
00156 #define __lll_lock(futex, private)                                   \
00157   ((void) ({                                                         \
00158     int *__futex = (futex);                                          \
00159     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \
00160                                                         1, 0), 0))    \
00161       {                                                                     \
00162        if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)             \
00163          __lll_lock_wait_private (__futex);                                 \
00164        else                                                          \
00165          __lll_lock_wait (__futex, private);                                \
00166       }                                                                     \
00167   }))
00168 #define lll_lock(futex, private) __lll_lock (&(futex), private)
00169 
00170 
00171 #define __lll_robust_lock(futex, id, private)                               \
00172   ({                                                                 \
00173     int *__futex = (futex);                                          \
00174     int __val = 0;                                                   \
00175                                                                      \
00176     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00177                                                         0), 0))             \
00178       __val = __lll_robust_lock_wait (__futex, private);                    \
00179     __val;                                                           \
00180   })
00181 #define lll_robust_lock(futex, id, private) \
00182   __lll_robust_lock (&(futex), id, private)
00183 
00184 
00185 static inline void __attribute__ ((always_inline))
00186 __lll_cond_lock (int *futex, int private)
00187 {
00188   if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
00189     __lll_lock_wait (futex, private);
00190 }
00191 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00192 
00193 
00194 #define lll_robust_cond_lock(futex, id, private) \
00195   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
00196 
00197 
00198 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
00199                              int private) attribute_hidden;
00200 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
00201                                    int private) attribute_hidden;
00202 
00203 static inline int __attribute__ ((always_inline))
00204 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
00205 {
00206   int result = 0;
00207   if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
00208     result = __lll_timedlock_wait (futex, abstime, private);
00209   return result;
00210 }
00211 #define lll_timedlock(futex, abstime, private) \
00212   __lll_timedlock (&(futex), abstime, private)
00213 
00214 
00215 static inline int __attribute__ ((always_inline))
00216 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
00217                      int id, int private)
00218 {
00219   int result = 0;
00220   if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
00221     result = __lll_robust_timedlock_wait (futex, abstime, private);
00222   return result;
00223 }
00224 #define lll_robust_timedlock(futex, abstime, id, private) \
00225   __lll_robust_timedlock (&(futex), abstime, id, private)
00226 
00227 
00228 #define __lll_unlock(futex, private)                                        \
00229   ((void) ({                                                         \
00230     int *__futex = (futex);                                          \
00231     int __val = atomic_exchange_rel (__futex, 0);                           \
00232                                                                      \
00233     if (__builtin_expect (__val > 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 __val = atomic_exchange_rel (__futex, 0);                           \
00243                                                                      \
00244     if (__builtin_expect (__val & FUTEX_WAITERS, 0))                        \
00245       lll_futex_wake (__futex, 1, private);                                 \
00246   }))
00247 #define lll_robust_unlock(futex, private) \
00248   __lll_robust_unlock(&(futex), private)
00249 
00250 
00251 #define lll_islocked(futex) \
00252   (futex != 0)
00253 
00254 
00255 /* Our internal lock implementation is identical to the binary-compatible
00256    mutex implementation. */
00257 
00258 /* Initializers for lock.  */
00259 #define LLL_LOCK_INITIALIZER              (0)
00260 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00261 
00262 /* The states of a lock are:
00263     0  -  untaken
00264     1  -  taken by one user
00265    >1  -  taken by more users */
00266 
00267 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
00268    wakeup when the clone terminates.  The memory location contains the
00269    thread ID while the clone is running and is reset to zero
00270    afterwards.       */
00271 #define lll_wait_tid(tid) \
00272   do {                                           \
00273     __typeof (tid) __tid;                        \
00274     while ((__tid = (tid)) != 0)                 \
00275       lll_futex_wait (&(tid), __tid, LLL_SHARED);       \
00276   } while (0)
00277 
00278 extern int __lll_timedwait_tid (int *, const struct timespec *)
00279      attribute_hidden;
00280 
00281 #define lll_timedwait_tid(tid, abstime) \
00282   ({                                             \
00283     int __res = 0;                               \
00284     if ((tid) != 0)                              \
00285       __res = __lll_timedwait_tid (&(tid), (abstime));  \
00286     __res;                                       \
00287   })
00288 
00289 #endif /* lowlevellock.h */