gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"gvisor.dev/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  }