summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/transport/tcp/timer.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/transport/tcp/timer.go')
-rw-r--r--pkg/tcpip/transport/tcp/timer.go51
1 files changed, 26 insertions, 25 deletions
diff --git a/pkg/tcpip/transport/tcp/timer.go b/pkg/tcpip/transport/tcp/timer.go
index 38a335840..5645c772e 100644
--- a/pkg/tcpip/transport/tcp/timer.go
+++ b/pkg/tcpip/transport/tcp/timer.go
@@ -15,21 +15,29 @@
package tcp
import (
+ "math"
"time"
"gvisor.dev/gvisor/pkg/sleep"
+ "gvisor.dev/gvisor/pkg/tcpip"
)
type timerState int
const (
+ // The timer is disabled.
timerStateDisabled timerState = iota
+ // The timer is enabled, but the clock timer may be set to an earlier
+ // expiration time due to a previous orphaned state.
timerStateEnabled
+ // The timer is disabled, but the clock timer is enabled, which means that
+ // it will cause a spurious wakeup unless the timer is enabled before the
+ // clock timer fires.
timerStateOrphaned
)
// timer is a timer implementation that reduces the interactions with the
-// runtime timer infrastructure by letting timers run (and potentially
+// clock timer infrastructure by letting timers run (and potentially
// eventually expire) even if they are stopped. It makes it cheaper to
// disable/reenable timers at the expense of spurious wakes. This is useful for
// cases when the same timer is disabled/reenabled repeatedly with relatively
@@ -39,44 +47,37 @@ const (
// (currently at least 200ms), and get disabled when acks are received, and
// reenabled when new pending segments are sent.
//
-// It is advantageous to avoid interacting with the runtime because it acquires
+// It is advantageous to avoid interacting with the clock because it acquires
// a global mutex and performs O(log n) operations, where n is the global number
// of timers, whenever a timer is enabled or disabled, and may make a syscall.
//
// This struct is thread-compatible.
type timer struct {
- // state is the current state of the timer, it can be one of the
- // following values:
- // disabled - the timer is disabled.
- // orphaned - the timer is disabled, but the runtime timer is
- // enabled, which means that it will evetually cause a
- // spurious wake (unless it gets enabled again before
- // then).
- // enabled - the timer is enabled, but the runtime timer may be set
- // to an earlier expiration time due to a previous
- // orphaned state.
state timerState
+ clock tcpip.Clock
+
// target is the expiration time of the current timer. It is only
// meaningful in the enabled state.
- target time.Time
+ target tcpip.MonotonicTime
- // runtimeTarget is the expiration time of the runtime timer. It is
+ // clockTarget is the expiration time of the clock timer. It is
// meaningful in the enabled and orphaned states.
- runtimeTarget time.Time
+ clockTarget tcpip.MonotonicTime
- // timer is the runtime timer used to wait on.
- timer *time.Timer
+ // timer is the clock timer used to wait on.
+ timer tcpip.Timer
}
// init initializes the timer. Once it expires, it the given waker will be
// asserted.
-func (t *timer) init(w *sleep.Waker) {
+func (t *timer) init(clock tcpip.Clock, w *sleep.Waker) {
t.state = timerStateDisabled
+ t.clock = clock
- // Initialize a runtime timer that will assert the waker, then
+ // Initialize a clock timer that will assert the waker, then
// immediately stop it.
- t.timer = time.AfterFunc(time.Hour, func() {
+ t.timer = t.clock.AfterFunc(math.MaxInt64, func() {
w.Assert()
})
t.timer.Stop()
@@ -106,9 +107,9 @@ func (t *timer) checkExpiration() bool {
// The timer is enabled, but it may have expired early. Check if that's
// the case, and if so, reset the runtime timer to the correct time.
- now := time.Now()
+ now := t.clock.NowMonotonic()
if now.Before(t.target) {
- t.runtimeTarget = t.target
+ t.clockTarget = t.target
t.timer.Reset(t.target.Sub(now))
return false
}
@@ -134,11 +135,11 @@ func (t *timer) enabled() bool {
// enable enables the timer, programming the runtime timer if necessary.
func (t *timer) enable(d time.Duration) {
- t.target = time.Now().Add(d)
+ t.target = t.clock.NowMonotonic().Add(d)
// Check if we need to set the runtime timer.
- if t.state == timerStateDisabled || t.target.Before(t.runtimeTarget) {
- t.runtimeTarget = t.target
+ if t.state == timerStateDisabled || t.target.Before(t.clockTarget) {
+ t.clockTarget = t.target
t.timer.Reset(d)
}