gcc50: Disconnect from buildworld.
[dragonfly.git] / contrib / gcc-5.0 / libitm / config / linux / rwlock.cc
1 /* Copyright (C) 2011-2015 Free Software Foundation, Inc.
2    Contributed by Torvald Riegel <triegel@redhat.com>.
3
4    This file is part of the GNU Transactional Memory Library (libitm).
5
6    Libitm is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    more details.
15
16    Under Section 7 of GPL version 3, you are granted additional
17    permissions described in the GCC Runtime Library Exception, version
18    3.1, as published by the Free Software Foundation.
19
20    You should have received a copy of the GNU General Public License and
21    a copy of the GCC Runtime Library Exception along with this program;
22    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23    <http://www.gnu.org/licenses/>.  */
24
25 #include "libitm_i.h"
26 #include "futex.h"
27 #include <limits.h>
28
29 namespace GTM HIDDEN {
30
31 // Acquire a RW lock for reading.
32
33 void
34 gtm_rwlock::read_lock (gtm_thread *tx)
35 {
36   for (;;)
37     {
38       // Fast path: first announce our intent to read, then check for
39       // conflicting intents to write.  The fence ensures that this happens
40       // in exactly this order.
41       tx->shared_state.store (0, memory_order_relaxed);
42       atomic_thread_fence (memory_order_seq_cst);
43       if (likely (writers.load (memory_order_relaxed) == 0))
44         return;
45
46       // There seems to be an active, waiting, or confirmed writer, so enter
47       // the futex-based slow path.
48
49       // Before waiting, we clear our read intent check whether there are any
50       // writers that might potentially wait for readers. If so, wake them.
51       // We need the barrier here for the same reason that we need it in
52       // read_unlock().
53       // TODO Potentially too many wake-ups. See comments in read_unlock().
54       tx->shared_state.store (-1, memory_order_relaxed);
55       atomic_thread_fence (memory_order_seq_cst);
56       if (writer_readers.load (memory_order_relaxed) > 0)
57         {
58           writer_readers.store (0, memory_order_relaxed);
59           futex_wake(&writer_readers, 1);
60         }
61
62       // Signal that there are waiting readers and wait until there is no
63       // writer anymore.
64       // TODO Spin here on writers for a while. Consider whether we woke
65       // any writers before?
66       while (writers.load (memory_order_relaxed))
67         {
68           // An active writer. Wait until it has finished. To avoid lost
69           // wake-ups, we need to use Dekker-like synchronization.
70           // Note that we cannot reset readers to zero when we see that there
71           // are no writers anymore after the barrier because this pending
72           // store could then lead to lost wake-ups at other readers.
73           readers.store (1, memory_order_relaxed);
74           atomic_thread_fence (memory_order_seq_cst);
75           if (writers.load (memory_order_relaxed))
76             futex_wait(&readers, 1);
77           else
78             {
79               // There is no writer, actually.  However, we can have enabled
80               // a futex_wait in other readers by previously setting readers
81               // to 1, so we have to wake them up because there is no writer
82               // that will do that.  We don't know whether the wake-up is
83               // really necessary, but we can get lost wake-up situations
84               // otherwise.
85               // No additional barrier nor a nonrelaxed load is required due
86               // to coherency constraints.  write_unlock() checks readers to
87               // see if any wake-up is necessary, but it is not possible that
88               // a reader's store prevents a required later writer wake-up;
89               // If the waking reader's store (value 0) is in modification
90               // order after the waiting readers store (value 1), then the
91               // latter will have to read 0 in the futex due to coherency
92               // constraints and the happens-before enforced by the futex
93               // (paragraph 6.10 in the standard, 6.19.4 in the Batty et al
94               // TR); second, the writer will be forced to read in
95               // modification order too due to Dekker-style synchronization
96               // with the waiting reader (see write_unlock()).
97               // ??? Can we avoid the wake-up if readers is zero (like in
98               // write_unlock())?  Anyway, this might happen too infrequently
99               // to improve performance significantly.
100               readers.store (0, memory_order_relaxed);
101               futex_wake(&readers, INT_MAX);
102             }
103         }
104
105       // And we try again to acquire a read lock.
106     }
107 }
108
109
110 // Acquire a RW lock for writing. Generic version that also works for
111 // upgrades.
112 // Note that an upgrade might fail (and thus waste previous work done during
113 // this transaction) if there is another thread that tried to go into serial
114 // mode earlier (i.e., upgrades do not have higher priority than pure writers).
115 // However, this seems rare enough to not consider it further as we need both
116 // a non-upgrade writer and a writer to happen to switch to serial mode
117 // concurrently. If we'd want to handle this, a writer waiting for readers
118 // would have to coordinate with later arriving upgrades and hand over the
119 // lock to them, including the the reader-waiting state. We can try to support
120 // this if this will actually happen often enough in real workloads.
121
122 bool
123 gtm_rwlock::write_lock_generic (gtm_thread *tx)
124 {
125   // Try to acquire the write lock.
126   int w = 0;
127   if (unlikely (!writers.compare_exchange_strong (w, 1)))
128     {
129       // If this is an upgrade, we must not wait for other writers or
130       // upgrades.
131       if (tx != 0)
132         return false;
133
134       // There is already a writer. If there are no other waiting writers,
135       // switch to contended mode.  We need seq_cst memory order to make the
136       // Dekker-style synchronization work.
137       if (w != 2)
138         w = writers.exchange (2);
139       while (w != 0)
140         {
141           futex_wait(&writers, 2);
142           w = writers.exchange (2);
143         }
144     }
145
146   // We have acquired the writer side of the R/W lock. Now wait for any
147   // readers that might still be active.
148   // We don't need an extra barrier here because the CAS and the xchg
149   // operations have full barrier semantics already.
150   // TODO In the worst case, this requires one wait/wake pair for each
151   // active reader. Reduce this!
152   for (gtm_thread *it = gtm_thread::list_of_threads; it != 0;
153       it = it->next_thread)
154     {
155       if (it == tx)
156         continue;
157       // Use a loop here to check reader flags again after waiting.
158       while (it->shared_state.load (memory_order_relaxed)
159           != ~(typeof it->shared_state)0)
160         {
161           // An active reader. Wait until it has finished. To avoid lost
162           // wake-ups, we need to use Dekker-like synchronization.
163           // Note that we can reset writer_readers to zero when we see after
164           // the barrier that the reader has finished in the meantime;
165           // however, this is only possible because we are the only writer.
166           // TODO Spin for a while on this reader flag.
167           writer_readers.store (1, memory_order_relaxed);
168           atomic_thread_fence (memory_order_seq_cst);
169           if (it->shared_state.load (memory_order_relaxed)
170               != ~(typeof it->shared_state)0)
171             futex_wait(&writer_readers, 1);
172           else
173             writer_readers.store (0, memory_order_relaxed);
174         }
175     }
176
177   return true;
178 }
179
180 // Acquire a RW lock for writing.
181
182 void
183 gtm_rwlock::write_lock ()
184 {
185   write_lock_generic (0);
186 }
187
188
189 // Upgrade a RW lock that has been locked for reading to a writing lock.
190 // Do this without possibility of another writer incoming.  Return false
191 // if this attempt fails (i.e. another thread also upgraded).
192
193 bool
194 gtm_rwlock::write_upgrade (gtm_thread *tx)
195 {
196   return write_lock_generic (tx);
197 }
198
199
200 // Has to be called iff the previous upgrade was successful and after it is
201 // safe for the transaction to not be marked as a reader anymore.
202
203 void
204 gtm_rwlock::write_upgrade_finish (gtm_thread *tx)
205 {
206   // We are not a reader anymore.  This is only safe to do after we have
207   // acquired the writer lock.
208   tx->shared_state.store (-1, memory_order_release);
209 }
210
211
212 // Release a RW lock from reading.
213
214 void
215 gtm_rwlock::read_unlock (gtm_thread *tx)
216 {
217   // We only need release memory order here because of privatization safety
218   // (this ensures that marking the transaction as inactive happens after
219   // any prior data accesses by this transaction, and that neither the
220   // compiler nor the hardware order this store earlier).
221   // ??? We might be able to avoid this release here if the compiler can't
222   // merge the release fence with the subsequent seq_cst fence.
223   tx->shared_state.store (-1, memory_order_release);
224
225   // If there is a writer waiting for readers, wake it up.  We need the fence
226   // to avoid lost wake-ups.  Furthermore, the privatization safety
227   // implementation in gtm_thread::try_commit() relies on the existence of
228   // this seq_cst fence.
229   // ??? We might not be the last active reader, so the wake-up might happen
230   // too early. How do we avoid this without slowing down readers too much?
231   // Each reader could scan the list of txns for other active readers but
232   // this can result in many cache misses. Use combining instead?
233   // TODO Sends out one wake-up for each reader in the worst case.
234   atomic_thread_fence (memory_order_seq_cst);
235   if (unlikely (writer_readers.load (memory_order_relaxed) > 0))
236     {
237       // No additional barrier needed here (see write_unlock()).
238       writer_readers.store (0, memory_order_relaxed);
239       futex_wake(&writer_readers, 1);
240     }
241 }
242
243
244 // Release a RW lock from writing.
245
246 void
247 gtm_rwlock::write_unlock ()
248 {
249   // This needs to have seq_cst memory order.
250   if (writers.fetch_sub (1) == 2)
251     {
252       // There might be waiting writers, so wake them.
253       writers.store (0, memory_order_relaxed);
254       if (futex_wake(&writers, 1) == 0)
255         {
256           // If we did not wake any waiting writers, we might indeed be the
257           // last writer (this can happen because write_lock_generic()
258           // exchanges 0 or 1 to 2 and thus might go to contended mode even if
259           // no other thread holds the write lock currently). Therefore, we
260           // have to wake up readers here as well.  Execute a barrier after
261           // the previous relaxed reset of writers (Dekker-style), and fall
262           // through to the normal reader wake-up code.
263           atomic_thread_fence (memory_order_seq_cst);
264         }
265       else
266         return;
267     }
268   // No waiting writers, so wake up all waiting readers.
269   // Because the fetch_and_sub is a full barrier already, we don't need
270   // another barrier here (as in read_unlock()).
271   if (readers.load (memory_order_relaxed) > 0)
272     {
273       // No additional barrier needed here.  The previous load must be in
274       // modification order because of the coherency constraints.  Late stores
275       // by a reader are not a problem because readers do Dekker-style
276       // synchronization on writers.
277       readers.store (0, memory_order_relaxed);
278       futex_wake(&readers, INT_MAX);
279     }
280 }
281
282 } // namespace GTM