tlds
Transactional Operations for Linked Data Structures
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
library_inst.hpp
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2011
3  * University of Rochester Department of Computer Science
4  * and
5  * Lehigh University Department of Computer Science and Engineering
6  *
7  * License: Modified BSD
8  * Please see the file LICENSE.RSTM for licensing information
9  */
10 
11 #ifndef API_LIBRARY_INST_HPP__
12 #define API_LIBRARY_INST_HPP__
13 
14 #include <stm/config.h>
15 
16 /**
17  * In the LIBRARY api, the transformation of reads and writes of addresses
18  * into correctly formed calls to the tmread and tmwrite functions is
19  * achieved through a set of templates. The role of the templates is to
20  * allow a single library call to be transformed into the right instructions
21  * to read at any supported size/type, even though the library itself only
22  * provides word-level read/write functions.
23  *
24  * This file presents those templates, to reduce clutter in the main
25  * library.hpp file.
26  *
27  * This file should be included in the middle of the library file. It has no
28  * includes of its own.
29  *
30  * Also, BE WARNED: this implementation of the library API allows "granular
31  * lost updates". If transaction A writes a single char, and thread B writes
32  * an adjacent char, then B's write could be lost.
33  */
34 
35 namespace stm
36 {
37  /**
38  * The DISPATCH class takes an address and a type, and determines which
39  * words (represented as void*s) ought to be read and written to effect a
40  * read or write of the given type, from the given address.
41  *
42  * NB: if the compiler can't find a valid specialization, it will use this
43  * variant, which will cause an error. This is the desired behavior.
44  */
45  template <typename T, size_t S>
46  struct DISPATCH
47  {
48  // use this to ensure compile-time errors
50 
51  // the read method will transform a read to a sizeof(T) byte range
52  // starting at addr into a set of stmread_word calls. For now, the
53  // range must be aligned on a sizeof(T) boundary, and T must be 1, 4,
54  // or 8 bytes.
55  TM_INLINE
56  static T read(T* addr, TxThread* thread)
57  {
59  T invalid = (T)itastp;
60  return invalid;
61  }
62 
63  // same as read, but for writes
64  TM_INLINE
65  static void write(T* addr, T val, TxThread* thread)
66  {
68  T invalid = (T)itaftp;
69  }
70  };
71 
72 #if defined(STM_BITS_32)
73  /*** standard dispatch for 4-byte types, since 8 bytes is the word size */
74  template <typename T>
75  struct DISPATCH<T, 4>
76  {
77  TM_INLINE
78  static T read(T* addr, TxThread* thread)
79  {
80  return (T)(uintptr_t)thread->tmread(thread, (void**)addr
81  STM_MASK(~0x0));
82  }
83 
84  TM_INLINE
85  static void write(T* addr, T val, TxThread* thread)
86  {
87  thread->tmwrite(thread, (void**)addr, (void*)(uintptr_t)val
88  STM_MASK(~0x0));
89  }
90  };
91 
92  /*** specialization for float */
93  template <>
94  struct DISPATCH<float, 4>
95  {
96  TM_INLINE
97  static float read(float* addr, TxThread* thread)
98  {
99  union { float f; void* v; } v;
100  v.v = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
101  return v.f;
102  }
103 
104  TM_INLINE
105  static void write(float* addr, float val, TxThread* thread)
106  {
107  union { float f; void* v; } v;
108  v.f = val;
109  thread->tmwrite(thread, (void**)addr, v.v STM_MASK(~0x0));
110  }
111  };
112 
113  /*** specialization for const float */
114  template <>
115  struct DISPATCH<const float, 4>
116  {
117  TM_INLINE
118  static float read(const float* addr, TxThread* thread)
119  {
120  union { float f; void* v; } v;
121  v.v = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
122  return v.f;
123  }
124 
125  TM_INLINE
126  static void write(const float*, float, TxThread*)
127  {
128  UNRECOVERABLE("You should not be writing a const float!");
129  }
130  };
131 
132  /*** specialization for 8-byte types... need to do two reads/writes */
133  template <typename T>
134  struct DISPATCH<T, 8>
135  {
136  TM_INLINE
137  static T read(T* addr, TxThread* thread)
138  {
139  // get second word's address
140  void** addr2 = (void**)((long)addr + 4);
141  union {
142  long long l;
143  struct { void* v1; void* v2; } v;
144  } v;
145  // read the two words
146  v.v.v1 = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
147  v.v.v2 = thread->tmread(thread, addr2 STM_MASK(~0x0));
148  return (T)v.l;
149  }
150 
151  TM_INLINE
152  static void write(T* addr, T val, TxThread* thread)
153  {
154  // compute the two addresses
155  void** addr1 = (void**)addr;
156  void** addr2 = (void**)((long)addr + 4);
157  // turn the value into two words
158  union {
159  T t;
160  struct { void* v1; void* v2; } v;
161  } v;
162  v.t = val;
163  // write the two words
164  thread->tmwrite(thread, addr1, v.v.v1 STM_MASK(~0x0));
165  thread->tmwrite(thread, addr2, v.v.v2 STM_MASK(~0x0));
166  }
167  };
168 
169  /**
170  * specialization for doubles... just like other 8-byte, but with an extra
171  * cast
172  */
173  template <>
174  struct DISPATCH<double, 8>
175  {
176  TM_INLINE
177  static double read(double* addr, TxThread* thread)
178  {
179  // get second word's address
180  void** addr2 = (void**)((long)addr + 4);
181  union {
182  double t;
183  struct { void* v1; void* v2; } v;
184  } v;
185  // read the two words
186  v.v.v1 = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
187  v.v.v2 = thread->tmread(thread, addr2 STM_MASK(~0x0));
188  return v.t;
189  }
190 
191  TM_INLINE
192  static void write(double* addr, double val, TxThread* thread)
193  {
194  // compute the two addresses
195  void** addr1 = (void**) addr;
196  void** addr2 = (void**) ((long)addr + 4);
197  // turn the value into two words
198  union {
199  double t;
200  struct { void* v1; void* v2; } v;
201  } v;
202  v.t = val;
203  // write the two words
204  thread->tmwrite(thread, addr1, v.v.v1 STM_MASK(~0x0));
205  thread->tmwrite(thread, addr2, v.v.v2 STM_MASK(~0x0));
206  }
207  };
208 
209  /*** specialization for const double */
210  template <>
211  struct DISPATCH<const double, 8>
212  {
213  TM_INLINE
214  static double read(const double* addr, TxThread* thread)
215  {
216  // get the second word's address
217  void** addr2 = (void**)((long)addr + 4);
218  union {
219  double t;
220  struct { void* v1; void* v2; } v;
221  } v;
222  // read the two words
223  v.v.v1 = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
224  v.v.v2 = thread->tmread(thread, addr2 STM_MASK(~0x0));
225  return v.t;
226  }
227 
228  TM_INLINE
229  static void write(const double*, double, TxThread*)
230  {
231  UNRECOVERABLE("You should not be writing a const double!");
232  }
233  };
234 
235  /**
236  * specialization for 1-byte types... must operate on the enclosing word.
237  *
238  * NB: this can lead to granularity bugs if a byte is accessed
239  * nontransactionally while an adjacent byte is accessed
240  * transactionally.
241  */
242  template <typename T>
243  struct DISPATCH<T, 1>
244  {
245  TM_INLINE
246  static T read(T* addr, TxThread* thread)
247  {
248  // we must read the word (as a void*) that contains the byte at
249  // address addr, then treat that as an array of T's from which we
250  // pull out a specific element (based on masking the last two
251  // bits)
252  union { char v[4]; void* v2; } v;
253  void** a = (void**)(((long)addr) & ~3);
254  long offset = ((long)addr) & 3;
255  v.v2 = thread->tmread(thread, a STM_MASK(0xFF << (8 * offset)));
256  return (T)v.v[offset];
257  }
258 
259  TM_INLINE
260  static void write(T* addr, T val, TxThread* thread)
261  {
262  // to protect granularity, we need to read the whole word and
263  // then write a byte of it
264  union { T v[4]; void* v2; } v;
265  void** a = (void**)(((long)addr) & ~3);
266  long offset = ((long)addr) & 3;
267  // read the enclosing word
268  v.v2 = thread->tmread(thread, a STM_MASK(0xFF << (8 * offset)));
269  v.v[offset] = val;
270  thread->tmwrite(thread, a, v.v2 STM_MASK(0xFF << (8 * offset)));
271  }
272  };
273 
274 #elif defined(STM_BITS_64)
275  /*** standard dispatch for 8-byte types, since 8 bytes is the word size */
276  template <typename T>
277  struct DISPATCH<T, 8>
278  {
279  TM_INLINE
280  static T read(T* addr, TxThread* thread)
281  {
282  return (T)(uintptr_t)thread->tmread(thread, (void**)addr
283  STM_MASK(~0x0));
284  }
285 
286  TM_INLINE
287  static void write(T* addr, T val, TxThread* thread)
288  {
289  thread->tmwrite(thread, (void**)addr, (void*)(uintptr_t)val
290  STM_MASK(~0x0));
291  }
292  };
293 
294  /*** specialization for double */
295  template <>
296  struct DISPATCH<double, 8>
297  {
298  TM_INLINE
299  static double read(double* addr, TxThread* thread)
300  {
301  union { double d; void* v; } v;
302  v.v = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
303  return v.d;
304  }
305 
306  TM_INLINE
307  static void write(double* addr, double val, TxThread* thread)
308  {
309  union { double d; void* v; } v;
310  v.d = val;
311  thread->tmwrite(thread, (void**)addr, v.v STM_MASK(~0x0));
312  }
313  };
314 
315  /*** specialization for const double */
316  template <>
317  struct DISPATCH<const double, 8>
318  {
319  TM_INLINE
320  static double read(const double* addr, TxThread* thread)
321  {
322  union { double d; void* v; } v;
323  v.v = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
324  return v.d;
325  }
326 
327  TM_INLINE
328  static void write(const double*, double, TxThread*)
329  {
330  UNRECOVERABLE("You should not be writing a const double!");
331  }
332  };
333 
334  /*** specialization for long-double */
335  template <>
336  struct DISPATCH<long double, 16>
337  {
338  TM_INLINE
339  static double read(double* addr, TxThread* thread)
340  {
341  // get second word's address
342  void** addr2 = (void**)((long)addr + 4);
343  union {
344  double t;
345  struct { void* v1; void* v2; } v;
346  } v;
347  // read the two words
348  v.v.v1 = thread->tmread(thread, (void**)addr STM_MASK(~0x0));
349  v.v.v2 = thread->tmread(thread, addr2 STM_MASK(~0x0));
350  return v.t;
351  }
352 
353  TM_INLINE
354  static void write(double* addr, double val, TxThread* thread)
355  {
356  // compute the two addresses
357  void** addr1 = (void**) addr;
358  void** addr2 = (void**) ((long)addr + 4);
359  // turn the value into two words
360  union {
361  double t;
362  struct { void* v1; void* v2; } v;
363  } v;
364  v.t = val;
365  // write the two words
366  thread->tmwrite(thread, addr1, v.v.v1 STM_MASK(~0x0));
367  thread->tmwrite(thread, addr2, v.v.v2 STM_MASK(~0x0));
368  }
369  };
370 
371  /**
372  * Since 4-byte types are sub-word, and since we do everything at the
373  * granularity of words, we need to do some careful work to make a 4-byte
374  * read/write work correctly.
375  *
376  * NB: We're going to assume that 4-byte reads are always aligned
377  *
378  * NB: This can lead to granularity bugs if a 4-byte value is accessed
379  * transactionally while a neighboring 4-byte value is accessed
380  * nontransactionally
381  */
382 
383  /*** specialization for generic 4-byte types */
384  template <typename T>
385  struct DISPATCH<T, 4>
386  {
387  TM_INLINE
388  static T read(T* addr, TxThread* thread)
389  {
390  // we must read the word (as a void*) that contains the 4byte at
391  // address addr, then treat that as an array of T's from which we
392  // pull out a specific element (based on the 3-lsb)
393  union { int v[2]; void* v2; } v;
394  void** a = (void**)(((intptr_t)addr) & ~7ul);
395  long offset = (((intptr_t)addr)>>2)&1;
396  v.v2 = thread->tmread(thread, a
397  STM_MASK(0xffffffff << (32 * offset)));
398  return (T)v.v[offset];
399  }
400 
401  TM_INLINE
402  static void write(T* addr, T val, TxThread* thread)
403  {
404  // to protect granularity, we need to read the whole word and
405  // then write a byte of it
406  union { T v[2]; void* v2; } v;
407  void** a = (void**)(((intptr_t)addr) & ~7ul);
408  int offset = (((intptr_t)addr)>>2) & 1;
409  // read the enclosing word
410  v.v2 = thread->tmread(thread, a
411  STM_MASK(0xffffffff << (32 * offset)));
412  v.v[offset] = val;
413  thread->tmwrite(thread, a, v.v2
414  STM_MASK(0xffffffff << (32 * offset)));
415  }
416  };
417 
418  /*** specialization for floats */
419  template <>
420  struct DISPATCH<float, 4>
421  {
422  TM_INLINE
423  static float read(float* addr, TxThread* thread)
424  {
425  // read the word as a void*, pull out the right portion of it
426  union { float v[2]; void* v2; } v;
427  void** a = (void**)(((intptr_t)addr)&~7ul);
428  long offset = (((intptr_t)addr)>>2)&1;
429  v.v2 = thread->tmread(thread, a
430  STM_MASK(0xffffffff << (32 * offset)));
431  return v.v[offset];
432  }
433 
434  TM_INLINE
435  static void write(float* addr, float val, TxThread* thread)
436  {
437  // read the whole word, then write a word of it
438  union { float v[2]; void* v2; } v;
439  void**a = (void**)(((intptr_t)addr) & ~7ul);
440  int offset = (((intptr_t)addr)>>2) & 1;
441  // read enclosing word
442  v.v2 = thread->tmread(thread, a
443  STM_MASK(0xffffffff << (32 * offset)));
444  v.v[offset] = val;
445  thread->tmwrite(thread, a, v.v2
446  STM_MASK(0xffffffff << (32 * offset)));
447  }
448  };
449 
450  /*** specialization for const float */
451  template <>
452  struct DISPATCH<const float, 4>
453  {
454  TM_INLINE
455  static float read(const float* addr, TxThread* thread)
456  {
457  // read the word as a void*, pull out the right portion of it
458  union { float v[2]; void* v2; } v;
459  void** a = (void**)(((intptr_t)addr)&~7ul);
460  long offset = (((intptr_t)addr)>>2)&1;
461  v.v2 = thread->tmread(thread, a
462  STM_MASK(0xffffffff << (32 * offset)));
463  return v.v[offset];
464  }
465 
466  TM_INLINE
467  static void write(const float*, float, TxThread*)
468  {
469  UNRECOVERABLE("You should not be writing a const float!");
470  }
471  };
472 
473  template <typename T>
474  struct DISPATCH<T, 1>
475  {
476  TM_INLINE
477  static T read(T* addr, TxThread* thread)
478  {
479  // we must read the word (as a void*) that contains the byte at
480  // address addr, then treat that as an array of T's from which we
481  // pull out a specific element (based on masking the last three
482  // bits)
483  union { char v[8]; void* v2; } v;
484  void** a = (void**)(((long)addr) & ~7);
485  long offset = ((long)addr) & 7;
486  v.v2 = thread->tmread(thread, a
487  STM_MASK(0xffffffff << (8 * offset)));
488  return (T)v.v[offset];
489  }
490 
491  TM_INLINE
492  static void write(T* addr, T val, TxThread* thread)
493  {
494  // to protect granularity, we need to read the whole word and
495  // then write a byte of it
496  union { T v[8]; void* v2; } v;
497  void** a = (void**)(((long)addr) & ~7);
498  long offset = ((long)addr) & 7;
499  // read the enclosing word
500  v.v2 = thread->tmread(thread, a
501  STM_MASK(0xffffffff << (8 * offset)));
502  v.v[offset] = val;
503  thread->tmwrite(thread, a, v.v2
504  STM_MASK(0xffffffff << (8 * offset)));
505  }
506  };
507 
508 #else
509 #error Cannot figure out the right dispatch mechanism
510 #endif
511 
512 } // namespace stm
513 
514 #endif // API_LIBRARY_INST_HPP__
static TM_INLINE void write(T *addr, T val, TxThread *thread)
Definition: library_inst.hpp:65
Definition: stm_fraser.c:61
static TM_INLINE T read(T *addr, TxThread *thread)
Definition: library_inst.hpp:56
Definition: my_thread.hpp:41
Definition: library_inst.hpp:46
#define TM_INLINE
Definition: platform.hpp:77
Definition: txthread.hpp:47
void NORETURN UNRECOVERABLE(const char *)
Definition: txthread.cpp:155
bool set_op int op_size set_t * l
Definition: stmskip.cc:240