]>
Commit | Line | Data |
---|---|---|
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. | |
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; | |
34 | ||
35 | void | |
36 | GTM::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. | |
128 | GTM::abi_dispatch* | |
129 | GTM::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 | ||
152 | void | |
153 | GTM::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 | ||
172 | static GTM::abi_dispatch* | |
173 | parse_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. | |
225 | void | |
226 | GTM::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 | } |