81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
|
// Copied from the go standard library.
|
||
|
//
|
||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE-BSD file.
|
||
|
|
||
|
package multiplex
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// pipeDeadline is an abstraction for handling timeouts.
|
||
|
type pipeDeadline struct {
|
||
|
mu sync.Mutex // Guards timer and cancel
|
||
|
timer *time.Timer
|
||
|
cancel chan struct{} // Must be non-nil
|
||
|
}
|
||
|
|
||
|
func makePipeDeadline() pipeDeadline {
|
||
|
return pipeDeadline{cancel: make(chan struct{})}
|
||
|
}
|
||
|
|
||
|
// set sets the point in time when the deadline will time out.
|
||
|
// A timeout event is signaled by closing the channel returned by waiter.
|
||
|
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
||
|
// t value in the future.
|
||
|
//
|
||
|
// A zero value for t prevents timeout.
|
||
|
func (d *pipeDeadline) set(t time.Time) {
|
||
|
d.mu.Lock()
|
||
|
defer d.mu.Unlock()
|
||
|
|
||
|
if d.timer != nil && !d.timer.Stop() {
|
||
|
<-d.cancel // Wait for the timer callback to finish and close cancel
|
||
|
}
|
||
|
d.timer = nil
|
||
|
|
||
|
// Time is zero, then there is no deadline.
|
||
|
closed := isClosedChan(d.cancel)
|
||
|
if t.IsZero() {
|
||
|
if closed {
|
||
|
d.cancel = make(chan struct{})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Time in the future, setup a timer to cancel in the future.
|
||
|
if dur := time.Until(t); dur > 0 {
|
||
|
if closed {
|
||
|
d.cancel = make(chan struct{})
|
||
|
}
|
||
|
d.timer = time.AfterFunc(dur, func() {
|
||
|
close(d.cancel)
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Time in the past, so close immediately.
|
||
|
if !closed {
|
||
|
close(d.cancel)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// wait returns a channel that is closed when the deadline is exceeded.
|
||
|
func (d *pipeDeadline) wait() chan struct{} {
|
||
|
d.mu.Lock()
|
||
|
defer d.mu.Unlock()
|
||
|
return d.cancel
|
||
|
}
|
||
|
|
||
|
func isClosedChan(c <-chan struct{}) bool {
|
||
|
select {
|
||
|
case <-c:
|
||
|
return true
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|