// i == oldt -> i = t -> pass
//
// otherwish block until i == oldt
-func cas(i *atomic.Int32, oldt, t int32) (ok bool, loop func(to ...time.Duration) error) {
- if i.CompareAndSwap(oldt, t) {
- return true, func(to ...time.Duration) error { return nil }
- } else {
- var called atomic.Bool
- return false, func(to ...time.Duration) error {
- if !called.CompareAndSwap(false, true) {
- panic("had called")
- }
- c := time.Now()
- for !i.CompareAndSwap(oldt, t) {
- if len(to) != 0 && time.Since(c) > to[0] {
- return fmt.Errorf("timeout to set %s => %s while is %s", parse(oldt), parse(t), parse(i.Load()))
- }
- runtime.Gosched()
- }
- return nil
+func cas(i *atomic.Int32, oldt, t int32, to ...time.Duration) error {
+ c := time.Now()
+ for !i.CompareAndSwap(oldt, t) {
+ if len(to) != 0 && time.Since(c) > to[0] {
+ return fmt.Errorf("timeout to set %s => %s while is %s", parse(oldt), parse(t), parse(i.Load()))
}
+ runtime.Gosched()
}
+ return nil
}
// i == t -> pass
// i == oldt -> i = t -> pass
//
// otherwish block until i == oldt
-func lcas(i *atomic.Int32, oldt, t int32) (ok bool, loop func(to ...time.Duration) error) {
- if i.Load() == t || i.CompareAndSwap(oldt, t) {
- return true, func(to ...time.Duration) error { return nil }
- } else {
- var called atomic.Bool
- return false, func(to ...time.Duration) error {
- if !called.CompareAndSwap(false, true) {
- panic("had called")
- }
- c := time.Now()
- for !i.CompareAndSwap(oldt, t) {
- if len(to) != 0 && time.Since(c) > to[0] {
- return fmt.Errorf("timeout to set %s => %s while is %s", parse(oldt), parse(t), parse(i.Load()))
- }
- runtime.Gosched()
- }
- return nil
+func lcas(i *atomic.Int32, oldt, t int32, to ...time.Duration) error {
+ c := time.Now()
+ for i.Load() != t && !i.CompareAndSwap(oldt, t) {
+ if len(to) != 0 && time.Since(c) > to[0] {
+ return fmt.Errorf("timeout to set %s => %s while is %s", parse(oldt), parse(t), parse(i.Load()))
}
+ runtime.Gosched()
}
+ return nil
}
// call inTimeCall() in time or panic(callTree)
// 不要在Rlock内设置变量,有DATA RACE风险
func (m *RWMutex) RLock(to ...time.Duration) (unlockf func(beforeUlock ...func())) {
if m.read.Add(1) == 1 {
- _, rlcLoop := cas(&m.rlc, ulock, rlock)
- if e := rlcLoop(to...); e != nil {
+ if e := cas(&m.rlc, ulock, rlock, to...); e != nil {
panic(e)
}
} else {
- _, rlcLoop := lcas(&m.rlc, ulock, rlock)
- if e := rlcLoop(to...); e != nil {
+ if e := lcas(&m.rlc, ulock, rlock, to...); e != nil {
panic(e)
}
}
for i := 0; i < len(beforeUlock); i++ {
beforeUlock[i]()
}
- _, rlcLoop := cas(&m.rlc, rlock, ulock)
- if e := rlcLoop(to...); e != nil {
+ if e := cas(&m.rlc, rlock, ulock, to...); e != nil {
panic(e)
}
}
// to[0]: wait lock timeout to[1]: run lock timeout
func (m *RWMutex) Lock(to ...time.Duration) (unlockf func(beforeUlock ...func())) {
- _, rlcLoop := cas(&m.rlc, ulock, lock)
- if e := rlcLoop(to...); e != nil {
+ if e := cas(&m.rlc, ulock, lock, to...); e != nil {
panic(e)
}
var callC atomic.Bool
for i := 0; i < len(beforeUlock); i++ {
beforeUlock[i]()
}
- _, rlcLoop := cas(&m.rlc, lock, ulock)
- if e := rlcLoop(to...); e != nil {
+ if e := cas(&m.rlc, lock, ulock, to...); e != nil {
panic(e)
}
}
return nil
}
-func (t *Exprier) LoopCheck(key string, whenfail func(error)) (breakLoop func()) {
+func (t *Exprier) LoopCheck(key string, whenfail func(key string, e error)) (breakLoop func()) {
breakLoop = func() {}
if t.Max <= 0 {
return
}
if key == "" {
- whenfail(ErrNoFound)
+ whenfail(key, ErrNoFound)
return
}
ey, ok := t.m.LoadV(key).(time.Time)
if !ok {
- whenfail(ErrNoFound)
+ whenfail(key, ErrNoFound)
return
} else if time.Now().After(ey) {
t.m.Delete(key)
- whenfail(ErrExprie)
+ whenfail(key, ErrExprie)
return
}
for t.Max > 0 {
ey, ok := t.m.LoadV(key).(time.Time)
if !ok {
- whenfail(ErrNoFound)
+ whenfail(key, ErrNoFound)
return
} else if time.Now().After(ey) {
t.m.Delete(key)
- whenfail(ErrExprie)
+ whenfail(key, ErrExprie)
return
}
select {
case <-c:
return
- case <-time.After(time.Until(ey)):
+ case <-time.After(time.Until(ey) + time.Second):
}
}
}()