github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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/SagerNet/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  // 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  }