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    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.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 Library; 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 #define SYS_futex           238
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 /* Values for 'private' parameter of locking macros.  Yes, the
00042    definition seems to be backwards.  But it is not.  The bit will be
00043    reversed before passing to the system call.  */
00044 #define LLL_PRIVATE  0
00045 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
00046 
00047 
00048 #if !defined NOT_IN_libc || defined IS_IN_rtld
00049 /* In libc.so or ld.so all futexes are private.  */
00050 # ifdef __ASSUME_PRIVATE_FUTEX
00051 #  define __lll_private_flag(fl, private) \
00052   ((fl) | FUTEX_PRIVATE_FLAG)
00053 # else
00054 #  define __lll_private_flag(fl, private) \
00055   ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
00056 # endif
00057 #else
00058 # ifdef __ASSUME_PRIVATE_FUTEX
00059 #  define __lll_private_flag(fl, private) \
00060   (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
00061 # else
00062 #  define __lll_private_flag(fl, private) \
00063   (__builtin_constant_p (private)                                    \
00064    ? ((private) == 0                                                 \
00065       ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))          \
00066       : (fl))                                                        \
00067    : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                              \
00068              & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
00069 # endif             
00070 #endif
00071 
00072 #define lll_futex_wait(futex, val, private) \
00073   lll_futex_timed_wait (futex, val, NULL, private)
00074 
00075 #define lll_futex_timed_wait(futex, val, timespec, private) \
00076   ({                                                                 \
00077     register unsigned long int __r2 asm ("2") = (unsigned long int) (futex);  \
00078     register unsigned long int __r3 asm ("3")                               \
00079       = __lll_private_flag (FUTEX_WAIT, private);                           \
00080     register unsigned long int __r4 asm ("4") = (unsigned long int) (val);    \
00081     register unsigned long int __r5 asm ("5") = (unsigned long int)(timespec);\
00082     register unsigned long int __result asm ("2");                          \
00083                                                                      \
00084     __asm __volatile ("svc %b1"                                             \
00085                     : "=d" (__result)                                       \
00086                     : "i" (SYS_futex), "0" (__r2), "d" (__r3),       \
00087                      "d" (__r4), "d" (__r5)                                 \
00088                     : "cc", "memory" );                              \
00089     __result;                                                        \
00090   })
00091 
00092 
00093 #define lll_futex_wake(futex, nr, private) \
00094   ({                                                                 \
00095     register unsigned long int __r2 asm ("2") = (unsigned long int) (futex);  \
00096     register unsigned long int __r3 asm ("3")                               \
00097       = __lll_private_flag (FUTEX_WAKE, private);                           \
00098     register unsigned long int __r4 asm ("4") = (unsigned long int) (nr);     \
00099     register unsigned long int __result asm ("2");                          \
00100                                                                      \
00101     __asm __volatile ("svc %b1"                                             \
00102                     : "=d" (__result)                                       \
00103                     : "i" (SYS_futex), "0" (__r2), "d" (__r3), "d" (__r4)   \
00104                     : "cc", "memory" );                              \
00105     __result;                                                        \
00106   })
00107 
00108 
00109 #define lll_robust_dead(futexv, private) \
00110   do                                                                 \
00111     {                                                                \
00112       int *__futexp = &(futexv);                                     \
00113                                                                      \
00114       atomic_or (__futexp, FUTEX_OWNER_DIED);                               \
00115       lll_futex_wake (__futexp, 1, private);                                \
00116     }                                                                \
00117   while (0)
00118 
00119 
00120 /* Returns non-zero if error happened, zero if success.  */
00121 #define lll_futex_requeue(futex, nr_wake, nr_move, mutex, val, private) \
00122   ({                                                                 \
00123     register unsigned long int __r2 asm ("2") = (unsigned long int) (futex);  \
00124     register unsigned long int __r3 asm ("3")                               \
00125       = __lll_private_flag (FUTEX_CMP_REQUEUE, private);                    \
00126     register unsigned long int __r4 asm ("4") = (long int) (nr_wake);       \
00127     register unsigned long int __r5 asm ("5") = (long int) (nr_move);       \
00128     register unsigned long int __r6 asm ("6") = (unsigned long int) (mutex);  \
00129     register unsigned long int __r7 asm ("7") = (int) (val);                \
00130     register unsigned long __result asm ("2");                              \
00131                                                                      \
00132     __asm __volatile ("svc %b1"                                             \
00133                     : "=d" (__result)                                       \
00134                     : "i" (SYS_futex), "0" (__r2), "d" (__r3),       \
00135                      "d" (__r4), "d" (__r5), "d" (__r6), "d" (__r7)         \
00136                     : "cc", "memory" );                              \
00137     __result > -4096UL;                                                     \
00138   })
00139 
00140 
00141 /* Returns non-zero if error happened, zero if success.  */
00142 #define lll_futex_wake_unlock(futex, nr_wake, nr_wake2, futex2, private) \
00143   ({                                                                 \
00144     register unsigned long int __r2 asm ("2") = (unsigned long int) (futex);  \
00145     register unsigned long int __r3 asm ("3")                               \
00146       = __lll_private_flag (FUTEX_WAKE_OP, private);                        \
00147     register unsigned long int __r4 asm ("4") = (long int) (nr_wake);       \
00148     register unsigned long int __r5 asm ("5") = (long int) (nr_wake2);             \
00149     register unsigned long int __r6 asm ("6") = (unsigned long int) (futex2); \
00150     register unsigned long int __r7 asm ("7")                               \
00151       = (int) FUTEX_OP_CLEAR_WAKE_IF_GT_ONE;                                \
00152     register unsigned long __result asm ("2");                              \
00153                                                                      \
00154     __asm __volatile ("svc %b1"                                             \
00155                     : "=d" (__result)                                       \
00156                     : "i" (SYS_futex), "0" (__r2), "d" (__r3),       \
00157                      "d" (__r4), "d" (__r5), "d" (__r6), "d" (__r7)         \
00158                     : "cc", "memory" );                              \
00159     __result > -4096UL;                                                     \
00160   })
00161 
00162 
00163 #define lll_compare_and_swap(futex, oldval, newval, operation) \
00164   do {                                                               \
00165     __typeof (futex) __futex = (futex);                                     \
00166     __asm __volatile ("       l   %1,%0\n"                                         \
00167                     "0: " operation "\n"                             \
00168                     "         cs  %1,%2,%0\n"                               \
00169                     "         jl  0b\n"                                     \
00170                     "1:"                                             \
00171                     : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval)       \
00172                     : "m" (*__futex) : "cc", "memory" );                    \
00173   } while (0)
00174 
00175 
00176 static inline int
00177 __attribute__ ((always_inline))
00178 __lll_trylock (int *futex)
00179 {
00180     unsigned int old;
00181 
00182     __asm __volatile ("cs %0,%3,%1"
00183                      : "=d" (old), "=Q" (*futex)
00184                      : "0" (0), "d" (1), "m" (*futex) : "cc", "memory" );
00185     return old != 0;
00186 }
00187 #define lll_trylock(futex) __lll_trylock (&(futex))
00188 
00189 
00190 static inline int
00191 __attribute__ ((always_inline))
00192 __lll_cond_trylock (int *futex)
00193 {
00194     unsigned int old;
00195 
00196     __asm __volatile ("cs %0,%3,%1"
00197                      : "=d" (old), "=Q" (*futex)
00198                      : "0" (0), "d" (2), "m" (*futex) : "cc", "memory" );
00199     return old != 0;
00200 }
00201 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
00202 
00203 
00204 static inline int
00205 __attribute__ ((always_inline))
00206 __lll_robust_trylock (int *futex, int id)
00207 {
00208     unsigned int old;
00209 
00210     __asm __volatile ("cs %0,%3,%1"
00211                      : "=d" (old), "=Q" (*futex)
00212                      : "0" (0), "d" (id), "m" (*futex) : "cc", "memory" );
00213     return old != 0;
00214 }
00215 #define lll_robust_trylock(futex, id) \
00216   __lll_robust_trylock (&(futex), id)
00217 
00218 
00219 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00220 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00221 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00222 
00223 static inline void
00224 __attribute__ ((always_inline))
00225 __lll_lock (int *futex, int private)
00226 {
00227   if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 1, 0), 0))
00228     {
00229       if (__builtin_constant_p (private) && private == LLL_PRIVATE)
00230        __lll_lock_wait_private (futex);
00231       else
00232        __lll_lock_wait (futex, private);
00233     }
00234 }
00235 #define lll_lock(futex, private) __lll_lock (&(futex), private)
00236 
00237 static inline int
00238 __attribute__ ((always_inline))
00239 __lll_robust_lock (int *futex, int id, int private)
00240 {
00241   int result = 0;
00242   if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
00243                      0))
00244     result = __lll_robust_lock_wait (futex, private);
00245   return result;
00246 }
00247 #define lll_robust_lock(futex, id, private) \
00248   __lll_robust_lock (&(futex), id, private)
00249 
00250 static inline void
00251 __attribute__ ((always_inline))
00252 __lll_cond_lock (int *futex, int private)
00253 {
00254   if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 2, 0), 0))
00255     __lll_lock_wait (futex, private);
00256 }
00257 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00258 
00259 #define lll_robust_cond_lock(futex, id, private) \
00260   __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
00261 
00262 extern int __lll_timedlock_wait
00263   (int *futex, const struct timespec *, int private) attribute_hidden;
00264 extern int __lll_robust_timedlock_wait
00265   (int *futex, const struct timespec *, int private) attribute_hidden;
00266 
00267 static inline int
00268 __attribute__ ((always_inline))
00269 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
00270 {
00271   int result = 0;
00272   if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 1, 0), 0))
00273     result = __lll_timedlock_wait (futex, abstime, private);
00274   return result;
00275 }
00276 #define lll_timedlock(futex, abstime, private) \
00277   __lll_timedlock (&(futex), abstime, private)
00278 
00279 static inline int
00280 __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
00286                      0))
00287     result = __lll_robust_timedlock_wait (futex, abstime, private);
00288   return result;
00289 }
00290 #define lll_robust_timedlock(futex, abstime, id, private) \
00291   __lll_robust_timedlock (&(futex), abstime, id, private)
00292 
00293 
00294 #define __lll_unlock(futex, private) \
00295   (void)                                                             \
00296     ({ int __oldval;                                                 \
00297        int __newval = 0;                                             \
00298        int *__futexp = (futex);                                             \
00299                                                                      \
00300        lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2");      \
00301        if (__builtin_expect (__oldval > 1, 0))                              \
00302         lll_futex_wake (__futexp, 1, private);                              \
00303     })
00304 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
00305 
00306 
00307 #define __lll_robust_unlock(futex, private) \
00308   (void)                                                             \
00309     ({ int __oldval;                                                 \
00310        int __newval = 0;                                             \
00311        int *__futexp = (futex);                                             \
00312                                                                      \
00313        lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2");      \
00314        if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))                  \
00315         lll_futex_wake (__futexp, 1, private);                              \
00316     })
00317 #define lll_robust_unlock(futex, private) \
00318   __lll_robust_unlock(&(futex), private)
00319 
00320 #define lll_islocked(futex) \
00321   (futex != 0)
00322 
00323 
00324 /* Initializers for lock.  */
00325 #define LLL_LOCK_INITIALIZER              (0)
00326 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00327 
00328 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
00329    wakeup when the clone terminates.  The memory location contains the
00330    thread ID while the clone is running and is reset to zero
00331    afterwards.       */
00332 #define __lll_wait_tid(ptid) \
00333   do                                                                 \
00334     {                                                                \
00335       int __tid;                                                     \
00336                                                                      \
00337       while ((__tid = *ptid) != 0)                                   \
00338        lll_futex_wait (ptid, __tid, LLL_SHARED);                     \
00339     }                                                                \
00340   while (0)
00341 #define lll_wait_tid(tid) __lll_wait_tid(&(tid))
00342 
00343 extern int __lll_timedwait_tid (int *, const struct timespec *)
00344      attribute_hidden;
00345 
00346 #define lll_timedwait_tid(tid, abstime) \
00347   ({                                                                 \
00348     int __res = 0;                                                   \
00349     if ((tid) != 0)                                                  \
00350       __res = __lll_timedwait_tid (&(tid), (abstime));                      \
00351     __res;                                                           \
00352   })
00353 
00354 #endif /* lowlevellock.h */