6b3d3682da1fd69379b55164ebb64cfdb6c2b5b7
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / rtld-lowlevel.h
1 /* Defintions for lowlevel handling in ld.so.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #ifndef _RTLD_LOWLEVEL_H
21 #define  _RTLD_LOWLEVEL_H 1
22
23 #include <atomic.h>
24 #include <lowlevellock.h>
25
26
27 /* Special multi-reader lock used in ld.so.  */
28 #define __RTLD_MRLOCK_WRITER 1
29 #define __RTLD_MRLOCK_RWAIT 2
30 #define __RTLD_MRLOCK_WWAIT 4
31 #define __RTLD_MRLOCK_RBITS \
32   ~(__RTLD_MRLOCK_WRITER | __RTLD_MRLOCK_RWAIT | __RTLD_MRLOCK_WWAIT)
33 #define __RTLD_MRLOCK_INC 8
34 #define __RTLD_MRLOCK_TRIES 5
35
36
37 typedef int __rtld_mrlock_t;
38
39
40 #define __rtld_mrlock_define(CLASS,NAME) \
41   CLASS __rtld_mrlock_t NAME;
42
43
44 #define _RTLD_MRLOCK_INITIALIZER 0
45 #define __rtld_mrlock_initialize(NAME) \
46   (void) ((NAME) = 0)
47
48
49 #define __rtld_mrlock_lock(lock) \
50   do {                                                                        \
51     __label__ out;                                                            \
52     while (1)                                                                 \
53       {                                                                       \
54         int oldval;                                                           \
55         for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries)             \
56           {                                                                   \
57             oldval = lock;                                                    \
58             while (__builtin_expect ((oldval                                  \
59                                       & (__RTLD_MRLOCK_WRITER                 \
60                                          | __RTLD_MRLOCK_WWAIT))              \
61                                      == 0, 1))                                \
62               {                                                               \
63                 int newval = ((oldval & __RTLD_MRLOCK_RBITS)                  \
64                               + __RTLD_MRLOCK_INC);                           \
65                 int ret = atomic_compare_and_exchange_val_acq (&(lock),       \
66                                                                newval,        \
67                                                                oldval);       \
68                 if (__builtin_expect (ret == oldval, 1))                      \
69                   goto out;                                                   \
70                 oldval = ret;                                                 \
71               }                                                               \
72             atomic_delay ();                                                  \
73           }                                                                   \
74         if ((oldval & __RTLD_MRLOCK_RWAIT) == 0)                              \
75           {                                                                   \
76             atomic_or (&(lock), __RTLD_MRLOCK_RWAIT);                         \
77             oldval |= __RTLD_MRLOCK_RWAIT;                                    \
78           }                                                                   \
79         lll_futex_wait (lock, oldval);                                        \
80       }                                                                       \
81   out:;                                                                       \
82   } while (0)
83
84
85 #define __rtld_mrlock_unlock(lock) \
86   do {                                                                        \
87     int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_INC);       \
88     if (__builtin_expect ((oldval                                             \
89                            & (__RTLD_MRLOCK_RBITS | __RTLD_MRLOCK_WWAIT))     \
90                           == (__RTLD_MRLOCK_INC | __RTLD_MRLOCK_WWAIT), 0))   \
91       /* We have to wake all threads since there might be some queued         \
92          readers already.  */                                                 \
93       lll_futex_wake (&(lock), 0x7fffffff);                                   \
94   } while (0)
95
96
97 /* There can only ever be one thread trying to get the exclusive lock.  */
98 #define __rtld_mrlock_change(lock) \
99   do {                                                                        \
100     __label__ out;                                                            \
101     while (1)                                                                 \
102       {                                                                       \
103         int oldval;                                                           \
104         for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries)             \
105           {                                                                   \
106             oldval = lock;                                                    \
107             while (__builtin_expect ((oldval & __RTLD_MRLOCK_RBITS) == 0, 1)) \
108               {                                                               \
109                 int newval = ((oldval & __RTLD_MRLOCK_RWAIT)                  \
110                               + __RTLD_MRLOCK_WRITER);                        \
111                 int ret = atomic_compare_and_exchange_val_acq (&(lock),       \
112                                                                newval,        \
113                                                                oldval);       \
114                 if (__builtin_expect (ret == oldval, 1))                      \
115                   goto out;                                                   \
116                 oldval = ret;                                                 \
117               }                                                               \
118             atomic_delay ();                                                  \
119           }                                                                   \
120         atomic_or (&(lock), __RTLD_MRLOCK_WWAIT);                             \
121         oldval |= __RTLD_MRLOCK_WWAIT;                                        \
122         lll_futex_wait (lock, oldval);                                        \
123       }                                                                       \
124   out:;                                                                       \
125   } while (0)
126
127
128 #define __rtld_mrlock_done(lock) \
129   do {                           \
130     int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_WRITER);    \
131     if (__builtin_expect ((oldval & __RTLD_MRLOCK_RWAIT) != 0, 0))            \
132       lll_futex_wake (&(lock), 0x7fffffff);                                   \
133   } while (0)
134
135
136 /* Function to wait for variable become zero.  Used in ld.so for
137    reference counters.  */
138 #define __rtld_waitzero(word) \
139   do {                                                                        \
140     while (1)                                                                 \
141       {                                                                       \
142         int val = word;                                                       \
143         if (val == 0)                                                         \
144           break;                                                              \
145         lll_futex_wait (&(word), val);                                        \
146       }                                                                       \
147   } while (0)
148
149
150 #define __rtld_notify(word) \
151   lll_futex_wake (&(word), 1)
152
153 #endif