throttle_timer: fix race, use mtx instead of atomic

This commit is contained in:
Ethan Buchman 2016-07-11 22:17:09 -04:00
parent 9dc4dc1960
commit 930880f574
1 changed files with 20 additions and 9 deletions

View File

@ -1,7 +1,7 @@
package common package common
import ( import (
"sync/atomic" "sync"
"time" "time"
) )
@ -12,12 +12,14 @@ If a long continuous burst of .Set() calls happens, ThrottleTimer fires
at most once every "dur". at most once every "dur".
*/ */
type ThrottleTimer struct { type ThrottleTimer struct {
Name string Name string
Ch chan struct{} Ch chan struct{}
quit chan struct{} quit chan struct{}
dur time.Duration dur time.Duration
mtx sync.Mutex
timer *time.Timer timer *time.Timer
isSet uint32 isSet bool
} }
func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer { func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
@ -30,9 +32,11 @@ func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
} }
func (t *ThrottleTimer) fireRoutine() { func (t *ThrottleTimer) fireRoutine() {
t.mtx.Lock()
defer t.mtx.Unlock()
select { select {
case t.Ch <- struct{}{}: case t.Ch <- struct{}{}:
atomic.StoreUint32(&t.isSet, 0) t.isSet = false
case <-t.quit: case <-t.quit:
// do nothing // do nothing
default: default:
@ -41,13 +45,18 @@ func (t *ThrottleTimer) fireRoutine() {
} }
func (t *ThrottleTimer) Set() { func (t *ThrottleTimer) Set() {
if atomic.CompareAndSwapUint32(&t.isSet, 0, 1) { t.mtx.Lock()
defer t.mtx.Unlock()
if !t.isSet {
t.isSet = true
t.timer.Reset(t.dur) t.timer.Reset(t.dur)
} }
} }
func (t *ThrottleTimer) Unset() { func (t *ThrottleTimer) Unset() {
atomic.StoreUint32(&t.isSet, 0) t.mtx.Lock()
defer t.mtx.Unlock()
t.isSet = false
t.timer.Stop() t.timer.Stop()
} }
@ -58,5 +67,7 @@ func (t *ThrottleTimer) Stop() bool {
return false return false
} }
close(t.quit) close(t.quit)
t.mtx.Lock()
defer t.mtx.Unlock()
return t.timer.Stop() return t.timer.Stop()
} }