OSDN Git Service

5e85653a2f450295cc582e266690b813975dc495
[pf3gnuchains/gcc-fork.git] / libitm / method-serial.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 "libitm_i.h"
26
27 // Avoid a dependency on libstdc++ for the pure virtuals in abi_dispatch.
28 extern "C" void HIDDEN
29 __cxa_pure_virtual ()
30 {
31   abort ();
32 }
33
34 using namespace GTM;
35
36 namespace {
37
38 // This group consists of the serial, serialirr, and serialirr_onwrite
39 // methods, which all need no global state (except what is already provided
40 // by the serial mode implementation).
41 struct serial_mg : public method_group
42 {
43   virtual void init() { }
44   virtual void fini() { }
45 };
46
47 static serial_mg o_serial_mg;
48
49
50 class serialirr_dispatch : public abi_dispatch
51 {
52  public:
53   serialirr_dispatch() : abi_dispatch(false, true, true, false, &o_serial_mg)
54   { }
55
56  protected:
57   serialirr_dispatch(bool ro, bool wt, bool uninstrumented,
58       bool closed_nesting, method_group* mg) :
59     abi_dispatch(ro, wt, uninstrumented, closed_nesting, mg) { }
60
61   // Transactional loads and stores simply access memory directly.
62   // These methods are static to avoid indirect calls, and will be used by the
63   // virtual ABI dispatch methods or by static direct-access methods created
64   // below.
65   template <typename V> static V load(const V* addr, ls_modifier mod)
66   {
67     return *addr;
68   }
69   template <typename V> static void store(V* addr, const V value,
70       ls_modifier mod)
71   {
72     *addr = value;
73   }
74
75  public:
76   static void memtransfer_static(void *dst, const void* src, size_t size,
77       bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod)
78   {
79     if (!may_overlap)
80       ::memcpy(dst, src, size);
81     else
82       ::memmove(dst, src, size);
83   }
84
85   static void memset_static(void *dst, int c, size_t size, ls_modifier mod)
86   {
87     ::memset(dst, c, size);
88   }
89
90   CREATE_DISPATCH_METHODS(virtual, )
91   CREATE_DISPATCH_METHODS_MEM()
92
93   virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; }
94   virtual bool trycommit(gtm_word& priv_time) { return true; }
95   virtual void rollback(gtm_transaction_cp *cp) { abort(); }
96
97   virtual abi_dispatch* closed_nesting_alternative()
98   {
99     // For nested transactions with an instrumented code path, we can do
100     // undo logging.
101     return GTM::dispatch_serial();
102   }
103 };
104
105 class serial_dispatch : public abi_dispatch
106 {
107 protected:
108   static void log(const void *addr, size_t len)
109   {
110     // TODO Ensure that this gets inlined: Use internal log interface and LTO.
111     GTM_LB(addr, len);
112   }
113
114   template <typename V> static V load(const V* addr, ls_modifier mod)
115   {
116     return *addr;
117   }
118   template <typename V> static void store(V* addr, const V value,
119       ls_modifier mod)
120   {
121     if (mod != WaW)
122       log(addr, sizeof(V));
123     *addr = value;
124   }
125
126 public:
127   static void memtransfer_static(void *dst, const void* src, size_t size,
128       bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod)
129   {
130     if (dst_mod != WaW && dst_mod != NONTXNAL)
131       log(dst, size);
132     if (!may_overlap)
133       ::memcpy(dst, src, size);
134     else
135       ::memmove(dst, src, size);
136   }
137
138   static void memset_static(void *dst, int c, size_t size, ls_modifier mod)
139   {
140     if (mod != WaW)
141       log(dst, size);
142     ::memset(dst, c, size);
143   }
144
145   virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; }
146   virtual bool trycommit(gtm_word& priv_time) { return true; }
147   // Local undo will handle this.
148   // trydropreference() need not be changed either.
149   virtual void rollback(gtm_transaction_cp *cp) { }
150
151   CREATE_DISPATCH_METHODS(virtual, )
152   CREATE_DISPATCH_METHODS_MEM()
153
154   serial_dispatch() : abi_dispatch(false, true, false, true, &o_serial_mg) { }
155 };
156
157
158 // Like serialirr_dispatch but does not requests serial-irrevocable mode until
159 // the first write in the transaction. Can be useful for read-mostly workloads
160 // and testing, but is likely too simple to be of general purpose.
161 class serialirr_onwrite_dispatch : public serialirr_dispatch
162 {
163  public:
164   serialirr_onwrite_dispatch() :
165     serialirr_dispatch(false, true, false, false, &o_serial_mg) { }
166
167  protected:
168   static void pre_write()
169   {
170     gtm_thread *tx = gtm_thr();
171     if (!(tx->state & (gtm_thread::STATE_SERIAL
172         | gtm_thread::STATE_IRREVOCABLE)))
173       tx->serialirr_mode();
174   }
175
176   // Transactional loads access memory directly.
177   // Transactional stores switch to serial mode first.
178   template <typename V> static void store(V* addr, const V value,
179       ls_modifier mod)
180   {
181     pre_write();
182     serialirr_dispatch::store(addr, value, mod);
183   }
184
185  public:
186   static void memtransfer_static(void *dst, const void* src, size_t size,
187       bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod)
188   {
189     pre_write();
190     serialirr_dispatch::memtransfer_static(dst, src, size, may_overlap,
191         dst_mod, src_mod);
192   }
193
194   static void memset_static(void *dst, int c, size_t size, ls_modifier mod)
195   {
196     pre_write();
197     serialirr_dispatch::memset_static(dst, c, size, mod);
198   }
199
200   CREATE_DISPATCH_METHODS(virtual, )
201   CREATE_DISPATCH_METHODS_MEM()
202
203   virtual void rollback(gtm_transaction_cp *cp)
204   {
205     gtm_thread *tx = gtm_thr();
206     if (tx->state & gtm_thread::STATE_IRREVOCABLE)
207       abort();
208   }
209 };
210
211 } // anon namespace
212
213 static const serialirr_dispatch o_serialirr_dispatch;
214 static const serial_dispatch o_serial_dispatch;
215 static const serialirr_onwrite_dispatch o_serialirr_onwrite_dispatch;
216
217 abi_dispatch *
218 GTM::dispatch_serialirr ()
219 {
220   return const_cast<serialirr_dispatch *>(&o_serialirr_dispatch);
221 }
222
223 abi_dispatch *
224 GTM::dispatch_serial ()
225 {
226   return const_cast<serial_dispatch *>(&o_serial_dispatch);
227 }
228
229 abi_dispatch *
230 GTM::dispatch_serialirr_onwrite ()
231 {
232   return
233       const_cast<serialirr_onwrite_dispatch *>(&o_serialirr_onwrite_dispatch);
234 }
235
236 // Put the transaction into serial-irrevocable mode.
237
238 void
239 GTM::gtm_thread::serialirr_mode ()
240 {
241   struct abi_dispatch *disp = abi_disp ();
242   bool need_restart = true;
243
244   if (this->state & STATE_SERIAL)
245     {
246       if (this->state & STATE_IRREVOCABLE)
247         return;
248
249       // Try to commit the dispatch-specific part of the transaction, as we
250       // would do for an outermost commit.
251       // We're already serial, so we don't need to ensure privatization safety
252       // for other transactions here.
253       gtm_word priv_time = 0;
254       bool ok = disp->trycommit (priv_time);
255       // Given that we're already serial, the trycommit better work.
256       assert (ok);
257       need_restart = false;
258     }
259   else if (serial_lock.write_upgrade (this))
260     {
261       this->state |= STATE_SERIAL;
262       // Try to commit the dispatch-specific part of the transaction, as we
263       // would do for an outermost commit.
264       // We have successfully upgraded to serial mode, so we don't need to
265       // ensure privatization safety for other transactions here.
266       gtm_word priv_time = 0;
267       if (disp->trycommit (priv_time))
268         need_restart = false;
269     }
270
271   if (need_restart)
272     restart (RESTART_SERIAL_IRR);
273   else
274     {
275       this->state |= (STATE_SERIAL | STATE_IRREVOCABLE);
276       set_abi_disp (dispatch_serialirr ());
277     }
278 }
279
280 void ITM_REGPARM
281 _ITM_changeTransactionMode (_ITM_transactionState state)
282 {
283   assert (state == modeSerialIrrevocable);
284   gtm_thr()->serialirr_mode ();
285 }