github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/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 "time" 19 20 "github.com/FlowerWrong/netstack/sleep" 21 ) 22 23 type timerState int 24 25 const ( 26 timerStateDisabled timerState = iota 27 timerStateEnabled 28 timerStateOrphaned 29 ) 30 31 // timer is a timer implementation that reduces the interactions with the 32 // runtime timer infrastructure by letting timers run (and potentially 33 // eventually expire) even if they are stopped. It makes it cheaper to 34 // disable/reenable timers at the expense of spurious wakes. This is useful for 35 // cases when the same timer is disabled/reenabled repeatedly with relatively 36 // long timeouts farther into the future. 37 // 38 // TCP retransmit timers benefit from this because they the timeouts are long 39 // (currently at least 200ms), and get disabled when acks are received, and 40 // reenabled when new pending segments are sent. 41 // 42 // It is advantageous to avoid interacting with the runtime because it acquires 43 // a global mutex and performs O(log n) operations, where n is the global number 44 // of timers, whenever a timer is enabled or disabled, and may make a syscall. 45 // 46 // This struct is thread-compatible. 47 type timer struct { 48 // state is the current state of the timer, it can be one of the 49 // following values: 50 // disabled - the timer is disabled. 51 // orphaned - the timer is disabled, but the runtime timer is 52 // enabled, which means that it will evetually cause a 53 // spurious wake (unless it gets enabled again before 54 // then). 55 // enabled - the timer is enabled, but the runtime timer may be set 56 // to an earlier expiration time due to a previous 57 // orphaned state. 58 state timerState 59 60 // target is the expiration time of the current timer. It is only 61 // meaningful in the enabled state. 62 target time.Time 63 64 // runtimeTarget is the expiration time of the runtime timer. It is 65 // meaningful in the enabled and orphaned states. 66 runtimeTarget time.Time 67 68 // timer is the runtime timer used to wait on. 69 timer *time.Timer 70 } 71 72 // init initializes the timer. Once it expires, it the given waker will be 73 // asserted. 74 func (t *timer) init(w *sleep.Waker) { 75 t.state = timerStateDisabled 76 77 // Initialize a runtime timer that will assert the waker, then 78 // immediately stop it. 79 t.timer = time.AfterFunc(time.Hour, func() { 80 w.Assert() 81 }) 82 t.timer.Stop() 83 } 84 85 // cleanup frees all resources associated with the timer. 86 func (t *timer) cleanup() { 87 t.timer.Stop() 88 } 89 90 // checkExpiration checks if the given timer has actually expired, it should be 91 // called whenever a sleeper wakes up due to the waker being asserted, and is 92 // used to check if it's a supurious wake (due to a previously orphaned timer) 93 // or a legitimate one. 94 func (t *timer) checkExpiration() bool { 95 // Transition to fully disabled state if we're just consuming an 96 // orphaned timer. 97 if t.state == timerStateOrphaned { 98 t.state = timerStateDisabled 99 return false 100 } 101 102 // The timer is enabled, but it may have expired early. Check if that's 103 // the case, and if so, reset the runtime timer to the correct time. 104 now := time.Now() 105 if now.Before(t.target) { 106 t.runtimeTarget = t.target 107 t.timer.Reset(t.target.Sub(now)) 108 return false 109 } 110 111 // The timer has actually expired, disable it for now and inform the 112 // caller. 113 t.state = timerStateDisabled 114 return true 115 } 116 117 // disable disables the timer, leaving it in an orphaned state if it wasn't 118 // already disabled. 119 func (t *timer) disable() { 120 if t.state != timerStateDisabled { 121 t.state = timerStateOrphaned 122 } 123 } 124 125 // enabled returns true if the timer is currently enabled, false otherwise. 126 func (t *timer) enabled() bool { 127 return t.state == timerStateEnabled 128 } 129 130 // enable enables the timer, programming the runtime timer if necessary. 131 func (t *timer) enable(d time.Duration) { 132 t.target = time.Now().Add(d) 133 134 // Check if we need to set the runtime timer. 135 if t.state == timerStateDisabled || t.target.Before(t.runtimeTarget) { 136 t.runtimeTarget = t.target 137 t.timer.Reset(d) 138 } 139 140 t.state = timerStateEnabled 141 }