inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/faketime/faketime.go (about) 1 // Copyright 2020 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 faketime provides a fake clock that implements tcpip.Clock interface. 16 package faketime 17 18 import ( 19 "container/heap" 20 "fmt" 21 "sync" 22 "time" 23 24 "inet.af/netstack/tcpip" 25 ) 26 27 // NullClock implements a clock that never advances. 28 type NullClock struct{} 29 30 var _ tcpip.Clock = (*NullClock)(nil) 31 32 // Now implements tcpip.Clock.Now. 33 func (*NullClock) Now() time.Time { 34 return time.Time{} 35 } 36 37 // NowMonotonic implements tcpip.Clock.NowMonotonic. 38 func (*NullClock) NowMonotonic() tcpip.MonotonicTime { 39 return tcpip.MonotonicTime{} 40 } 41 42 // AfterFunc implements tcpip.Clock.AfterFunc. 43 func (*NullClock) AfterFunc(time.Duration, func()) tcpip.Timer { 44 return nil 45 } 46 47 type notificationChannels struct { 48 mu struct { 49 sync.Mutex 50 51 ch []<-chan struct{} 52 } 53 } 54 55 func (n *notificationChannels) add(ch <-chan struct{}) { 56 n.mu.Lock() 57 defer n.mu.Unlock() 58 n.mu.ch = append(n.mu.ch, ch) 59 } 60 61 // wait returns once all the notification channels are readable. 62 // 63 // Channels that are added while waiting on existing channels will be waited on 64 // as well. 65 func (n *notificationChannels) wait() { 66 for { 67 n.mu.Lock() 68 ch := n.mu.ch 69 n.mu.ch = nil 70 n.mu.Unlock() 71 72 if len(ch) == 0 { 73 break 74 } 75 76 for _, c := range ch { 77 <-c 78 } 79 } 80 } 81 82 // ManualClock implements tcpip.Clock and only advances manually with Advance 83 // method. 84 type ManualClock struct { 85 // runningTimers tracks the completion of timer callbacks that began running 86 // immediately upon their scheduling. It is used to ensure the proper ordering 87 // of timer callback dispatch. 88 runningTimers notificationChannels 89 90 mu struct { 91 sync.RWMutex 92 93 // now is the current (fake) time of the clock. 94 now time.Time 95 96 // times is min-heap of times. 97 times timeHeap 98 99 // timers holds the timers scheduled for each time. 100 timers map[time.Time]map[*manualTimer]struct{} 101 } 102 } 103 104 // NewManualClock creates a new ManualClock instance. 105 func NewManualClock() *ManualClock { 106 c := &ManualClock{} 107 108 c.mu.Lock() 109 defer c.mu.Unlock() 110 111 // Set the initial time to a non-zero value since the zero value is used to 112 // detect inactive timers. 113 c.mu.now = time.Unix(0, 0) 114 c.mu.timers = make(map[time.Time]map[*manualTimer]struct{}) 115 116 return c 117 } 118 119 var _ tcpip.Clock = (*ManualClock)(nil) 120 121 // Now implements tcpip.Clock.Now. 122 func (mc *ManualClock) Now() time.Time { 123 mc.mu.RLock() 124 defer mc.mu.RUnlock() 125 return mc.mu.now 126 } 127 128 // NowMonotonic implements tcpip.Clock.NowMonotonic. 129 func (mc *ManualClock) NowMonotonic() tcpip.MonotonicTime { 130 var mt tcpip.MonotonicTime 131 return mt.Add(mc.Now().Sub(time.Unix(0, 0))) 132 } 133 134 // AfterFunc implements tcpip.Clock.AfterFunc. 135 func (mc *ManualClock) AfterFunc(d time.Duration, f func()) tcpip.Timer { 136 mt := &manualTimer{ 137 clock: mc, 138 f: f, 139 } 140 141 mc.mu.Lock() 142 defer mc.mu.Unlock() 143 144 mt.mu.Lock() 145 defer mt.mu.Unlock() 146 147 mc.resetTimerLocked(mt, d) 148 return mt 149 } 150 151 // resetTimerLocked schedules a timer to be fired after the given duration. 152 // 153 // Precondition: mc.mu and mt.mu must be locked. 154 func (mc *ManualClock) resetTimerLocked(mt *manualTimer, d time.Duration) { 155 if !mt.mu.firesAt.IsZero() { 156 panic("tried to reset an active timer") 157 } 158 159 t := mc.mu.now.Add(d) 160 161 if !mc.mu.now.Before(t) { 162 // If the timer is scheduled to fire immediately, call its callback 163 // in a new goroutine immediately. 164 // 165 // It needs to be called in its own goroutine to escape its current 166 // execution context - like an actual timer. 167 ch := make(chan struct{}) 168 mc.runningTimers.add(ch) 169 170 go func() { 171 defer close(ch) 172 173 mt.f() 174 }() 175 176 return 177 } 178 179 mt.mu.firesAt = t 180 181 timers, ok := mc.mu.timers[t] 182 if !ok { 183 timers = make(map[*manualTimer]struct{}) 184 mc.mu.timers[t] = timers 185 heap.Push(&mc.mu.times, t) 186 } 187 188 timers[mt] = struct{}{} 189 } 190 191 // stopTimerLocked stops a timer from firing. 192 // 193 // Precondition: mc.mu and mt.mu must be locked. 194 func (mc *ManualClock) stopTimerLocked(mt *manualTimer) { 195 t := mt.mu.firesAt 196 mt.mu.firesAt = time.Time{} 197 198 if t.IsZero() { 199 panic("tried to stop an inactive timer") 200 } 201 202 timers, ok := mc.mu.timers[t] 203 if !ok { 204 err := fmt.Sprintf("tried to stop an active timer but the clock does not have anything scheduled for the timer @ t = %s %p\nScheduled timers @:", t.UTC(), mt) 205 for t := range mc.mu.timers { 206 err += fmt.Sprintf("%s\n", t.UTC()) 207 } 208 panic(err) 209 } 210 211 if _, ok := timers[mt]; !ok { 212 panic(fmt.Sprintf("did not have an entry in timers for an active timer @ t = %s", t.UTC())) 213 } 214 215 delete(timers, mt) 216 217 if len(timers) == 0 { 218 delete(mc.mu.timers, t) 219 } 220 } 221 222 // RunImmediatelyScheduledJobs runs all jobs scheduled to run at the current 223 // time. 224 func (mc *ManualClock) RunImmediatelyScheduledJobs() { 225 mc.Advance(0) 226 } 227 228 // Advance executes all work that have been scheduled to execute within d from 229 // the current time. Blocks until all work has completed execution. 230 func (mc *ManualClock) Advance(d time.Duration) { 231 // We spawn goroutines for timers that were scheduled to fire at the time of 232 // being reset. Wait for those goroutines to complete before proceeding so 233 // that timer callbacks are called in the right order. 234 mc.runningTimers.wait() 235 236 mc.mu.Lock() 237 defer mc.mu.Unlock() 238 239 until := mc.mu.now.Add(d) 240 for mc.mu.times.Len() > 0 { 241 t := heap.Pop(&mc.mu.times).(time.Time) 242 if t.After(until) { 243 // No work to do 244 heap.Push(&mc.mu.times, t) 245 break 246 } 247 248 timers := mc.mu.timers[t] 249 delete(mc.mu.timers, t) 250 251 mc.mu.now = t 252 253 // Mark the timers as inactive since they will be fired. 254 // 255 // This needs to be done while holding mc's lock because we remove the entry 256 // in the map of timers for the current time. If an attempt to stop a 257 // timer is made after mc's lock was dropped but before the timer is 258 // marked inactive, we would panic since no entry exists for the time when 259 // the timer was expected to fire. 260 for mt := range timers { 261 mt.mu.Lock() 262 mt.mu.firesAt = time.Time{} 263 mt.mu.Unlock() 264 } 265 266 // Release the lock before calling the timer's callback fn since the 267 // callback fn might try to schedule a timer which requires obtaining 268 // mc's lock. 269 mc.mu.Unlock() 270 271 for mt := range timers { 272 mt.f() 273 } 274 275 // The timer callbacks may have scheduled a timer to fire immediately. 276 // We spawn goroutines for these timers and need to wait for them to 277 // finish before proceeding so that timer callbacks are called in the 278 // right order. 279 mc.runningTimers.wait() 280 mc.mu.Lock() 281 } 282 283 mc.mu.now = until 284 } 285 286 func (mc *ManualClock) resetTimer(mt *manualTimer, d time.Duration) { 287 mc.mu.Lock() 288 defer mc.mu.Unlock() 289 290 mt.mu.Lock() 291 defer mt.mu.Unlock() 292 293 if !mt.mu.firesAt.IsZero() { 294 mc.stopTimerLocked(mt) 295 } 296 297 mc.resetTimerLocked(mt, d) 298 } 299 300 func (mc *ManualClock) stopTimer(mt *manualTimer) bool { 301 mc.mu.Lock() 302 defer mc.mu.Unlock() 303 304 mt.mu.Lock() 305 defer mt.mu.Unlock() 306 307 if mt.mu.firesAt.IsZero() { 308 return false 309 } 310 311 mc.stopTimerLocked(mt) 312 return true 313 } 314 315 type manualTimer struct { 316 clock *ManualClock 317 f func() 318 319 mu struct { 320 sync.Mutex 321 322 // firesAt is the time when the timer will fire. 323 // 324 // Zero only when the timer is not active. 325 firesAt time.Time 326 } 327 } 328 329 var _ tcpip.Timer = (*manualTimer)(nil) 330 331 // Reset implements tcpip.Timer.Reset. 332 func (mt *manualTimer) Reset(d time.Duration) { 333 mt.clock.resetTimer(mt, d) 334 } 335 336 // Stop implements tcpip.Timer.Stop. 337 func (mt *manualTimer) Stop() bool { 338 return mt.clock.stopTimer(mt) 339 } 340 341 type timeHeap []time.Time 342 343 var _ heap.Interface = (*timeHeap)(nil) 344 345 func (h timeHeap) Len() int { 346 return len(h) 347 } 348 349 func (h timeHeap) Less(i, j int) bool { 350 return h[i].Before(h[j]) 351 } 352 353 func (h timeHeap) Swap(i, j int) { 354 h[i], h[j] = h[j], h[i] 355 } 356 357 func (h *timeHeap) Push(x interface{}) { 358 *h = append(*h, x.(time.Time)) 359 } 360 361 func (h *timeHeap) Pop() interface{} { 362 last := (*h)[len(*h)-1] 363 *h = (*h)[:len(*h)-1] 364 return last 365 }