OSDN Git Service

* config/x86/target.h (GTM_longjmp): Correct the .cfi corrections.
[pf3gnuchains/gcc-fork.git] / libitm / retry.cc
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())
61             // Still the same method group.
62             disp->get_method_group()->reinit();
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
72         // We are a serial transaction already, which makes things simple.
73         disp->get_method_group()->reinit();
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     }
202   else if (strncmp(env, "ml_wt", 5) == 0)
203     {
204       disp = GTM::dispatch_ml_wt();
205       env += 5;
206     }
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.
251       if (default_dispatch_user && default_dispatch_user->supports(now))
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.
259       if (default_dispatch_user && default_dispatch_user->supports(now))
260         set_default_dispatch(default_dispatch_user);
261       else
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         }
270     }
271 }