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 Paul Mackerras <paulus@au.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 #ifndef __NR_futex
00030 # define __NR_futex         221
00031 #endif
00032 #define FUTEX_WAIT          0
00033 #define FUTEX_WAKE          1
00034 #define FUTEX_REQUEUE              3
00035 #define FUTEX_CMP_REQUEUE   4
00036 #define FUTEX_WAKE_OP              5
00037 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
00038 #define FUTEX_LOCK_PI              6
00039 #define FUTEX_UNLOCK_PI            7
00040 #define FUTEX_TRYLOCK_PI    8
00041 #define FUTEX_PRIVATE_FLAG  128
00042 
00043 /* Values for 'private' parameter of locking macros.  Yes, the
00044    definition seems to be backwards.  But it is not.  The bit will be
00045    reversed before passing to the system call.  */
00046 #define LLL_PRIVATE  0
00047 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
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 #define lll_futex_wait(futexp, val, private) \
00074   lll_futex_timed_wait (futexp, val, NULL, private)
00075 
00076 #define lll_futex_timed_wait(futexp, val, timespec, private) \
00077   ({                                                                 \
00078     INTERNAL_SYSCALL_DECL (__err);                                   \
00079     long int __ret;                                                  \
00080                                                                      \
00081     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                    \
00082                            __lll_private_flag (FUTEX_WAIT, private),        \
00083                            (val), (timespec));                       \
00084     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;               \
00085   })
00086 
00087 #define lll_futex_wake(futexp, nr, private) \
00088   ({                                                                 \
00089     INTERNAL_SYSCALL_DECL (__err);                                   \
00090     long int __ret;                                                  \
00091                                                                      \
00092     __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                    \
00093                            __lll_private_flag (FUTEX_WAKE, private),        \
00094                            (nr), 0);                                        \
00095     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;               \
00096   })
00097 
00098 #define lll_robust_dead(futexv, private) \
00099   do                                                                 \
00100     {                                                                \
00101       INTERNAL_SYSCALL_DECL (__err);                                        \
00102       int *__futexp = &(futexv);                                     \
00103                                                                      \
00104       atomic_or (__futexp, FUTEX_OWNER_DIED);                               \
00105       INTERNAL_SYSCALL (futex, __err, 4, __futexp,                          \
00106                      __lll_private_flag (FUTEX_WAKE, private), 1, 0);      \
00107     }                                                                \
00108   while (0)
00109 
00110 /* Returns non-zero if error happened, zero if success.  */
00111 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
00112   ({                                                                 \
00113     INTERNAL_SYSCALL_DECL (__err);                                   \
00114     long int __ret;                                                  \
00115                                                                      \
00116     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00117                            __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
00118                            (nr_wake), (nr_move), (mutex), (val));           \
00119     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00120   })
00121 
00122 /* Returns non-zero if error happened, zero if success.  */
00123 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
00124   ({                                                                 \
00125     INTERNAL_SYSCALL_DECL (__err);                                   \
00126     long int __ret;                                                  \
00127                                                                      \
00128     __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                    \
00129                            __lll_private_flag (FUTEX_WAKE_OP, private),    \
00130                            (nr_wake), (nr_wake2), (futexp2),                \
00131                            FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                  \
00132     INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                \
00133   })
00134   
00135   
00136 #ifdef UP
00137 # define __lll_acq_instr    ""
00138 # define __lll_rel_instr    ""
00139 #else
00140 # define __lll_acq_instr    "isync"
00141 # ifdef _ARCH_PWR4
00142 /*
00143  * Newer powerpc64 processors support the new "light weight" sync (lwsync)
00144  * So if the build is using -mcpu=[power4,power5,power5+,970] we can
00145  * safely use lwsync.
00146  */
00147 #  define __lll_rel_instr   "lwsync"
00148 # else
00149 /*
00150  * Older powerpc32 processors don't support the new "light weight"
00151  * sync (lwsync).  So the only safe option is to use normal sync
00152  * for all powerpc32 applications.
00153  */
00154 #  define __lll_rel_instr   "sync"
00155 # endif
00156 #endif
00157 
00158 /* Set *futex to ID if it is 0, atomically.  Returns the old value */
00159 #define __lll_robust_trylock(futex, id) \
00160   ({ int __val;                                                             \
00161      __asm __volatile ("1:  lwarx  %0,0,%2" MUTEX_HINT_ACQ "\n"             \
00162                      "      cmpwi  0,%0,0\n"                         \
00163                      "      bne    2f\n"                             \
00164                      "      stwcx. %3,0,%2\n"                        \
00165                      "      bne-   1b\n"                             \
00166                      "2:    " __lll_acq_instr                        \
00167                      : "=&r" (__val), "=m" (*futex)                         \
00168                      : "r" (futex), "r" (id), "m" (*futex)                  \
00169                      : "cr0", "memory");                             \
00170      __val;                                                          \
00171   })
00172 
00173 #define lll_robust_trylock(lock, id) __lll_robust_trylock (&(lock), id)
00174 
00175 /* Set *futex to 1 if it is 0, atomically.  Returns the old value */
00176 #define __lll_trylock(futex) __lll_robust_trylock (futex, 1)
00177 
00178 #define lll_trylock(lock)   __lll_trylock (&(lock))
00179 
00180 /* Set *futex to 2 if it is 0, atomically.  Returns the old value */
00181 #define __lll_cond_trylock(futex) __lll_robust_trylock (futex, 2)
00182 
00183 #define lll_cond_trylock(lock)     __lll_cond_trylock (&(lock))
00184 
00185 
00186 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00187 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00188 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00189 
00190 #define lll_lock(lock, private) \
00191   (void) ({                                                          \
00192     int *__futex = &(lock);                                          \
00193     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
00194                        0) != 0)                                      \
00195       {                                                                     \
00196        if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)             \
00197          __lll_lock_wait_private (__futex);                                 \
00198        else                                                          \
00199          __lll_lock_wait (__futex, private);                                \
00200       }                                                                     \
00201   })
00202 
00203 #define lll_robust_lock(lock, id, private) \
00204   ({                                                                 \
00205     int *__futex = &(lock);                                          \
00206     int __val = 0;                                                   \
00207     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00208                                                         0), 0))             \
00209       __val = __lll_robust_lock_wait (__futex, private);                    \
00210     __val;                                                           \
00211   })
00212 
00213 #define lll_cond_lock(lock, private) \
00214   (void) ({                                                          \
00215     int *__futex = &(lock);                                          \
00216     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\
00217                        0) != 0)                                      \
00218       __lll_lock_wait (__futex, private);                            \
00219   })
00220 
00221 #define lll_robust_cond_lock(lock, id, private) \
00222   ({                                                                 \
00223     int *__futex = &(lock);                                          \
00224     int __val = 0;                                                   \
00225     int __id = id | FUTEX_WAITERS;                                   \
00226     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, __id,\
00227                                                         0), 0))             \
00228       __val = __lll_robust_lock_wait (__futex, private);                    \
00229     __val;                                                           \
00230   })
00231 
00232 
00233 extern int __lll_timedlock_wait
00234   (int *futex, const struct timespec *, int private) attribute_hidden;
00235 extern int __lll_robust_timedlock_wait
00236   (int *futex, const struct timespec *, int private) attribute_hidden;
00237 
00238 #define lll_timedlock(lock, abstime, private) \
00239   ({                                                                 \
00240     int *__futex = &(lock);                                          \
00241     int __val = 0;                                                   \
00242     if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
00243                        0) != 0)                                      \
00244       __val = __lll_timedlock_wait (__futex, abstime, private);                    \
00245     __val;                                                           \
00246   })
00247 
00248 #define lll_robust_timedlock(lock, abstime, id, private) \
00249   ({                                                                 \
00250     int *__futex = &(lock);                                          \
00251     int __val = 0;                                                   \
00252     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00253                                                         0), 0))             \
00254       __val = __lll_robust_timedlock_wait (__futex, abstime, private);             \
00255     __val;                                                           \
00256   })
00257 
00258 #define lll_unlock(lock, private) \
00259   ((void) ({                                                         \
00260     int *__futex = &(lock);                                          \
00261     int __val = atomic_exchange_rel (__futex, 0);                           \
00262     if (__builtin_expect (__val > 1, 0))                             \
00263       lll_futex_wake (__futex, 1, private);                                 \
00264   }))
00265 
00266 #define lll_robust_unlock(lock, private) \
00267   ((void) ({                                                         \
00268     int *__futex = &(lock);                                          \
00269     int __val = atomic_exchange_rel (__futex, 0);                           \
00270     if (__builtin_expect (__val & FUTEX_WAITERS, 0))                        \
00271       lll_futex_wake (__futex, 1, private);                                 \
00272   }))
00273 
00274 #define lll_islocked(futex) \
00275   (futex != 0)
00276 
00277 
00278 /* Initializers for lock.  */
00279 #define LLL_LOCK_INITIALIZER              (0)
00280 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00281 
00282 /* The states of a lock are:
00283     0  -  untaken
00284     1  -  taken by one user
00285    >1  -  taken by more users */
00286 
00287 /* The kernel notifies a process which uses CLONE_CLEARTID via futex
00288    wakeup when the clone terminates.  The memory location contains the
00289    thread ID while the clone is running and is reset to zero
00290    afterwards.       */
00291 #define lll_wait_tid(tid) \
00292   do {                                                               \
00293     __typeof (tid) __tid;                                            \
00294     while ((__tid = (tid)) != 0)                                     \
00295       lll_futex_wait (&(tid), __tid, LLL_SHARED);                           \
00296   } while (0)
00297 
00298 extern int __lll_timedwait_tid (int *, const struct timespec *)
00299      attribute_hidden;
00300 
00301 #define lll_timedwait_tid(tid, abstime) \
00302   ({                                                                 \
00303     int __res = 0;                                                   \
00304     if ((tid) != 0)                                                  \
00305       __res = __lll_timedwait_tid (&(tid), (abstime));                      \
00306     __res;                                                           \
00307   })
00308 
00309 #endif /* lowlevellock.h */