aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Joiner <anacrolix@gmail.com>2019-10-31 16:35:43 +1100
committerMatt Joiner <anacrolix@gmail.com>2019-10-31 16:35:43 +1100
commite6b2d4ff0d0d5afaf71ef6df45351909faf7c87b (patch)
treefa264666735c15bc05782a6b4f53ccf545207365
parentPanic when trying to set a nil Var (diff)
parentAdd Tx.Return and a return value from Atomically (diff)
downloadstm-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.go26
-rw-r--r--stm_test.go30
-rw-r--r--tx.go8
3 files changed, 42 insertions, 22 deletions
diff --git a/funcs.go b/funcs.go
index 7b5df38..4967e83 100644
--- a/funcs.go
+++ b/funcs.go
@@ -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)
}
diff --git a/tx.go b/tx.go
index d4f343a..5dd41ae 100644
--- a/tx.go
+++ b/tx.go
@@ -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{}
+}