inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/transport/tcp/timer.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tcp 16 17 import ( 18 "math" 19 "time" 20 21 "inet.af/netstack/sleep" 22 "inet.af/netstack/tcpip" 23 ) 24 25 type timerState int 26 27 const ( 28 // The timer is disabled. 29 timerStateDisabled timerState = iota 30 // The timer is enabled, but the clock timer may be set to an earlier 31 // expiration time due to a previous orphaned state. 32 timerStateEnabled 33 // The timer is disabled, but the clock timer is enabled, which means that 34 // it will cause a spurious wakeup unless the timer is enabled before the 35 // clock timer fires. 36 timerStateOrphaned 37 ) 38 39 // timer is a timer implementation that reduces the interactions with the 40 // clock timer infrastructure by letting timers run (and potentially 41 // eventually expire) even if they are stopped. It makes it cheaper to 42 // disable/reenable timers at the expense of spurious wakes. This is useful for 43 // cases when the same timer is disabled/reenabled repeatedly with relatively 44 // long timeouts farther into the future. 45 // 46 // TCP retransmit timers benefit from this because they the timeouts are long 47 // (currently at least 200ms), and get disabled when acks are received, and 48 // reenabled when new pending segments are sent. 49 // 50 // It is advantageous to avoid interacting with the clock because it acquires 51 // a global mutex and performs O(log n) operations, where n is the global number 52 // of timers, whenever a timer is enabled or disabled, and may make a syscall. 53 // 54 // This struct is thread-compatible. 55 type timer struct { 56 state timerState 57 58 clock tcpip.Clock 59 60 // target is the expiration time of the current timer. It is only 61 // meaningful in the enabled state. 62 target tcpip.MonotonicTime 63 64 // clockTarget is the expiration time of the clock timer. It is 65 // meaningful in the enabled and orphaned states. 66 clockTarget tcpip.MonotonicTime 67 68 // timer is the clock timer used to wait on. 69 timer tcpip.Timer 70 } 71 72 // init initializes the timer. Once it expires, it the given waker will be 73 // asserted. 74 func (t *timer) init(clock tcpip.Clock, w *sleep.Waker) { 75 t.state = timerStateDisabled 76 t.clock = clock 77 78 // Initialize a clock timer that will assert the waker, then 79 // immediately stop it. 80 t.timer = t.clock.AfterFunc(math.MaxInt64, func() { 81 w.Assert() 82 }) 83 t.timer.Stop() 84 } 85 86 // cleanup frees all resources associated with the timer. 87 func (t *timer) cleanup() { 88 if t.timer == nil { 89 // No cleanup needed. 90 return 91 } 92 t.timer.Stop() 93 *t = timer{} 94 } 95 96 // checkExpiration checks if the given timer has actually expired, it should be 97 // called whenever a sleeper wakes up due to the waker being asserted, and is 98 // used to check if it's a supurious wake (due to a previously orphaned timer) 99 // or a legitimate one. 100 func (t *timer) checkExpiration() bool { 101 // Transition to fully disabled state if we're just consuming an 102 // orphaned timer. 103 if t.state == timerStateOrphaned { 104 t.state = timerStateDisabled 105 return false 106 } 107 108 // The timer is enabled, but it may have expired early. Check if that's 109 // the case, and if so, reset the runtime timer to the correct time. 110 now := t.clock.NowMonotonic() 111 if now.Before(t.target) { 112 t.clockTarget = t.target 113 t.timer.Reset(t.target.Sub(now)) 114 return false 115 } 116 117 // The timer has actually expired, disable it for now and inform the 118 // caller. 119 t.state = timerStateDisabled 120 return true 121 } 122 123 // disable disables the timer, leaving it in an orphaned state if it wasn't 124 // already disabled. 125 func (t *timer) disable() { 126 if t.state != timerStateDisabled { 127 t.state = timerStateOrphaned 128 } 129 } 130 131 // enabled returns true if the timer is currently enabled, false otherwise. 132 func (t *timer) enabled() bool { 133 return t.state == timerStateEnabled 134 } 135 136 // enable enables the timer, programming the runtime timer if necessary. 137 func (t *timer) enable(d time.Duration) { 138 t.target = t.clock.NowMonotonic().Add(d) 139 140 // Check if we need to set the runtime timer. 141 if t.state == timerStateDisabled || t.target.Before(t.clockTarget) { 142 t.clockTarget = t.target 143 t.timer.Reset(d) 144 } 145 146 t.state = timerStateEnabled 147 }