tlds
Transactional Operations for Linked Data Structures
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
UndoLog.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 /**
12  * Implement an undo log so that we can centralize all logic for
13  * stack-filtering and abort/throw behavior in in-place update STMs
14  */
15 
16 #ifndef UNDO_LOG_HPP__
17 #define UNDO_LOG_HPP__
18 
19 #include <stm/config.h>
20 #include "stm/MiniVector.hpp"
21 #include "stm/macros.hpp"
22 
23 /**
24  * An undo log is a pretty simple structure. We never need to search it, so
25  * its only purpose is to store stuff and write stuff out when we
26  * abort. It's split out into its own class in order to deal with the
27  * configuration-based behavior that we need it to observe, like
28  * byte-accesses, stack protection, etc.
29  */
30 namespace stm
31 {
32  /**
33  * The undo log entry is the type stored in the undo log. If we're
34  * byte-logging then it has a mask, otherwise it's just an address-value
35  * pair.
36  */
37 
38  /*** Word-logging variant of undo log entries */
40  {
41  void** addr;
42  void* val;
43 
45  : addr(addr), val(val)
46  { }
47 
48  /*** for word logging, we undo an entry by simply writing it back */
49  inline void undo() const { *addr = val; }
50 
51  /**
52  * Called in order to find out if the logged word falls within the
53  * address range. This is used to both filter out undo operations to
54  * the protected stack, and the exception object.
55  *
56  * Note that while the wordlog can _only_ be completely filtered out,
57  * we don't have support for partial filtering here. This is almost
58  * certainly ok, since the stack is word aligned, and an exception
59  * object is probably aligned as well, and at least a word large.
60  *
61  * The bytelog version /can/ be partially filtered, which is just a
62  * masking operation.
63  */
64  inline bool filter(void** lower, void** upper)
65  {
66  return (addr >= lower && addr + 1 < upper);
67  }
68  };
69 
70  /*** Byte-logging variant of undo log entries */
72  {
73  // We use unions here to make our life easier, since we may access
74  // these as byte, bytes, or word
75  union {
76  void** addr;
77  uint8_t* byte_addr;
78  };
79 
80  union {
81  void* val;
82  uint8_t byte_val[sizeof(void*)];
83  };
84 
85  union {
86  uintptr_t mask;
87  uint8_t byte_mask[sizeof(uintptr_t)];
88  };
89 
90  /*** construction is simple, except for the unions */
91  ByteLoggingUndoLogEntry(void** paddr, void* pval, uintptr_t pmask)
92  : addr(), val(), mask()
93  {
94  addr = paddr;
95  val = pval;
96  mask = pmask;
97  }
98 
99  /*** write (undo) a log entry */
100  inline static void DoMaskedWrite(void** addr, void* val, uintptr_t mask)
101  {
102  // common case is word access
103  if (mask == ~(uintptr_t)0x0) {
104  *addr = val;
105  return;
106  }
107 
108  // simple check for null mask, which might result from a filter call
109  if (mask == 0x0)
110  return;
111 
112  union {
113  void** word;
114  uint8_t* bytes;
115  } uaddr = { addr };
116 
117  union {
118  void* word;
119  uint8_t bytes[sizeof(void*)];
120  } uval = { val };
121 
122  union {
123  uintptr_t word;
124  uint8_t bytes[sizeof(uintptr_t)];
125  } umask = { mask };
126 
127  // We're just going to write out individual bytes, which turns all
128  // subword accesses into byte accesses. This might be inefficient but
129  // should be correct, since the locations that we're writing to are
130  // supposed to be locked, and if there's a data race we can have any
131  // sort of behavior.
132  for (unsigned i = 0; i < sizeof(void*); ++i)
133  if (umask.bytes[i] == 0xFF)
134  uaddr.bytes[i] = uval.bytes[i];
135  }
136 
137  inline void undo() const { DoMaskedWrite(addr, val, mask); }
138 
139  /**
140  * The bytelog implementation of the filter operation support any sort
141  * of intersection possible.
142  */
143  inline bool filter(void** lower, void** upper)
144  {
145  // fastpath when there's no intersection
146  return (addr + 1 < lower || addr >= upper)
147  ? false
148  : filterSlow(lower, upper);
149  }
150 
151  private:
152 
153  /**
154  * We outline the slowpath filter. If this /ever/ happens it will be
155  * such a corner case that it just doesn't matter. Plus this is an
156  * abort path anyway.
157  */
158  bool filterSlow(void**, void**);
159  };
160 
161  /**
162  * Macros for hiding the WS_(WORD/BYTE)MASK API differences.
163  */
164 #if defined(STM_WS_WORDLOG)
165  typedef WordLoggingUndoLogEntry UndoLogEntry;
166 #define STM_UNDO_LOG_ENTRY(addr, val, mask) addr, val
167 #define STM_DO_MASKED_WRITE(addr, val, mask) *addr = val
168 #elif defined(STM_WS_BYTELOG)
169  typedef ByteLoggingUndoLogEntry UndoLogEntry;
170 #define STM_UNDO_LOG_ENTRY(addr, val, mask) addr, val, mask
171 #define STM_DO_MASKED_WRITE(addr, val, mask) \
172  stm::ByteLoggingUndoLogEntry::DoMaskedWrite(addr, val, mask)
173 #else
174 # error Configuration logic error.
175 #endif
176 
177  class UndoLog : public stm::MiniVector<UndoLogEntry>
178  {
179  public:
180  UndoLog(const uintptr_t cap) : stm::MiniVector<UndoLogEntry>(cap) { }
181 
182  /**
183  * A utility for undo-log implementations that undoes all of the
184  * accesses in a write log except for those that took place to an
185  * exception object that is being thrown-on-abort. This is mainly to
186  * support the itm2stm shim at the moment, since baseline stm doesn't
187  * have abort-on-throw capabilities.
188  */
189 #if !defined(STM_PROTECT_STACK) && !defined(STM_ABORT_ON_THROW)
190  void undo();
191 # define STM_UNDO(log, stack, except, len) log.undo()
192 #elif defined(STM_PROTECT_STACK) && !defined(STM_ABORT_ON_THROW)
193  void undo(void** upper_stack_bound);
194 # define STM_UNDO(log, stack, except, len) log.undo(stack)
195 #elif !defined(STM_PROTECT_STACK) && defined(STM_ABORT_ON_THROW)
196  void undo(void** except, size_t len);
197 # define STM_UNDO(log, stack, except, len) log.undo(except, len)
198 #elif defined(STM_PROTECT_STACK) && defined(STM_ABORT_ON_THROW)
199  void undo(void** upper_stack_bound, void** exception, size_t len);
200 # define STM_UNDO(log, stack, except, len) log.undo(stack, except, len)
201 #else
202 # error if/else logic error
203 #endif
204  };
205 }
206 #endif // UNDO_LOG_HPP__
Definition: stm_fraser.c:61
void ** addr
Definition: UndoLog.hpp:76
bool filter(void **lower, void **upper)
Definition: UndoLog.hpp:64
Definition: UndoLog.hpp:39
void ** addr
Definition: UndoLog.hpp:41
uint8_t byte_val[sizeof(void *)]
Definition: UndoLog.hpp:82
void undo() const
Definition: UndoLog.hpp:49
static void DoMaskedWrite(void **addr, void *val, uintptr_t mask)
Definition: UndoLog.hpp:100
Definition: UndoLog.hpp:177
uintptr_t mask
Definition: UndoLog.hpp:86
UndoLog(const uintptr_t cap)
Definition: UndoLog.hpp:180
Definition: MiniVector.hpp:30
void undo() const
Definition: UndoLog.hpp:137
bool filterSlow(void **, void **)
Definition: types.cpp:259
void * val
Definition: UndoLog.hpp:42
bool filter(void **lower, void **upper)
Definition: UndoLog.hpp:143
void undo()
Definition: types.cpp:184
WordLoggingUndoLogEntry(void **addr, void *val)
Definition: UndoLog.hpp:44
ByteLoggingUndoLogEntry(void **paddr, void *pval, uintptr_t pmask)
Definition: UndoLog.hpp:91
uint8_t byte_mask[sizeof(uintptr_t)]
Definition: UndoLog.hpp:87
Definition: UndoLog.hpp:71
void * val
Definition: UndoLog.hpp:81
uint8_t * byte_addr
Definition: UndoLog.hpp:77