hppa: Install __sync libfuncs for linux.
[official-gcc.git] / libitm / retry.cc
blobdecd7731b46282ede4e79805d34c5d2ef8c53601
1 /* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Transactional Memory Library (libitm).
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.
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.
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.
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/>. */
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include "libitm_i.h"
30 // The default TM method used when starting a new transaction.
31 static GTM::abi_dispatch* default_dispatch = 0;
32 // The default TM method as requested by the user, if any.
33 static GTM::abi_dispatch* default_dispatch_user = 0;
35 void
36 GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r)
38 struct abi_dispatch *disp = abi_disp ();
40 this->restart_reason[r]++;
41 this->restart_total++;
43 if (r == RESTART_INIT_METHOD_GROUP)
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)
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())
62 // Still the same method group.
63 disp->get_method_group()->fini();
64 disp->get_method_group()->init();
66 serial_lock.write_unlock();
67 serial_lock.read_lock(this);
68 if (disp->get_method_group() != default_dispatch->get_method_group())
70 disp = default_dispatch;
71 set_abi_disp(disp);
74 else
76 // We are a serial transaction already, which makes things simple.
77 disp->get_method_group()->fini();
78 disp->get_method_group()->init();
82 bool retry_irr = (r == RESTART_SERIAL_IRR);
83 bool retry_serial = (retry_irr || this->restart_total > 100);
85 // We assume closed nesting to be infrequently required, so just use
86 // dispatch_serial (with undo logging) if required.
87 if (r == RESTART_CLOSED_NESTING)
88 retry_serial = true;
90 if (retry_serial)
92 // In serialirr_mode we can succeed with the upgrade to
93 // write-lock but fail the trycommit. In any case, if the
94 // write lock is not yet held, grab it. Don't do this with
95 // an upgrade, since we've no need to preserve the state we
96 // acquired with the read.
97 // Note that we will be restarting with either dispatch_serial or
98 // dispatch_serialirr, which are compatible with all TM methods; if
99 // we would retry with a different method, we would have to first check
100 // whether the default dispatch or the method group have changed. Also,
101 // the caller must have rolled back the previous transaction, so we
102 // don't have to worry about things such as privatization.
103 if ((this->state & STATE_SERIAL) == 0)
105 this->state |= STATE_SERIAL;
106 serial_lock.read_unlock (this);
107 serial_lock.write_lock ();
110 // We can retry with dispatch_serialirr if the transaction
111 // doesn't contain an abort and if we don't need closed nesting.
112 if ((this->prop & pr_hasNoAbort) && (r != RESTART_CLOSED_NESTING))
113 retry_irr = true;
116 // Note that we can just use serial mode here without having to switch
117 // TM method sets because serial mode is compatible with all of them.
118 if (retry_irr)
120 this->state = (STATE_SERIAL | STATE_IRREVOCABLE);
121 disp = dispatch_serialirr ();
122 set_abi_disp (disp);
124 else if (retry_serial)
126 disp = dispatch_serial();
127 set_abi_disp (disp);
132 // Decides which TM method should be used on the first attempt to run this
133 // transaction.
134 GTM::abi_dispatch*
135 GTM::gtm_thread::decide_begin_dispatch (uint32_t prop)
137 // TODO Pay more attention to prop flags (eg, *omitted) when selecting
138 // dispatch.
139 if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode))
140 return dispatch_serialirr();
142 // If we might need closed nesting and the default dispatch has an
143 // alternative that supports closed nesting, use it.
144 // ??? We could choose another TM method that we know supports closed
145 // nesting but isn't the default (e.g., dispatch_serial()). However, we
146 // assume that aborts that need closed nesting are infrequent, so don't
147 // choose a non-default method until we have to actually restart the
148 // transaction.
149 if (!(prop & pr_hasNoAbort) && !default_dispatch->closed_nesting()
150 && default_dispatch->closed_nesting_alternative())
151 return default_dispatch->closed_nesting_alternative();
153 // No special case, just use the default dispatch.
154 return default_dispatch;
158 void
159 GTM::gtm_thread::set_default_dispatch(GTM::abi_dispatch* disp)
161 if (default_dispatch == disp)
162 return;
163 if (default_dispatch)
165 // If we are switching method groups, initialize and shut down properly.
166 if (default_dispatch->get_method_group() != disp->get_method_group())
168 default_dispatch->get_method_group()->fini();
169 disp->get_method_group()->init();
172 else
173 disp->get_method_group()->init();
174 default_dispatch = disp;
178 static GTM::abi_dispatch*
179 parse_default_method()
181 const char *env = getenv("ITM_DEFAULT_METHOD");
182 GTM::abi_dispatch* disp = 0;
183 if (env == NULL)
184 return 0;
186 while (isspace((unsigned char) *env))
187 ++env;
188 if (strncmp(env, "serialirr_onwrite", 17) == 0)
190 disp = GTM::dispatch_serialirr_onwrite();
191 env += 17;
193 else if (strncmp(env, "serialirr", 9) == 0)
195 disp = GTM::dispatch_serialirr();
196 env += 9;
198 else if (strncmp(env, "serial", 6) == 0)
200 disp = GTM::dispatch_serial();
201 env += 6;
203 else if (strncmp(env, "gl_wt", 5) == 0)
205 disp = GTM::dispatch_gl_wt();
206 env += 5;
208 else
209 goto unknown;
211 while (isspace((unsigned char) *env))
212 ++env;
213 if (*env == '\0')
214 return disp;
216 unknown:
217 GTM::GTM_error("Unknown TM method in environment variable "
218 "ITM_DEFAULT_METHOD\n");
219 return 0;
222 // Gets notifications when the number of registered threads changes. This is
223 // used to initialize the method set choice and trigger straightforward choice
224 // adaption.
225 // This must be called only by serial threads.
226 void
227 GTM::gtm_thread::number_of_threads_changed(unsigned previous, unsigned now)
229 if (previous == 0)
231 // No registered threads before, so initialize.
232 static bool initialized = false;
233 if (!initialized)
235 initialized = true;
236 // Check for user preferences here.
237 default_dispatch_user = parse_default_method();
240 else if (now == 0)
242 // No registered threads anymore. The dispatch based on serial mode do
243 // not have any global state, so this effectively shuts down properly.
244 set_default_dispatch(dispatch_serialirr());
247 if (now == 1)
249 // Only one thread, so use a serializing method.
250 // ??? If we don't have a fast serial mode implementation, it might be
251 // better to use the global lock method set here.
252 if (default_dispatch_user)
253 set_default_dispatch(default_dispatch_user);
254 else
255 set_default_dispatch(dispatch_serialirr());
257 else if (now > 1 && previous <= 1)
259 // More than one thread, use the default method.
260 if (default_dispatch_user)
261 set_default_dispatch(default_dispatch_user);
262 else
263 set_default_dispatch(dispatch_serialirr_onwrite());