tlds
Transactional Operations for Linked Data Structures
|
#include <WriteSet.hpp>
Public Member Functions | |
ByteLoggingWriteSetEntry (void **paddr, void *pval, uintptr_t pmask) | |
void | update (const ByteLoggingWriteSetEntry &rhs) |
bool | filter (void **lower, void **upper) |
void | writeback () const |
void | rollback (void **lower, void **upper) |
Public Attributes | |
union { | |
void ** addr | |
uint8_t * byte_addr | |
}; | |
union { | |
void * val | |
uint8_t byte_val [sizeof(void *)] | |
}; | |
union { | |
uintptr_t mask | |
uint8_t byte_mask [sizeof(void *)] | |
}; | |
The log entry for byte logging is complicated by
1) the fact that we store a bitmask 2) that we need to treat the address/value/mask instance variables as both word types, and byte types.
We do this with unions, which makes the use of these easier since it reduces the huge number of casts we perform otherwise.
Union naming is important, since the outside world only directly deals with the word-sized fields.
|
inline |
|
inline |
Check to see if the entry is completely contained within the given address range. We have some preconditions here w.r.t. alignment and size of the range. It has to be at least word aligned and word sized. This is currently only used with stack addresses, so we don't include asserts because we don't want to pay for them in the common case writeback loop.
The byte-logging writeset can actually accommodate awkward intersections here using the mask, but we're not going to worry about that given the expected size/alignment of the range.
|
inline |
Called during the rollback loop in order to write out buffered writes to an exception object (represented by the address range). We don't assume anything about the alignment or size of the exception object.
|
inline |
Called when we are WAW an address, and we want to coalesce the write. Trivial for the word-based writeset, but complicated for the byte-based version.
The new value is the bytes from the incoming log injected into the existing value, we mask out the bytes we want from the incoming word, mask the existing word, and union them.
|
inline |
If we're byte-logging, we'll write out each byte individually when we're not writing a whole word. This turns all subword writes into byte writes, so we lose the original atomicity of (say) half-word writes in the original source. This isn't a correctness problem because of our transactional synchronization, but could be a performance problem if the system depends on sub-word writes for performance.
union { ... } |
union { ... } |
union { ... } |
void** stm::ByteLoggingWriteSetEntry::addr |
uint8_t* stm::ByteLoggingWriteSetEntry::byte_addr |
uint8_t stm::ByteLoggingWriteSetEntry::byte_mask[sizeof(void *)] |
uint8_t stm::ByteLoggingWriteSetEntry::byte_val[sizeof(void *)] |
uintptr_t stm::ByteLoggingWriteSetEntry::mask |
void* stm::ByteLoggingWriteSetEntry::val |