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 Jakub Jelinek <jakub@redhat.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 <ia64intrin.h>
00027 #include <atomic.h>
00028 #include <kernel-features.h>
00029 
00030 #define __NR_futex          1230
00031 #define FUTEX_WAIT          0
00032 #define FUTEX_WAKE          1
00033 #define FUTEX_REQUEUE              3
00034 #define FUTEX_CMP_REQUEUE   4
00035 #define FUTEX_WAKE_OP              5
00036 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE     ((4 << 24) | 1)
00037 #define FUTEX_LOCK_PI              6
00038 #define FUTEX_UNLOCK_PI            7
00039 #define FUTEX_TRYLOCK_PI    8
00040 #define FUTEX_PRIVATE_FLAG  128
00041 
00042 /* Values for 'private' parameter of locking macros.  Yes, the
00043    definition seems to be backwards.  But it is not.  The bit will be
00044    reversed before passing to the system call.  */
00045 #define LLL_PRIVATE  0
00046 #define LLL_SHARED   FUTEX_PRIVATE_FLAG
00047 
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 
00074 /* Delay in spinlock loop.  */
00075 #define BUSY_WAIT_NOP          asm ("hint @pause")
00076 
00077 #define lll_futex_wait(futex, val, private) \
00078   lll_futex_timed_wait (futex, val, NULL, private)
00079 
00080 #define lll_futex_timed_wait(ftx, val, timespec, private)             \
00081 ({                                                             \
00082    DO_INLINE_SYSCALL(futex, 4, (long) (ftx),                          \
00083                    __lll_private_flag (FUTEX_WAIT, private),          \
00084                    (int) (val), (long) (timespec));                   \
00085    _r10 == -1 ? -_retval : _retval;                                   \
00086 })
00087 
00088 #define lll_futex_wake(ftx, nr, private)                       \
00089 ({                                                             \
00090    DO_INLINE_SYSCALL(futex, 3, (long) (ftx),                          \
00091                    __lll_private_flag (FUTEX_WAKE, private),          \
00092                    (int) (nr));                                \
00093    _r10 == -1 ? -_retval : _retval;                                   \
00094 })
00095 
00096 #define lll_robust_dead(futexv, private)                       \
00097 do                                                             \
00098   {                                                            \
00099     int *__futexp = &(futexv);                                        \
00100     atomic_or (__futexp, FUTEX_OWNER_DIED);                           \
00101     DO_INLINE_SYSCALL(futex, 3, (long) __futexp,               \
00102                     __lll_private_flag (FUTEX_WAKE, private), 1);     \
00103   }                                                            \
00104 while (0)
00105 
00106 /* Returns non-zero if error happened, zero if success.  */
00107 #define lll_futex_requeue(ftx, nr_wake, nr_move, mutex, val, private)      \
00108 ({                                                                  \
00109    DO_INLINE_SYSCALL(futex, 6, (long) (ftx),                               \
00110                    __lll_private_flag (FUTEX_CMP_REQUEUE, private),        \
00111                    (int) (nr_wake), (int) (nr_move), (long) (mutex),       \
00112                    (int) val);                                      \
00113    _r10 == -1;                                                             \
00114 })
00115 
00116 /* Returns non-zero if error happened, zero if success.  */
00117 #define lll_futex_wake_unlock(ftx, nr_wake, nr_wake2, ftx2, private)       \
00118 ({                                                                  \
00119    DO_INLINE_SYSCALL(futex, 6, (long) (ftx),                               \
00120                    __lll_private_flag (FUTEX_WAKE_OP, private),            \
00121                    (int) (nr_wake), (int) (nr_wake2), (long) (ftx2),       \
00122                    FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                         \
00123    _r10 == -1;                                                             \
00124 })
00125 
00126 
00127 #define __lll_trylock(futex) \
00128   (atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0)
00129 #define lll_trylock(futex) __lll_trylock (&(futex))
00130 
00131 
00132 #define __lll_robust_trylock(futex, id) \
00133   (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
00134 #define lll_robust_trylock(futex, id) \
00135   __lll_robust_trylock (&(futex), id)
00136 
00137 
00138 #define __lll_cond_trylock(futex) \
00139   (atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0)
00140 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
00141 
00142 
00143 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
00144 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
00145 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
00146 
00147 
00148 #define __lll_lock(futex, private)                                   \
00149   ((void) ({                                                         \
00150     int *__futex = (futex);                                          \
00151     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \
00152                                                         1, 0), 0))    \
00153       {                                                                     \
00154        if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)             \
00155          __lll_lock_wait_private (__futex);                                 \
00156        else                                                          \
00157          __lll_lock_wait (__futex, private);                                \
00158       }                                                                     \
00159   }))
00160 #define lll_lock(futex, private) __lll_lock (&(futex), private)
00161 
00162 
00163 #define __lll_robust_lock(futex, id, private)                               \
00164   ({                                                                 \
00165     int *__futex = (futex);                                          \
00166     int __val = 0;                                                   \
00167                                                                      \
00168     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00169                                                         0), 0))             \
00170       __val = __lll_robust_lock_wait (__futex, private);                    \
00171     __val;                                                           \
00172   })
00173 #define lll_robust_lock(futex, id, private) \
00174   __lll_robust_lock (&(futex), id, private)
00175 
00176 
00177 #define __lll_cond_lock(futex, private)                                     \
00178   ((void) ({                                                         \
00179     int *__futex = (futex);                                          \
00180     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, 2,   \
00181                                                         0), 0))             \
00182       __lll_lock_wait (__futex, private);                            \
00183   }))
00184 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
00185 
00186 
00187 #define __lll_robust_cond_lock(futex, id, private)                          \
00188   ({                                                                 \
00189     int *__futex = (futex);                                          \
00190     int __val = 0;                                                   \
00191     int __id = (id) | FUTEX_WAITERS;                                        \
00192                                                                      \
00193     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \
00194                                                         __id, 0), 0)) \
00195       __val = __lll_robust_lock_wait (__futex, private);                    \
00196     __val;                                                           \
00197   })
00198 #define lll_robust_cond_lock(futex, id, private) \
00199   __lll_robust_cond_lock (&(futex), id, private)
00200 
00201 
00202 extern int __lll_timedlock_wait (int *futex, const struct timespec *,
00203                              int private) attribute_hidden;
00204 extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
00205                                    int private) attribute_hidden;
00206 
00207 
00208 #define __lll_timedlock(futex, abstime, private)                     \
00209   ({                                                                 \
00210      int *__futex = (futex);                                                \
00211      int __val = 0;                                                  \
00212                                                                      \
00213      if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, 1,  \
00214                                                          0), 0))      \
00215        __val = __lll_timedlock_wait (__futex, abstime, private);            \
00216      __val;                                                          \
00217   })
00218 #define lll_timedlock(futex, abstime, private) \
00219   __lll_timedlock (&(futex), abstime, private)
00220 
00221 
00222 #define __lll_robust_timedlock(futex, abstime, id, private)                 \
00223   ({                                                                 \
00224     int *__futex = (futex);                                          \
00225     int __val = 0;                                                   \
00226                                                                      \
00227     if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
00228                                                         0), 0))             \
00229       __val = __lll_robust_timedlock_wait (__futex, abstime, private);             \
00230     __val;                                                           \
00231   })
00232 #define lll_robust_timedlock(futex, abstime, id, private) \
00233   __lll_robust_timedlock (&(futex), abstime, id, private)
00234 
00235 
00236 #define __lll_unlock(futex, private)                                        \
00237   ((void) ({                                                         \
00238     int *__futex = (futex);                                          \
00239     int __val = atomic_exchange_rel (__futex, 0);                           \
00240                                                                      \
00241     if (__builtin_expect (__val > 1, 0))                             \
00242       lll_futex_wake (__futex, 1, private);                                 \
00243   }))
00244 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
00245 
00246 
00247 #define __lll_robust_unlock(futex, private)                                 \
00248   ((void) ({                                                         \
00249     int *__futex = (futex);                                          \
00250     int __val = atomic_exchange_rel (__futex, 0);                           \
00251                                                                      \
00252     if (__builtin_expect (__val & FUTEX_WAITERS, 0))                        \
00253       lll_futex_wake (__futex, 1, private);                                 \
00254   }))
00255 #define lll_robust_unlock(futex, private) \
00256   __lll_robust_unlock(&(futex), private)
00257 
00258 
00259 #define lll_islocked(futex) \
00260   (futex != 0)
00261 
00262 /* Initializers for lock.  */
00263 #define LLL_LOCK_INITIALIZER              (0)
00264 #define LLL_LOCK_INITIALIZER_LOCKED       (1)
00265 
00266 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
00267    wakeup when the clone terminates.  The memory location contains the
00268    thread ID while the clone is running and is reset to zero
00269    afterwards.       */
00270 #define lll_wait_tid(tid) \
00271   do                                             \
00272     {                                            \
00273       __typeof (tid) __tid;                      \
00274       while ((__tid = (tid)) != 0)               \
00275        lll_futex_wait (&(tid), __tid, LLL_SHARED);      \
00276     }                                            \
00277   while (0)
00278 
00279 extern int __lll_timedwait_tid (int *, const struct timespec *)
00280      attribute_hidden;
00281 
00282 #define lll_timedwait_tid(tid, abstime) \
00283   ({                                             \
00284     int __res = 0;                               \
00285     if ((tid) != 0)                              \
00286       __res = __lll_timedwait_tid (&(tid), (abstime));  \
00287     __res;                                       \
00288   })
00289 
00290 #endif /* lowlevellock.h */