tlds
Transactional Operations for Linked Data Structures
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ValueList.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 STM_VALUE_LIST_HPP
12 #define STM_VALUE_LIST_HPP
13 
14 /**
15  * We use the ValueList class to log address/value pairs for our
16  * value-based-validation implementations---NOrec and NOrecPrio currently. We
17  * generally log things at word granularity, and during validation we check to
18  * see if any of the bits in the word has changed since the word was originally
19  * read. If they have, then we have a conflict.
20  *
21  * This word-granularity continues to be correct when we have enabled byte
22  * logging (because we're building for C++ TM compatibility), but it introduces
23  * the possibility of byte-level false conflicts. One of VBV's advantages is
24  * that there are no false conflicts. In order to preserve this behavior, we
25  * offer the user the option to use the byte-mask (which is already enabled for
26  * byte logging) to do byte-granularity validation. The disadvantage to this
27  * technique is that the read log entry size is increased by the size of the
28  * stored mask (we could optimize for 64-bit Linux and pack the mask into an
29  * unused part of the logged address, but we don't yet have this capability).
30  *
31  * This file implements the value log given the current configuration settings
32  * in stm/config.h
33  */
34 #include "stm/config.h"
35 #include "stm/MiniVector.hpp"
36 
37 namespace stm {
38  /**
39  * When we're word logging we simply store address/value pairs in the
40  * ValueList.
41  */
43  void** addr;
44  void* val;
45 
46  public:
47  WordLoggingValueListEntry(void** a, void* v) : addr(a), val(v) {
48  }
49 
50  /**
51  * When word logging, we can just check if the address still has the
52  * value that we read earlier.
53  */
54  bool isValid() const {
55  return *addr == val;
56  }
57  };
58 
59  /**
60  * When we're byte-logging we store a third word, the mask, and use it in the
61  * isValid() operation. The value we store is stored in masked form, which is
62  * an extra operation of overhead for single-threaded execution, but saves us
63  * masking during validation.
64  */
66  void** addr;
67  void* val;
68  uintptr_t mask;
69 
70  public:
71  ByteLoggingValueListEntry(void** a, void* v, uintptr_t m)
72  : addr(a), val(v), mask(m) {
73  }
74 
75  /**
76  * When we're dealing with byte-granularity we need to check values on a
77  * per-byte basis.
78  *
79  * We believe that this implementation is safe because the logged address
80  * is *always* word aligned, thus promoting subword loads to aligned word
81  * loads followed by a masking operation will not cause any undesired HW
82  * behavior (page fault, etc.).
83  *
84  * We're also assuming that the masking operation means that any
85  * potential "low-level" race that we introduce is immaterial---this may
86  * or may not be safe in C++1X. As an example, someone is
87  * nontransactionally writing the first byte of a word and we're
88  * transactionally reading the scond byte. There is no language-level
89  * race, however when we promote the transactional byte read to a word,
90  * we read the same location the nontransactional access is writing, and
91  * there is no intervening synchronization. We're safe from some bad
92  * behavior because of the atomicity of word-level accesses, and we mask
93  * out the first byte, which means the racing read was actually
94  * dead. There are no executions where the source program can observe the
95  * race and thus they conclude that it is race-free.
96  *
97  * I don't know if this argument is valid, but it is certainly valid for
98  * now, since there is no memory model for C/C++.
99  *
100  * If this becomes a problem we can switch to a loop-when-mask != ~0x0
101  * approach.
102  */
103  bool isValid() const {
104  return ((uintptr_t)val & mask) == ((uintptr_t)*addr & mask);
105  }
106  };
107 
108 #if defined(STM_WS_WORDLOG) || defined(STM_USE_WORD_LOGGING_VALUELIST)
109  typedef WordLoggingValueListEntry ValueListEntry;
110 #define STM_VALUE_LIST_ENTRY(addr, val, mask) ValueListEntry(addr, val)
111 #elif defined(STM_WS_BYTELOG)
112  typedef ByteLoggingValueListEntry ValueListEntry;
113 #define STM_VALUE_LIST_ENTRY(addr, val, mask) ValueListEntry(addr, val, mask)
114 #else
115 #error "Preprocessor configuration error: STM_WS_(WORD|BYTE)LOG should be set"
116 #endif
117 
118  struct ValueList : public MiniVector<ValueListEntry> {
119  ValueList(const unsigned long cap) : MiniVector<ValueListEntry>(cap) {
120  }
121  };
122 }
123 
124 #endif // STM_VALUE_LIST_HPP
Definition: stm_fraser.c:61
uintptr_t mask
Definition: ValueList.hpp:68
Definition: ValueList.hpp:65
bool isValid() const
Definition: ValueList.hpp:54
Definition: ValueList.hpp:118
void ** addr
Definition: ValueList.hpp:43
void * val
Definition: ValueList.hpp:67
bool isValid() const
Definition: ValueList.hpp:103
Definition: MiniVector.hpp:30
void ** addr
Definition: ValueList.hpp:66
WordLoggingValueListEntry(void **a, void *v)
Definition: ValueList.hpp:47
ByteLoggingValueListEntry(void **a, void *v, uintptr_t m)
Definition: ValueList.hpp:71
ValueList(const unsigned long cap)
Definition: ValueList.hpp:119
void * val
Definition: ValueList.hpp:44
Definition: ValueList.hpp:42