diff options
author | Matt Joiner <anacrolix@gmail.com> | 2019-10-31 16:35:43 +1100 |
---|---|---|
committer | Matt Joiner <anacrolix@gmail.com> | 2019-10-31 16:35:43 +1100 |
commit | e6b2d4ff0d0d5afaf71ef6df45351909faf7c87b (patch) | |
tree | fa264666735c15bc05782a6b4f53ccf545207365 | |
parent | Panic when trying to set a nil Var (diff) | |
parent | Add Tx.Return and a return value from Atomically (diff) | |
download | stm-e6b2d4ff0d0d5afaf71ef6df45351909faf7c87b.tar.gz stm-e6b2d4ff0d0d5afaf71ef6df45351909faf7c87b.tar.xz |
Merge branch 'master' into var-conds
* master:
Add Tx.Return and a return value from Atomically
Panic when trying to set a nil Var
# Conflicts:
# funcs.go
-rw-r--r-- | funcs.go | 26 | ||||
-rw-r--r-- | stm_test.go | 30 | ||||
-rw-r--r-- | tx.go | 8 |
3 files changed, 42 insertions, 22 deletions
@@ -1,7 +1,7 @@ package stm // Atomically executes the atomic function fn. -func Atomically(fn func(*Tx)) { +func Atomically(fn func(*Tx)) interface{} { retry: // run the transaction tx := &Tx{ @@ -9,9 +9,26 @@ retry: writes: make(map[*Var]interface{}), } tx.cond.L = &globalLock - if catchRetry(fn, tx) { - // wait for one of the variables we read to change before retrying - tx.wait() + var ret interface{} + if func() (retry bool) { + defer func() { + r := recover() + if r == nil { + return + } + if _ret, ok := r.(_return); ok { + ret = _ret.value + } else if r == Retry { + // wait for one of the variables we read to change before retrying + tx.wait() + retry = true + } else { + panic(r) + } + }() + fn(tx) + return false + }() { goto retry } // verify the read log @@ -23,6 +40,7 @@ retry: // commit the write log and broadcast that variables have changed tx.commit() globalLock.Unlock() + return ret } // AtomicGet is a helper function that atomically reads a value. diff --git a/stm_test.go b/stm_test.go index f030a8a..527e480 100644 --- a/stm_test.go +++ b/stm_test.go @@ -223,25 +223,19 @@ func testPingPong(t testing.TB, n int, afterHit func(string)) { hits := NewVar(0) ready := NewVar(true) // The ball is ready for hitting. bat := func(from, to interface{}, noise string) { - done := false - for { - Atomically(func(tx *Tx) { - if tx.Get(doneVar).(bool) { - done = true - return - } - tx.Assert(tx.Get(ready).(bool)) - if tx.Get(ball) == from { - tx.Set(ball, to) - tx.Set(hits, tx.Get(hits).(int)+1) - tx.Set(ready, false) - return - } - tx.Retry() - }) - if done { - break + for !Atomically(func(tx *Tx) { + if tx.Get(doneVar).(bool) { + tx.Return(true) + } + tx.Assert(tx.Get(ready).(bool)) + if tx.Get(ball) == from { + tx.Set(ball, to) + tx.Set(hits, tx.Get(hits).(int)+1) + tx.Set(ready, false) + tx.Return(false) } + tx.Retry() + }).(bool) { afterHit(noise) AtomicSet(ready, true) } @@ -87,3 +87,11 @@ func (tx *Tx) Assert(p bool) { tx.Retry() } } + +func (tx *Tx) Return(v interface{}) { + panic(_return{v}) +} + +type _return struct { + value interface{} +} |