Back to index

glibc  2.9
lowlevellock.h
Go to the documentation of this file.
00001 /* Copyright (C) 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, (futexp),                    \
00080                            __lll_private_flag (FUTEX_WAIT, private),        \
00081                            (val), (timespec));                       \
00082     __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, (futexp),                    \
00090                            __lll_private_flag (FUTEX_WAKE, private),        \
00091                            (nr), 0);                                        \
00092     __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, (futexp),                    \
00110                            __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
00111                            (nr_wake), (nr_move), (mutex), (val));           \
00112     __ret;                                                           \
00113   })
00114 
00115 
00116 /* Returns non-zero if error happened, zero if success.  */
00117 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
00118   ({                                                                 \
00119     INTERNAL_SYSCALL_DECL (__err);                                   \
00120     long int __ret;                                                  \
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     __ret;                                                           \
00126   })
00127 
00128 
00129 #define lll_trylock(lock)   \
00130   atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
00131 
00132 #define lll_cond_trylock(lock)     \
00133   atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
00134 
00135 #define __lll_robust_trylock(futex, id) \
00136   (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
00137 #define lll_robust_trylock(lock, id) \
00138   __lll_robust_trylock (&(lock), id)
00139 
00140 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00141 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00142 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00143 
00144 #define __lll_lock(futex, private)                                   \
00145   ((void) ({                                                         \
00146     int *__futex = (futex);                                          \
00147     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
00148                                                         1, 0), 0))    \
00149       {                                                                     \
00150        if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)             \
00151          __lll_lock_wait_private (__futex);                                 \
00152        else                                                          \
00153          __lll_lock_wait (__futex, private);                                \
00154       }                                                                     \
00155   }))
00156 #define lll_lock(futex, private) __lll_lock (&(futex), private)
00157 
00158 
00159 #define __lll_robust_lock(futex, id, private)                               \
00160   ({                                                                 \
00161     int *__futex = (futex);                                          \
00162     int __val = 0;                                                   \
00163                                                                      \
00164     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00165                                                         0), 0))             \
00166       __val = __lll_robust_lock_wait (__futex, private);                    \
00167     __val;                                                           \
00168   })
00169 #define lll_robust_lock(futex, id, private) \
00170   __lll_robust_lock (&(futex), id, private)
00171 
00172 
00173 #define __lll_cond_lock(futex, private)                                     \
00174   ((void) ({                                                         \
00175     int *__futex = (futex);                                          \
00176     if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))                    \
00177       __lll_lock_wait (__futex, private);                            \
00178   }))
00179 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00180 
00181 
00182 #define lll_robust_cond_lock(futex, id, private) \
00183   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
00184 
00185 
00186 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
00187                              int private) attribute_hidden;
00188 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
00189                                    int private) attribute_hidden;
00190 
00191 #define __lll_timedlock(futex, abstime, private)                     \
00192   ({                                                                 \
00193      int *__futex = (futex);                                                \
00194      int __val = 0;                                                  \
00195                                                                      \
00196      if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))            \
00197        __val = __lll_timedlock_wait (__futex, abstime, private);            \
00198      __val;                                                          \
00199   })
00200 #define lll_timedlock(futex, abstime, private) \
00201   __lll_timedlock (&(futex), abstime, private)
00202 
00203 
00204 #define __lll_robust_timedlock(futex, abstime, id, private)                 \
00205   ({                                                                 \
00206     int *__futex = (futex);                                          \
00207     int __val = 0;                                                   \
00208                                                                      \
00209     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00210                                                         0), 0))             \
00211       __val = __lll_robust_timedlock_wait (__futex, abstime, private);             \
00212     __val;                                                           \
00213   })
00214 #define lll_robust_timedlock(futex, abstime, id, private) \
00215   __lll_robust_timedlock (&(futex), abstime, id, private)
00216 
00217 
00218 #define __lll_unlock(futex, private) \
00219   (void)                                                \
00220     ({ int *__futex = (futex);                                 \
00221        int __oldval = atomic_exchange_rel (__futex, 0);        \
00222        if (__builtin_expect (__oldval > 1, 0))                 \
00223         lll_futex_wake (__futex, 1, private);                  \
00224     })
00225 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
00226 
00227 
00228 #define __lll_robust_unlock(futex, private) \
00229   (void)                                                \
00230     ({ int *__futex = (futex);                                 \
00231        int __oldval = atomic_exchange_rel (__futex, 0);        \
00232        if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))     \
00233         lll_futex_wake (__futex, 1, private);                  \
00234     })
00235 #define lll_robust_unlock(futex, private) \
00236   __lll_robust_unlock(&(futex), private)
00237 
00238 
00239 #define lll_islocked(futex) \
00240   (futex != 0)
00241 
00242 
00243 /* Our internal lock implementation is identical to the binary-compatible
00244    mutex implementation. */
00245 
00246 /* Initializers for lock.  */
00247 #define LLL_LOCK_INITIALIZER              (0)
00248 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00249 
00250 /* The states of a lock are:
00251     0  -  untaken
00252     1  -  taken by one user
00253    >1  -  taken by more users */
00254 
00255 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
00256    wakeup when the clone terminates.  The memory location contains the
00257    thread ID while the clone is running and is reset to zero
00258    afterwards.       */
00259 #define lll_wait_tid(tid) \
00260   do {                             \
00261     __typeof (tid) __tid;          \
00262     while ((__tid = (tid)) != 0)   \
00263       lll_futex_wait (&(tid), __tid, LLL_SHARED);\
00264   } while (0)
00265 
00266 extern int __lll_timedwait_tid (int *, const struct timespec *)
00267      attribute_hidden;
00268 
00269 #define lll_timedwait_tid(tid, abstime) \
00270   ({                                             \
00271     int __res = 0;                               \
00272     if ((tid) != 0)                              \
00273       __res = __lll_timedwait_tid (&(tid), (abstime));  \
00274     __res;                                       \
00275   })
00276 
00277 #endif /* lowlevellock.h */