1 |
737 |
jeremybenn |
/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
|
2 |
|
|
Contributed by Richard Henderson <rth@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 <stdlib.h>
|
26 |
|
|
#include <string.h>
|
27 |
|
|
#include <ctype.h>
|
28 |
|
|
#include "libitm_i.h"
|
29 |
|
|
|
30 |
|
|
// The default TM method used when starting a new transaction. Initialized
|
31 |
|
|
// in number_of_threads_changed() below.
|
32 |
|
|
// Access to this variable is always synchronized with help of the serial
|
33 |
|
|
// lock, except one read access that happens in decide_begin_dispatch() before
|
34 |
|
|
// a transaction has become active (by acquiring the serial lock in read or
|
35 |
|
|
// write mode). The default_dispatch is only changed and initialized in
|
36 |
|
|
// serial mode. Transactions stay active when they restart (see beginend.cc),
|
37 |
|
|
// thus decide_retry_strategy() can expect default_dispatch to be unmodified.
|
38 |
|
|
// See decide_begin_dispatch() for further comments.
|
39 |
|
|
static std::atomic<GTM::abi_dispatch*> default_dispatch;
|
40 |
|
|
// The default TM method as requested by the user, if any.
|
41 |
|
|
static GTM::abi_dispatch* default_dispatch_user = 0;
|
42 |
|
|
|
43 |
|
|
void
|
44 |
|
|
GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r)
|
45 |
|
|
{
|
46 |
|
|
struct abi_dispatch *disp = abi_disp ();
|
47 |
|
|
|
48 |
|
|
this->restart_reason[r]++;
|
49 |
|
|
this->restart_total++;
|
50 |
|
|
|
51 |
|
|
if (r == RESTART_INIT_METHOD_GROUP)
|
52 |
|
|
{
|
53 |
|
|
// A re-initializations of the method group has been requested. Switch
|
54 |
|
|
// to serial mode, initialize, and resume normal operation.
|
55 |
|
|
if ((state & STATE_SERIAL) == 0)
|
56 |
|
|
{
|
57 |
|
|
// We have to eventually re-init the method group. Therefore,
|
58 |
|
|
// we cannot just upgrade to a write lock here because this could
|
59 |
|
|
// fail forever when other transactions execute in serial mode.
|
60 |
|
|
// However, giving up the read lock then means that a change of the
|
61 |
|
|
// method group could happen in-between, so check that we're not
|
62 |
|
|
// re-initializing without a need.
|
63 |
|
|
// ??? Note that we can still re-initialize too often, but avoiding
|
64 |
|
|
// that would increase code complexity, which seems unnecessary
|
65 |
|
|
// given that re-inits should be very infrequent.
|
66 |
|
|
serial_lock.read_unlock(this);
|
67 |
|
|
serial_lock.write_lock();
|
68 |
|
|
if (disp->get_method_group()
|
69 |
|
|
== default_dispatch.load(memory_order_relaxed)
|
70 |
|
|
->get_method_group())
|
71 |
|
|
// Still the same method group.
|
72 |
|
|
disp->get_method_group()->reinit();
|
73 |
|
|
serial_lock.write_unlock();
|
74 |
|
|
// Also, we're making the transaction inactive, so when we become
|
75 |
|
|
// active again, some other thread might have changed the default
|
76 |
|
|
// dispatch, so we run the same code as for the first execution
|
77 |
|
|
// attempt.
|
78 |
|
|
disp = decide_begin_dispatch(prop);
|
79 |
|
|
set_abi_disp(disp);
|
80 |
|
|
}
|
81 |
|
|
else
|
82 |
|
|
// We are a serial transaction already, which makes things simple.
|
83 |
|
|
disp->get_method_group()->reinit();
|
84 |
|
|
|
85 |
|
|
return;
|
86 |
|
|
}
|
87 |
|
|
|
88 |
|
|
bool retry_irr = (r == RESTART_SERIAL_IRR);
|
89 |
|
|
bool retry_serial = (retry_irr || this->restart_total > 100);
|
90 |
|
|
|
91 |
|
|
// We assume closed nesting to be infrequently required, so just use
|
92 |
|
|
// dispatch_serial (with undo logging) if required.
|
93 |
|
|
if (r == RESTART_CLOSED_NESTING)
|
94 |
|
|
retry_serial = true;
|
95 |
|
|
|
96 |
|
|
if (retry_serial)
|
97 |
|
|
{
|
98 |
|
|
// In serialirr_mode we can succeed with the upgrade to
|
99 |
|
|
// write-lock but fail the trycommit. In any case, if the
|
100 |
|
|
// write lock is not yet held, grab it. Don't do this with
|
101 |
|
|
// an upgrade, since we've no need to preserve the state we
|
102 |
|
|
// acquired with the read.
|
103 |
|
|
// Note that we will be restarting with either dispatch_serial or
|
104 |
|
|
// dispatch_serialirr, which are compatible with all TM methods; if
|
105 |
|
|
// we would retry with a different method, we would have to first check
|
106 |
|
|
// whether the default dispatch or the method group have changed. Also,
|
107 |
|
|
// the caller must have rolled back the previous transaction, so we
|
108 |
|
|
// don't have to worry about things such as privatization.
|
109 |
|
|
if ((this->state & STATE_SERIAL) == 0)
|
110 |
|
|
{
|
111 |
|
|
this->state |= STATE_SERIAL;
|
112 |
|
|
serial_lock.read_unlock (this);
|
113 |
|
|
serial_lock.write_lock ();
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
// We can retry with dispatch_serialirr if the transaction
|
117 |
|
|
// doesn't contain an abort and if we don't need closed nesting.
|
118 |
|
|
if ((this->prop & pr_hasNoAbort) && (r != RESTART_CLOSED_NESTING))
|
119 |
|
|
retry_irr = true;
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
// Note that we can just use serial mode here without having to switch
|
123 |
|
|
// TM method sets because serial mode is compatible with all of them.
|
124 |
|
|
if (retry_irr)
|
125 |
|
|
{
|
126 |
|
|
this->state = (STATE_SERIAL | STATE_IRREVOCABLE);
|
127 |
|
|
disp = dispatch_serialirr ();
|
128 |
|
|
set_abi_disp (disp);
|
129 |
|
|
}
|
130 |
|
|
else if (retry_serial)
|
131 |
|
|
{
|
132 |
|
|
disp = dispatch_serial();
|
133 |
|
|
set_abi_disp (disp);
|
134 |
|
|
}
|
135 |
|
|
}
|
136 |
|
|
|
137 |
|
|
|
138 |
|
|
// Decides which TM method should be used on the first attempt to run this
|
139 |
|
|
// transaction. Acquires the serial lock and sets transaction state
|
140 |
|
|
// according to the chosen TM method.
|
141 |
|
|
GTM::abi_dispatch*
|
142 |
|
|
GTM::gtm_thread::decide_begin_dispatch (uint32_t prop)
|
143 |
|
|
{
|
144 |
|
|
abi_dispatch* dd;
|
145 |
|
|
// TODO Pay more attention to prop flags (eg, *omitted) when selecting
|
146 |
|
|
// dispatch.
|
147 |
|
|
// ??? We go irrevocable eagerly here, which is not always good for
|
148 |
|
|
// performance. Don't do this?
|
149 |
|
|
if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode))
|
150 |
|
|
dd = dispatch_serialirr();
|
151 |
|
|
|
152 |
|
|
else
|
153 |
|
|
{
|
154 |
|
|
// Load the default dispatch. We're not an active transaction and so it
|
155 |
|
|
// can change concurrently but will still be some valid dispatch.
|
156 |
|
|
// Relaxed memory order is okay because we expect each dispatch to be
|
157 |
|
|
// constructed properly already (at least that its closed_nesting() and
|
158 |
|
|
// closed_nesting_alternatives() will return sensible values). It is
|
159 |
|
|
// harmless if we incorrectly chose the serial or serialirr methods, and
|
160 |
|
|
// for all other methods we will acquire the serial lock in read mode
|
161 |
|
|
// and load the default dispatch again.
|
162 |
|
|
abi_dispatch* dd_orig = default_dispatch.load(memory_order_relaxed);
|
163 |
|
|
dd = dd_orig;
|
164 |
|
|
|
165 |
|
|
// If we might need closed nesting and the default dispatch has an
|
166 |
|
|
// alternative that supports closed nesting, use it.
|
167 |
|
|
// ??? We could choose another TM method that we know supports closed
|
168 |
|
|
// nesting but isn't the default (e.g., dispatch_serial()). However, we
|
169 |
|
|
// assume that aborts that need closed nesting are infrequent, so don't
|
170 |
|
|
// choose a non-default method until we have to actually restart the
|
171 |
|
|
// transaction.
|
172 |
|
|
if (!(prop & pr_hasNoAbort) && !dd->closed_nesting()
|
173 |
|
|
&& dd->closed_nesting_alternative())
|
174 |
|
|
dd = dd->closed_nesting_alternative();
|
175 |
|
|
|
176 |
|
|
if (dd != dispatch_serial() && dd != dispatch_serialirr())
|
177 |
|
|
{
|
178 |
|
|
// The current dispatch is supposedly a non-serial one. Become an
|
179 |
|
|
// active transaction and verify this. Relaxed memory order is fine
|
180 |
|
|
// because the serial lock itself will have established
|
181 |
|
|
// happens-before for any change to the selected dispatch.
|
182 |
|
|
serial_lock.read_lock (this);
|
183 |
|
|
if (default_dispatch.load(memory_order_relaxed) == dd_orig)
|
184 |
|
|
return dd;
|
185 |
|
|
|
186 |
|
|
// If we raced with a concurrent modification of default_dispatch,
|
187 |
|
|
// just fall back to serialirr. The dispatch choice might not be
|
188 |
|
|
// up-to-date anymore, but this is harmless.
|
189 |
|
|
serial_lock.read_unlock (this);
|
190 |
|
|
dd = dispatch_serialirr();
|
191 |
|
|
}
|
192 |
|
|
}
|
193 |
|
|
|
194 |
|
|
// We are some kind of serial transaction.
|
195 |
|
|
serial_lock.write_lock();
|
196 |
|
|
if (dd == dispatch_serialirr())
|
197 |
|
|
state = STATE_SERIAL | STATE_IRREVOCABLE;
|
198 |
|
|
else
|
199 |
|
|
state = STATE_SERIAL;
|
200 |
|
|
return dd;
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
|
204 |
|
|
void
|
205 |
|
|
GTM::gtm_thread::set_default_dispatch(GTM::abi_dispatch* disp)
|
206 |
|
|
{
|
207 |
|
|
abi_dispatch* dd = default_dispatch.load(memory_order_relaxed);
|
208 |
|
|
if (dd == disp)
|
209 |
|
|
return;
|
210 |
|
|
if (dd)
|
211 |
|
|
{
|
212 |
|
|
// If we are switching method groups, initialize and shut down properly.
|
213 |
|
|
if (dd->get_method_group() != disp->get_method_group())
|
214 |
|
|
{
|
215 |
|
|
dd->get_method_group()->fini();
|
216 |
|
|
disp->get_method_group()->init();
|
217 |
|
|
}
|
218 |
|
|
}
|
219 |
|
|
else
|
220 |
|
|
disp->get_method_group()->init();
|
221 |
|
|
default_dispatch.store(disp, memory_order_relaxed);
|
222 |
|
|
}
|
223 |
|
|
|
224 |
|
|
|
225 |
|
|
static GTM::abi_dispatch*
|
226 |
|
|
parse_default_method()
|
227 |
|
|
{
|
228 |
|
|
const char *env = getenv("ITM_DEFAULT_METHOD");
|
229 |
|
|
GTM::abi_dispatch* disp = 0;
|
230 |
|
|
if (env == NULL)
|
231 |
|
|
return 0;
|
232 |
|
|
|
233 |
|
|
while (isspace((unsigned char) *env))
|
234 |
|
|
++env;
|
235 |
|
|
if (strncmp(env, "serialirr_onwrite", 17) == 0)
|
236 |
|
|
{
|
237 |
|
|
disp = GTM::dispatch_serialirr_onwrite();
|
238 |
|
|
env += 17;
|
239 |
|
|
}
|
240 |
|
|
else if (strncmp(env, "serialirr", 9) == 0)
|
241 |
|
|
{
|
242 |
|
|
disp = GTM::dispatch_serialirr();
|
243 |
|
|
env += 9;
|
244 |
|
|
}
|
245 |
|
|
else if (strncmp(env, "serial", 6) == 0)
|
246 |
|
|
{
|
247 |
|
|
disp = GTM::dispatch_serial();
|
248 |
|
|
env += 6;
|
249 |
|
|
}
|
250 |
|
|
else if (strncmp(env, "gl_wt", 5) == 0)
|
251 |
|
|
{
|
252 |
|
|
disp = GTM::dispatch_gl_wt();
|
253 |
|
|
env += 5;
|
254 |
|
|
}
|
255 |
|
|
else if (strncmp(env, "ml_wt", 5) == 0)
|
256 |
|
|
{
|
257 |
|
|
disp = GTM::dispatch_ml_wt();
|
258 |
|
|
env += 5;
|
259 |
|
|
}
|
260 |
|
|
else
|
261 |
|
|
goto unknown;
|
262 |
|
|
|
263 |
|
|
while (isspace((unsigned char) *env))
|
264 |
|
|
++env;
|
265 |
|
|
if (*env == '\0')
|
266 |
|
|
return disp;
|
267 |
|
|
|
268 |
|
|
unknown:
|
269 |
|
|
GTM::GTM_error("Unknown TM method in environment variable "
|
270 |
|
|
"ITM_DEFAULT_METHOD\n");
|
271 |
|
|
return 0;
|
272 |
|
|
}
|
273 |
|
|
|
274 |
|
|
// Gets notifications when the number of registered threads changes. This is
|
275 |
|
|
// used to initialize the method set choice and trigger straightforward choice
|
276 |
|
|
// adaption.
|
277 |
|
|
// This must be called only by serial threads.
|
278 |
|
|
void
|
279 |
|
|
GTM::gtm_thread::number_of_threads_changed(unsigned previous, unsigned now)
|
280 |
|
|
{
|
281 |
|
|
if (previous == 0)
|
282 |
|
|
{
|
283 |
|
|
// No registered threads before, so initialize.
|
284 |
|
|
static bool initialized = false;
|
285 |
|
|
if (!initialized)
|
286 |
|
|
{
|
287 |
|
|
initialized = true;
|
288 |
|
|
// Check for user preferences here.
|
289 |
|
|
default_dispatch = 0;
|
290 |
|
|
default_dispatch_user = parse_default_method();
|
291 |
|
|
}
|
292 |
|
|
}
|
293 |
|
|
else if (now == 0)
|
294 |
|
|
{
|
295 |
|
|
// No registered threads anymore. The dispatch based on serial mode do
|
296 |
|
|
// not have any global state, so this effectively shuts down properly.
|
297 |
|
|
set_default_dispatch(dispatch_serialirr());
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
if (now == 1)
|
301 |
|
|
{
|
302 |
|
|
// Only one thread, so use a serializing method.
|
303 |
|
|
// ??? If we don't have a fast serial mode implementation, it might be
|
304 |
|
|
// better to use the global lock method set here.
|
305 |
|
|
if (default_dispatch_user && default_dispatch_user->supports(now))
|
306 |
|
|
set_default_dispatch(default_dispatch_user);
|
307 |
|
|
else
|
308 |
|
|
set_default_dispatch(dispatch_serialirr());
|
309 |
|
|
}
|
310 |
|
|
else if (now > 1 && previous <= 1)
|
311 |
|
|
{
|
312 |
|
|
// More than one thread, use the default method.
|
313 |
|
|
if (default_dispatch_user && default_dispatch_user->supports(now))
|
314 |
|
|
set_default_dispatch(default_dispatch_user);
|
315 |
|
|
else
|
316 |
|
|
{
|
317 |
|
|
abi_dispatch* a = dispatch_ml_wt();
|
318 |
|
|
if (a->supports(now))
|
319 |
|
|
set_default_dispatch(a);
|
320 |
|
|
else
|
321 |
|
|
// Serial-irrevocable mode always works.
|
322 |
|
|
set_default_dispatch(dispatch_serialirr());
|
323 |
|
|
}
|
324 |
|
|
}
|
325 |
|
|
}
|