Use catomic_* operations instead of atomic_*.
[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 = catomic_compare_and_exchange_val_acq (&(lock),      \
66                                                                 newval,       \
67                                                                 oldval);      \
68                 if (__builtin_expect (ret == oldval, 1))                      \
69                   goto out;                                                   \
70               }                                                               \
71             atomic_delay ();                                                  \
72           }                                                                   \
73         if ((oldval & __RTLD_MRLOCK_RWAIT) == 0)                              \
74           {                                                                   \
75             catomic_or (&(lock), __RTLD_MRLOCK_RWAIT);                        \
76             oldval |= __RTLD_MRLOCK_RWAIT;                                    \
77           }                                                                   \
78         lll_futex_wait (lock, oldval);                                        \
79       }                                                                       \
80   out:;                                                                       \
81   } while (0)
82
83
84 #define __rtld_mrlock_unlock(lock) \
85   do {                                                                        \
86     int oldval = catomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_INC);      \
87     if (__builtin_expect ((oldval                                             \
88                            & (__RTLD_MRLOCK_RBITS | __RTLD_MRLOCK_WWAIT))     \
89                           == (__RTLD_MRLOCK_INC | __RTLD_MRLOCK_WWAIT), 0))   \
90       /* We have to wake all threads since there might be some queued         \
91          readers already.  */                                                 \
92       lll_futex_wake (&(lock), 0x7fffffff);                                   \
93   } while (0)
94
95
96 /* There can only ever be one thread trying to get the exclusive lock.  */
97 #define __rtld_mrlock_change(lock) \
98   do {                                                                        \
99     __label__ out;                                                            \
100     while (1)                                                                 \
101       {                                                                       \
102         int oldval;                                                           \
103         for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries)             \
104           {                                                                   \
105             oldval = lock;                                                    \
106             while (__builtin_expect ((oldval & __RTLD_MRLOCK_RBITS) == 0, 1))\
107               {                                                               \
108                 int newval = ((oldval & __RTLD_MRLOCK_RWAIT)                  \
109                               + __RTLD_MRLOCK_WRITER);                        \
110                 int ret = catomic_compare_and_exchange_val_acq (&(lock),      \
111                                                                newval,        \
112                                                                oldval);       \
113                 if (__builtin_expect (ret == oldval, 1))                      \
114                   goto out;                                                   \
115               }                                                               \
116             atomic_delay ();                                                  \
117           }                                                                   \
118         catomic_or (&(lock), __RTLD_MRLOCK_WWAIT);                            \
119         oldval |= __RTLD_MRLOCK_WWAIT;                                        \
120         lll_futex_wait (lock, oldval);                                        \
121       }                                                                       \
122   out:;                                                                       \
123   } while (0)
124
125
126 #define __rtld_mrlock_done(lock) \
127   do {                           \
128     int oldval = catomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_WRITER);   \
129     if (__builtin_expect ((oldval & __RTLD_MRLOCK_RWAIT) != 0, 0))            \
130       lll_futex_wake (&(lock), 0x7fffffff);                                   \
131   } while (0)
132
133
134 /* Function to wait for variable become zero.  Used in ld.so for
135    reference counters.  */
136 #define __rtld_waitzero(word) \
137   do {                                                                        \
138     while (1)                                                                 \
139       {                                                                       \
140         int val = word;                                                       \
141         if (val == 0)                                                         \
142           break;                                                              \
143         lll_futex_wait (&(word), val);                                        \
144       }                                                                       \
145   } while (0)
146
147
148 #define __rtld_notify(word) \
149   lll_futex_wake (&(word), 1)
150
151 #endif