diff options
author | Matt Joiner <anacrolix@gmail.com> | 2019-11-04 15:14:33 +1100 |
---|---|---|
committer | Matt Joiner <anacrolix@gmail.com> | 2019-11-04 15:14:33 +1100 |
commit | 80ec29f423aeb8f7de75c057b12b2e5cd8cb35ba (patch) | |
tree | 65b7923b152f9695a0a87dbc26a58bef1d10e29c | |
parent | Transfer project stewardship to anacrolix (diff) | |
download | stm-80ec29f423aeb8f7de75c057b12b2e5cd8cb35ba.tar.gz stm-80ec29f423aeb8f7de75c057b12b2e5cd8cb35ba.tar.xz |
Use atomic pointers for Var data
-rw-r--r-- | funcs.go | 8 | ||||
-rw-r--r-- | tx.go | 16 | ||||
-rw-r--r-- | var.go | 30 |
3 files changed, 31 insertions, 23 deletions
@@ -58,13 +58,7 @@ retry: // AtomicGet is a helper function that atomically reads a value. func AtomicGet(v *Var) interface{} { - // since we're only doing one operation, we don't need a full transaction - globalLock.Lock() - v.mu.Lock() - val := v.val - v.mu.Unlock() - globalLock.Unlock() - return val + return v.loadState().val } // AtomicSet is a helper function that atomically writes a value. @@ -14,9 +14,7 @@ type Tx struct { // Check that none of the logged values have changed since the transaction began. func (tx *Tx) verify() bool { for v, version := range tx.reads { - v.mu.Lock() - changed := v.version != version - v.mu.Unlock() + changed := v.loadState().version != version if changed { return false } @@ -27,10 +25,7 @@ func (tx *Tx) verify() bool { // Writes the values in the transaction log to their respective Vars. func (tx *Tx) commit() { for v, val := range tx.writes { - v.mu.Lock() - v.val = val - v.version++ - v.mu.Unlock() + v.changeValue(val) for tx := range v.watchers { tx.cond.Broadcast() delete(v.watchers, tx) @@ -59,13 +54,12 @@ func (tx *Tx) Get(v *Var) interface{} { if val, ok := tx.writes[v]; ok { return val } - v.mu.Lock() - defer v.mu.Unlock() + state := v.loadState() // If we haven't previously read v, record its version if _, ok := tx.reads[v]; !ok { - tx.reads[v] = v.version + tx.reads[v] = state.version } - return v.val + return state.val } // Set sets the value of a Var for the lifetime of the transaction. @@ -1,20 +1,40 @@ package stm -import "sync" +import ( + "sync/atomic" + "unsafe" +) // Holds an STM variable. type Var struct { - mu sync.Mutex + state *varSnapshot + watchers map[*Tx]struct{} +} + +func (v *Var) addr() *unsafe.Pointer { + return (*unsafe.Pointer)(unsafe.Pointer(&v.state)) +} + +func (v *Var) loadState() *varSnapshot { + return (*varSnapshot)(atomic.LoadPointer(v.addr())) +} + +func (v *Var) changeValue(new interface{}) { + version := v.loadState().version + atomic.StorePointer(v.addr(), unsafe.Pointer(&varSnapshot{version: version + 1, val: new})) +} + +type varSnapshot struct { val interface{} version uint64 - - watchers map[*Tx]struct{} } // Returns a new STM variable. func NewVar(val interface{}) *Var { return &Var{ - val: val, + state: &varSnapshot{ + val: val, + }, watchers: make(map[*Tx]struct{}), } } |