]> git.ipfire.org Git - thirdparty/gcc.git/blame - libitm/retry.cc
re PR tree-optimization/52286 (wrong code bug)
[thirdparty/gcc.git] / libitm / retry.cc
CommitLineData
0a35513e
AH
1/* 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.
31static GTM::abi_dispatch* default_dispatch = 0;
32// The default TM method as requested by the user, if any.
33static GTM::abi_dispatch* default_dispatch_user = 0;
34
35void
36GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r)
37{
38 struct abi_dispatch *disp = abi_disp ();
39
40 this->restart_reason[r]++;
41 this->restart_total++;
42
43 if (r == RESTART_INIT_METHOD_GROUP)
44 {
45 // A re-initializations of the method group has been requested. Switch
46 // to serial mode, initialize, and resume normal operation.
47 if ((state & STATE_SERIAL) == 0)
48 {
49 // We have to eventually re-init the method group. Therefore,
50 // we cannot just upgrade to a write lock here because this could
51 // fail forever when other transactions execute in serial mode.
52 // However, giving up the read lock then means that a change of the
53 // method group could happen in-between, so check that we're not
54 // re-initializing without a need.
55 // ??? Note that we can still re-initialize too often, but avoiding
56 // that would increase code complexity, which seems unnecessary
57 // given that re-inits should be very infrequent.
58 serial_lock.read_unlock(this);
59 serial_lock.write_lock();
60 if (disp->get_method_group() == default_dispatch->get_method_group())
5b9cf5d2
TR
61 // Still the same method group.
62 disp->get_method_group()->reinit();
0a35513e
AH
63 serial_lock.write_unlock();
64 serial_lock.read_lock(this);
65 if (disp->get_method_group() != default_dispatch->get_method_group())
66 {
67 disp = default_dispatch;
68 set_abi_disp(disp);
69 }
70 }
71 else
5b9cf5d2
TR
72 // We are a serial transaction already, which makes things simple.
73 disp->get_method_group()->reinit();
0a35513e
AH
74 }
75
76 bool retry_irr = (r == RESTART_SERIAL_IRR);
77 bool retry_serial = (retry_irr || this->restart_total > 100);
78
79 // We assume closed nesting to be infrequently required, so just use
80 // dispatch_serial (with undo logging) if required.
81 if (r == RESTART_CLOSED_NESTING)
82 retry_serial = true;
83
84 if (retry_serial)
85 {
86 // In serialirr_mode we can succeed with the upgrade to
87 // write-lock but fail the trycommit. In any case, if the
88 // write lock is not yet held, grab it. Don't do this with
89 // an upgrade, since we've no need to preserve the state we
90 // acquired with the read.
91 // Note that we will be restarting with either dispatch_serial or
92 // dispatch_serialirr, which are compatible with all TM methods; if
93 // we would retry with a different method, we would have to first check
94 // whether the default dispatch or the method group have changed. Also,
95 // the caller must have rolled back the previous transaction, so we
96 // don't have to worry about things such as privatization.
97 if ((this->state & STATE_SERIAL) == 0)
98 {
99 this->state |= STATE_SERIAL;
100 serial_lock.read_unlock (this);
101 serial_lock.write_lock ();
102 }
103
104 // We can retry with dispatch_serialirr if the transaction
105 // doesn't contain an abort and if we don't need closed nesting.
106 if ((this->prop & pr_hasNoAbort) && (r != RESTART_CLOSED_NESTING))
107 retry_irr = true;
108 }
109
110 // Note that we can just use serial mode here without having to switch
111 // TM method sets because serial mode is compatible with all of them.
112 if (retry_irr)
113 {
114 this->state = (STATE_SERIAL | STATE_IRREVOCABLE);
115 disp = dispatch_serialirr ();
116 set_abi_disp (disp);
117 }
118 else if (retry_serial)
119 {
120 disp = dispatch_serial();
121 set_abi_disp (disp);
122 }
123}
124
125
126// Decides which TM method should be used on the first attempt to run this
127// transaction.
128GTM::abi_dispatch*
129GTM::gtm_thread::decide_begin_dispatch (uint32_t prop)
130{
131 // TODO Pay more attention to prop flags (eg, *omitted) when selecting
132 // dispatch.
133 if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode))
134 return dispatch_serialirr();
135
136 // If we might need closed nesting and the default dispatch has an
137 // alternative that supports closed nesting, use it.
138 // ??? We could choose another TM method that we know supports closed
139 // nesting but isn't the default (e.g., dispatch_serial()). However, we
140 // assume that aborts that need closed nesting are infrequent, so don't
141 // choose a non-default method until we have to actually restart the
142 // transaction.
143 if (!(prop & pr_hasNoAbort) && !default_dispatch->closed_nesting()
144 && default_dispatch->closed_nesting_alternative())
145 return default_dispatch->closed_nesting_alternative();
146
147 // No special case, just use the default dispatch.
148 return default_dispatch;
149}
150
151
152void
153GTM::gtm_thread::set_default_dispatch(GTM::abi_dispatch* disp)
154{
155 if (default_dispatch == disp)
156 return;
157 if (default_dispatch)
158 {
159 // If we are switching method groups, initialize and shut down properly.
160 if (default_dispatch->get_method_group() != disp->get_method_group())
161 {
162 default_dispatch->get_method_group()->fini();
163 disp->get_method_group()->init();
164 }
165 }
166 else
167 disp->get_method_group()->init();
168 default_dispatch = disp;
169}
170
171
172static GTM::abi_dispatch*
173parse_default_method()
174{
175 const char *env = getenv("ITM_DEFAULT_METHOD");
176 GTM::abi_dispatch* disp = 0;
177 if (env == NULL)
178 return 0;
179
180 while (isspace((unsigned char) *env))
181 ++env;
182 if (strncmp(env, "serialirr_onwrite", 17) == 0)
183 {
184 disp = GTM::dispatch_serialirr_onwrite();
185 env += 17;
186 }
187 else if (strncmp(env, "serialirr", 9) == 0)
188 {
189 disp = GTM::dispatch_serialirr();
190 env += 9;
191 }
192 else if (strncmp(env, "serial", 6) == 0)
193 {
194 disp = GTM::dispatch_serial();
195 env += 6;
196 }
197 else if (strncmp(env, "gl_wt", 5) == 0)
198 {
199 disp = GTM::dispatch_gl_wt();
200 env += 5;
201 }
31772c95
TR
202 else if (strncmp(env, "ml_wt", 5) == 0)
203 {
204 disp = GTM::dispatch_ml_wt();
205 env += 5;
206 }
0a35513e
AH
207 else
208 goto unknown;
209
210 while (isspace((unsigned char) *env))
211 ++env;
212 if (*env == '\0')
213 return disp;
214
215 unknown:
216 GTM::GTM_error("Unknown TM method in environment variable "
217 "ITM_DEFAULT_METHOD\n");
218 return 0;
219}
220
221// Gets notifications when the number of registered threads changes. This is
222// used to initialize the method set choice and trigger straightforward choice
223// adaption.
224// This must be called only by serial threads.
225void
226GTM::gtm_thread::number_of_threads_changed(unsigned previous, unsigned now)
227{
228 if (previous == 0)
229 {
230 // No registered threads before, so initialize.
231 static bool initialized = false;
232 if (!initialized)
233 {
234 initialized = true;
235 // Check for user preferences here.
236 default_dispatch_user = parse_default_method();
237 }
238 }
239 else if (now == 0)
240 {
241 // No registered threads anymore. The dispatch based on serial mode do
242 // not have any global state, so this effectively shuts down properly.
243 set_default_dispatch(dispatch_serialirr());
244 }
245
246 if (now == 1)
247 {
248 // Only one thread, so use a serializing method.
249 // ??? If we don't have a fast serial mode implementation, it might be
250 // better to use the global lock method set here.
5b9cf5d2 251 if (default_dispatch_user && default_dispatch_user->supports(now))
0a35513e
AH
252 set_default_dispatch(default_dispatch_user);
253 else
254 set_default_dispatch(dispatch_serialirr());
255 }
256 else if (now > 1 && previous <= 1)
257 {
258 // More than one thread, use the default method.
5b9cf5d2 259 if (default_dispatch_user && default_dispatch_user->supports(now))
0a35513e
AH
260 set_default_dispatch(default_dispatch_user);
261 else
5b9cf5d2
TR
262 {
263 abi_dispatch* a = dispatch_serialirr_onwrite();
264 if (a->supports(now))
265 set_default_dispatch(a);
266 else
267 // Serial-irrevocable mode always works.
268 set_default_dispatch(dispatch_serialirr());
269 }
0a35513e
AH
270 }
271}