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 
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 #ifndef __ASSEMBLER__
00023 #include <time.h>
00024 #include <sys/param.h>
00025 #include <bits/pthreadtypes.h>
00026 #include <kernel-features.h>
00027 #endif
00028 
00029 #define SYS_futex           240
00030 #define FUTEX_WAIT          0
00031 #define FUTEX_WAKE          1
00032 #define FUTEX_CMP_REQUEUE   4
00033 #define FUTEX_WAKE_OP              5
00034 #define FUTEX_LOCK_PI              6
00035 #define FUTEX_UNLOCK_PI            7
00036 #define FUTEX_TRYLOCK_PI    8
00037 #define FUTEX_PRIVATE_FLAG  128
00038 
00039 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
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 #ifndef __ASSEMBLER__
00073 
00074 /* Initializer for compatibility lock.  */
00075 #define LLL_LOCK_INITIALIZER              (0)
00076 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00077 #define LLL_LOCK_INITIALIZER_WAITERS      (2)
00078 
00079 extern int __lll_lock_wait_private (int val, int *__futex)
00080   attribute_hidden;
00081 extern int __lll_lock_wait (int val, int *__futex, int private)
00082   attribute_hidden;
00083 extern int __lll_timedlock_wait (int val, int *__futex,
00084                              const struct timespec *abstime, int private)
00085   attribute_hidden;
00086 extern int __lll_robust_lock_wait (int val, int *__futex, int private)
00087   attribute_hidden;
00088 extern int __lll_robust_timedlock_wait (int val, int *__futex,
00089                                    const struct timespec *abstime,
00090                                    int private)
00091   attribute_hidden;
00092 extern int __lll_unlock_wake_private (int *__futex) attribute_hidden;
00093 extern int __lll_unlock_wake (int *__futex, int private) attribute_hidden;
00094 
00095 #define lll_trylock(futex) \
00096   ({ unsigned char __result; \
00097      __asm __volatile ("\
00098        .align 2\n\
00099        mova 1f,r0\n\
00100        nop\n\
00101        mov r15,r1\n\
00102        mov #-8,r15\n\
00103      0: mov.l @%1,r2\n\
00104        cmp/eq r2,%3\n\
00105        bf 1f\n\
00106        mov.l %2,@%1\n\
00107      1: mov r1,r15\n\
00108        mov #-1,%0\n\
00109        negc %0,%0"\
00110        : "=r" (__result) \
00111        : "r" (&(futex)), \
00112          "r" (LLL_LOCK_INITIALIZER_LOCKED), \
00113          "r" (LLL_LOCK_INITIALIZER) \
00114        : "r0", "r1", "r2", "t", "memory"); \
00115      __result; })
00116 
00117 #define lll_robust_trylock(futex, id)     \
00118   ({ unsigned char __result; \
00119      __asm __volatile ("\
00120        .align 2\n\
00121        mova 1f,r0\n\
00122        nop\n\
00123        mov r15,r1\n\
00124        mov #-8,r15\n\
00125      0: mov.l @%1,r2\n\
00126        cmp/eq r2,%3\n\
00127        bf 1f\n\
00128        mov.l %2,@%1\n\
00129      1: mov r1,r15\n\
00130        mov #-1,%0\n\
00131        negc %0,%0"\
00132        : "=r" (__result) \
00133        : "r" (&(futex)), \
00134          "r" (id), \
00135          "r" (LLL_LOCK_INITIALIZER) \
00136        : "r0", "r1", "r2", "t", "memory"); \
00137      __result; })
00138 
00139 #define lll_cond_trylock(futex) \
00140   ({ unsigned char __result; \
00141      __asm __volatile ("\
00142        .align 2\n\
00143        mova 1f,r0\n\
00144        nop\n\
00145        mov r15,r1\n\
00146        mov #-8,r15\n\
00147      0: mov.l @%1,r2\n\
00148        cmp/eq r2,%3\n\
00149        bf 1f\n\
00150        mov.l %2,@%1\n\
00151      1: mov r1,r15\n\
00152        mov #-1,%0\n\
00153        negc %0,%0"\
00154        : "=r" (__result) \
00155        : "r" (&(futex)), \
00156          "r" (LLL_LOCK_INITIALIZER_WAITERS), \
00157          "r" (LLL_LOCK_INITIALIZER) \
00158        : "r0", "r1", "r2", "t", "memory"); \
00159      __result; })
00160 
00161 #define lll_lock(futex, private) \
00162   (void) ({ int __result, *__futex = &(futex); \
00163            __asm __volatile ("\
00164               .align 2\n\
00165               mova 1f,r0\n\
00166               nop\n\
00167               mov r15,r1\n\
00168               mov #-8,r15\n\
00169             0: mov.l @%2,%0\n\
00170               tst %0,%0\n\
00171               bf 1f\n\
00172               mov.l %1,@%2\n\
00173             1: mov r1,r15"\
00174               : "=&r" (__result) : "r" (1), "r" (__futex) \
00175               : "r0", "r1", "t", "memory"); \
00176            if (__result) \
00177              { \
00178               if (__builtin_constant_p (private) \
00179                   && (private) == LLL_PRIVATE) \
00180                 __lll_lock_wait_private (__result, __futex); \
00181                else \
00182                 __lll_lock_wait (__result, __futex, (private));       \
00183              } \
00184     })
00185 
00186 #define lll_robust_lock(futex, id, private) \
00187   ({ int __result, *__futex = &(futex); \
00188      __asm __volatile ("\
00189        .align 2\n\
00190        mova 1f,r0\n\
00191        nop\n\
00192        mov r15,r1\n\
00193        mov #-8,r15\n\
00194       0: mov.l @%2,%0\n\
00195        tst %0,%0\n\
00196        bf 1f\n\
00197        mov.l %1,@%2\n\
00198       1: mov r1,r15"\
00199        : "=&r" (__result) : "r" (id), "r" (__futex) \
00200        : "r0", "r1", "t", "memory"); \
00201      if (__result) \
00202        __result = __lll_robust_lock_wait (__result, __futex, private); \
00203      __result; })
00204 
00205 /* Special version of lll_mutex_lock which causes the unlock function to
00206    always wakeup waiters.  */
00207 #define lll_cond_lock(futex, private) \
00208   (void) ({ int __result, *__futex = &(futex); \
00209            __asm __volatile ("\
00210               .align 2\n\
00211               mova 1f,r0\n\
00212               nop\n\
00213               mov r15,r1\n\
00214               mov #-8,r15\n\
00215             0: mov.l @%2,%0\n\
00216               tst %0,%0\n\
00217               bf 1f\n\
00218               mov.l %1,@%2\n\
00219             1: mov r1,r15"\
00220               : "=&r" (__result) : "r" (2), "r" (__futex) \
00221               : "r0", "r1", "t", "memory"); \
00222            if (__result) \
00223              __lll_lock_wait (__result, __futex, private); })
00224 
00225 #define lll_robust_cond_lock(futex, id, private) \
00226   ({ int __result, *__futex = &(futex); \
00227      __asm __volatile ("\
00228        .align 2\n\
00229        mova 1f,r0\n\
00230        nop\n\
00231        mov r15,r1\n\
00232        mov #-8,r15\n\
00233      0: mov.l @%2,%0\n\
00234        tst %0,%0\n\
00235        bf 1f\n\
00236        mov.l %1,@%2\n\
00237      1: mov r1,r15"\
00238        : "=&r" (__result) : "r" (id | FUTEX_WAITERS), "r" (__futex) \
00239        : "r0", "r1", "t", "memory"); \
00240       if (__result) \
00241        __result = __lll_robust_lock_wait (__result, __futex, private); \
00242       __result; })
00243 
00244 #define lll_timedlock(futex, timeout, private) \
00245   ({ int __result, *__futex = &(futex); \
00246      __asm __volatile ("\
00247        .align 2\n\
00248        mova 1f,r0\n\
00249        nop\n\
00250        mov r15,r1\n\
00251        mov #-8,r15\n\
00252      0: mov.l @%2,%0\n\
00253        tst %0,%0\n\
00254        bf 1f\n\
00255        mov.l %1,@%2\n\
00256      1: mov r1,r15"\
00257        : "=&r" (__result) : "r" (1), "r" (__futex) \
00258        : "r0", "r1", "t", "memory"); \
00259     if (__result) \
00260       __result = __lll_timedlock_wait (__result, __futex, timeout, private); \
00261     __result; })
00262 
00263 #define lll_robust_timedlock(futex, timeout, id, private) \
00264   ({ int __result, *__futex = &(futex); \
00265      __asm __volatile ("\
00266        .align 2\n\
00267        mova 1f,r0\n\
00268        nop\n\
00269        mov r15,r1\n\
00270        mov #-8,r15\n\
00271      0: mov.l @%2,%0\n\
00272        tst %0,%0\n\
00273        bf 1f\n\
00274        mov.l %1,@%2\n\
00275      1: mov r1,r15"\
00276        : "=&r" (__result) : "r" (id), "r" (__futex) \
00277        : "r0", "r1", "t", "memory"); \
00278     if (__result) \
00279       __result = __lll_robust_timedlock_wait (__result, __futex, \
00280                                          timeout, private); \
00281     __result; })
00282 
00283 #define lll_unlock(futex, private) \
00284   (void) ({ int __result, *__futex = &(futex); \
00285            __asm __volatile ("\
00286               .align 2\n\
00287               mova 1f,r0\n\
00288               mov r15,r1\n\
00289               mov #-6,r15\n\
00290             0: mov.l @%1,%0\n\
00291               add #-1,%0\n\
00292               mov.l %0,@%1\n\
00293             1: mov r1,r15"\
00294               : "=&r" (__result) : "r" (__futex) \
00295               : "r0", "r1", "memory"); \
00296            if (__result) \
00297              { \
00298               if (__builtin_constant_p (private) \
00299                   && (private) == LLL_PRIVATE) \
00300                 __lll_unlock_wake_private (__futex); \
00301                else \
00302                 __lll_unlock_wake (__futex, (private)); \
00303              } \
00304     })
00305 
00306 #define lll_robust_unlock(futex, private) \
00307   (void) ({ int __result, *__futex = &(futex); \
00308            __asm __volatile ("\
00309               .align 2\n\
00310               mova 1f,r0\n\
00311               mov r15,r1\n\
00312               mov #-6,r15\n\
00313             0: mov.l @%1,%0\n\
00314               and %2,%0\n\
00315               mov.l %0,@%1\n\
00316             1: mov r1,r15"\
00317               : "=&r" (__result) : "r" (__futex), "r" (FUTEX_WAITERS) \
00318               : "r0", "r1", "memory");    \
00319            if (__result) \
00320              __lll_unlock_wake (__futex, private); })
00321 
00322 #define lll_robust_dead(futex, private)                 \
00323   (void) ({ int __ignore, *__futex = &(futex); \
00324            __asm __volatile ("\
00325               .align 2\n\
00326               mova 1f,r0\n\
00327               mov r15,r1\n\
00328               mov #-6,r15\n\
00329             0: mov.l @%1,%0\n\
00330               or %2,%0\n\
00331               mov.l %0,@%1\n\
00332             1: mov r1,r15"\
00333               : "=&r" (__ignore) : "r" (__futex), "r" (FUTEX_OWNER_DIED) \
00334               : "r0", "r1", "memory");    \
00335            lll_futex_wake (__futex, 1, private); })
00336 
00337 # ifdef NEED_SYSCALL_INST_PAD
00338 #  define SYSCALL_WITH_INST_PAD "\
00339        trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0"
00340 # else
00341 #  define SYSCALL_WITH_INST_PAD "\
00342        trapa #0x14"
00343 # endif
00344 
00345 #define lll_futex_wait(futex, val, private) \
00346   lll_futex_timed_wait (futex, val, NULL, private)
00347 
00348 
00349 #define lll_futex_timed_wait(futex, val, timeout, private) \
00350   ({                                                                 \
00351     int __status;                                                    \
00352     register unsigned long __r3 asm ("r3") = SYS_futex;                     \
00353     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);       \
00354     register unsigned long __r5 asm ("r5")                                  \
00355       = __lll_private_flag (FUTEX_WAIT, private);                           \
00356     register unsigned long __r6 asm ("r6") = (unsigned long) (val);         \
00357     register unsigned long __r7 asm ("r7") = (timeout);                     \
00358     __asm __volatile (SYSCALL_WITH_INST_PAD                                 \
00359                     : "=z" (__status)                                       \
00360                     : "r" (__r3), "r" (__r4), "r" (__r5),                   \
00361                      "r" (__r6), "r" (__r7)                                 \
00362                     : "memory", "t");                                       \
00363     __status;                                                        \
00364   })
00365 
00366 
00367 #define lll_futex_wake(futex, nr, private) \
00368   do {                                                               \
00369     int __ignore;                                                    \
00370     register unsigned long __r3 asm ("r3") = SYS_futex;                     \
00371     register unsigned long __r4 asm ("r4") = (unsigned long) (futex);       \
00372     register unsigned long __r5 asm ("r5")                                  \
00373       = __lll_private_flag (FUTEX_WAKE, private);                           \
00374     register unsigned long __r6 asm ("r6") = (unsigned long) (nr);          \
00375     register unsigned long __r7 asm ("r7") = 0;                             \
00376     __asm __volatile (SYSCALL_WITH_INST_PAD                                 \
00377                     : "=z" (__ignore)                                       \
00378                     : "r" (__r3), "r" (__r4), "r" (__r5),                   \
00379                      "r" (__r6), "r" (__r7)                                 \
00380                     : "memory", "t");                                       \
00381   } while (0)
00382 
00383 
00384 #define lll_islocked(futex) \
00385   (futex != LLL_LOCK_INITIALIZER)
00386 
00387 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
00388    wakeup when the clone terminates.  The memory location contains the
00389    thread ID while the clone is running and is reset to zero
00390    afterwards.  */
00391 
00392 #define lll_wait_tid(tid) \
00393   do {                                                               \
00394     __typeof (tid) *__tid = &(tid);                                         \
00395     while (*__tid != 0)                                                     \
00396       lll_futex_wait (__tid, *__tid, LLL_SHARED);                           \
00397   } while (0)
00398 
00399 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
00400      attribute_hidden;
00401 #define lll_timedwait_tid(tid, abstime) \
00402   ({                                                                 \
00403     int __result = 0;                                                       \
00404     if (tid != 0)                                                    \
00405       {                                                                     \
00406        if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)          \
00407          __result = EINVAL;                                          \
00408        else                                                          \
00409          __result = __lll_timedwait_tid (&tid, abstime);                    \
00410       }                                                                     \
00411     __result; })
00412 
00413 #endif  /* !__ASSEMBLER__ */
00414 
00415 #endif  /* lowlevellock.h */