1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp
import (
"math"
"time"
"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
// 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
// long timeouts farther into the future.
//
// TCP retransmit timers benefit from this because they the timeouts are long
// (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 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 timerState
clock tcpip.Clock
// target is the expiration time of the current timer. It is only
// meaningful in the enabled state.
target tcpip.MonotonicTime
// clockTarget is the expiration time of the clock timer. It is
// meaningful in the enabled and orphaned states.
clockTarget tcpip.MonotonicTime
// timer is the clock timer used to wait on.
timer tcpip.Timer
}
// init initializes the timer. Once it expires the function callback
// passed will be called.
func (t *timer) init(clock tcpip.Clock, f func()) {
t.state = timerStateDisabled
t.clock = clock
// Initialize a clock timer that will call the callback func, then
// immediately stop it.
t.timer = t.clock.AfterFunc(math.MaxInt64, f)
t.timer.Stop()
}
// cleanup frees all resources associated with the timer.
func (t *timer) cleanup() {
if t.timer == nil {
// No cleanup needed.
return
}
t.timer.Stop()
*t = timer{}
}
// isZero returns true if the timer is in the zero state. This is usually
// only true if init() has never been called or if cleanup has been called.
func (t *timer) isZero() bool {
return *t == timer{}
}
// checkExpiration checks if the given timer has actually expired, it should be
// called whenever the callback function is called, and is used to check if it's
// a supurious timer expiration (due to a previously orphaned timer) or a
// legitimate one.
func (t *timer) checkExpiration() bool {
// Transition to fully disabled state if we're just consuming an
// orphaned timer.
if t.state == timerStateOrphaned {
t.state = timerStateDisabled
return false
}
// 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 := t.clock.NowMonotonic()
if now.Before(t.target) {
t.clockTarget = t.target
t.timer.Reset(t.target.Sub(now))
return false
}
// The timer has actually expired, disable it for now and inform the
// caller.
t.state = timerStateDisabled
return true
}
// disable disables the timer, leaving it in an orphaned state if it wasn't
// already disabled.
func (t *timer) disable() {
if t.state != timerStateDisabled {
t.state = timerStateOrphaned
}
}
// enabled returns true if the timer is currently enabled, false otherwise.
func (t *timer) enabled() bool {
return t.state == timerStateEnabled
}
// enable enables the timer, programming the runtime timer if necessary.
func (t *timer) enable(d time.Duration) {
t.target = t.clock.NowMonotonic().Add(d)
// Check if we need to set the runtime timer.
if t.state == timerStateDisabled || t.target.Before(t.clockTarget) {
t.clockTarget = t.target
t.timer.Reset(d)
}
t.state = timerStateEnabled
}
|