Don't cause rare spurious event timeout
Correctly resetting timers is surprisingly tricky.
This commit is contained in:
@@ -164,11 +164,20 @@ func (l *Logger) Log(t EventType, data interface{}) {
|
|||||||
func (l *Logger) Subscribe(mask EventType) *Subscription {
|
func (l *Logger) Subscribe(mask EventType) *Subscription {
|
||||||
l.mutex.Lock()
|
l.mutex.Lock()
|
||||||
dl.Debugln("subscribe", mask)
|
dl.Debugln("subscribe", mask)
|
||||||
|
|
||||||
s := &Subscription{
|
s := &Subscription{
|
||||||
mask: mask,
|
mask: mask,
|
||||||
events: make(chan Event, BufferSize),
|
events: make(chan Event, BufferSize),
|
||||||
timeout: time.NewTimer(0),
|
timeout: time.NewTimer(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to create the timeout timer in the stopped, non-fired state so
|
||||||
|
// that Subscription.Poll() can safely reset it and select on the timeout
|
||||||
|
// channel. This ensures the timer is stopped and the channel drained.
|
||||||
|
if !s.timeout.Stop() {
|
||||||
|
<-s.timeout.C
|
||||||
|
}
|
||||||
|
|
||||||
l.subs = append(l.subs, s)
|
l.subs = append(l.subs, s)
|
||||||
l.mutex.Unlock()
|
l.mutex.Unlock()
|
||||||
return s
|
return s
|
||||||
@@ -196,19 +205,18 @@ func (l *Logger) Unsubscribe(s *Subscription) {
|
|||||||
func (s *Subscription) Poll(timeout time.Duration) (Event, error) {
|
func (s *Subscription) Poll(timeout time.Duration) (Event, error) {
|
||||||
dl.Debugln("poll", timeout)
|
dl.Debugln("poll", timeout)
|
||||||
|
|
||||||
if !s.timeout.Reset(timeout) {
|
s.timeout.Reset(timeout)
|
||||||
select {
|
|
||||||
case <-s.timeout.C:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case e, ok := <-s.events:
|
case e, ok := <-s.events:
|
||||||
if !ok {
|
if !ok {
|
||||||
return e, ErrClosed
|
return e, ErrClosed
|
||||||
}
|
}
|
||||||
s.timeout.Stop()
|
if !s.timeout.Stop() {
|
||||||
|
// The timeout must be stopped and possibly drained to be ready
|
||||||
|
// for reuse in the next call.
|
||||||
|
<-s.timeout.C
|
||||||
|
}
|
||||||
return e, nil
|
return e, nil
|
||||||
case <-s.timeout.C:
|
case <-s.timeout.C:
|
||||||
return Event{}, ErrTimeout
|
return Event{}, ErrTimeout
|
||||||
|
|||||||
Reference in New Issue
Block a user