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