inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/stdclock.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 tcpip
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"inet.af/netstack/sync"
    22  )
    23  
    24  // stdClock implements Clock with the time package.
    25  //
    26  // +stateify savable
    27  type stdClock struct {
    28  	// baseTime holds the time when the clock was constructed.
    29  	//
    30  	// This value is used to calculate the monotonic time from the time package.
    31  	// As per https://golang.org/pkg/time/#hdr-Monotonic_Clocks,
    32  	//
    33  	//   Operating systems provide both a “wall clock,” which is subject to
    34  	//   changes for clock synchronization, and a “monotonic clock,” which is not.
    35  	//   The general rule is that the wall clock is for telling time and the
    36  	//   monotonic clock is for measuring time. Rather than split the API, in this
    37  	//   package the Time returned by time.Now contains both a wall clock reading
    38  	//   and a monotonic clock reading; later time-telling operations use the wall
    39  	//   clock reading, but later time-measuring operations, specifically
    40  	//   comparisons and subtractions, use the monotonic clock reading.
    41  	//
    42  	//   ...
    43  	//
    44  	//   If Times t and u both contain monotonic clock readings, the operations
    45  	//   t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out using
    46  	//   the monotonic clock readings alone, ignoring the wall clock readings. If
    47  	//   either t or u contains no monotonic clock reading, these operations fall
    48  	//   back to using the wall clock readings.
    49  	//
    50  	// Given the above, we can safely conclude that time.Since(baseTime) will
    51  	// return monotonically increasing values if we use time.Now() to set baseTime
    52  	// at the time of clock construction.
    53  	//
    54  	// Note that time.Since(t) is shorthand for time.Now().Sub(t), as per
    55  	// https://golang.org/pkg/time/#Since.
    56  	baseTime time.Time `state:"nosave"`
    57  
    58  	// monotonicOffset is the offset applied to the calculated monotonic time.
    59  	//
    60  	// monotonicOffset is assigned maxMonotonic after restore so that the
    61  	// monotonic time will continue from where it "left off" before saving as part
    62  	// of S/R.
    63  	monotonicOffset MonotonicTime `state:"nosave"`
    64  
    65  	// monotonicMU protects maxMonotonic.
    66  	monotonicMU  sync.Mutex `state:"nosave"`
    67  	maxMonotonic MonotonicTime
    68  }
    69  
    70  // NewStdClock returns an instance of a clock that uses the time package.
    71  func NewStdClock() Clock {
    72  	return &stdClock{
    73  		baseTime: time.Now(),
    74  	}
    75  }
    76  
    77  var _ Clock = (*stdClock)(nil)
    78  
    79  // Now implements Clock.Now.
    80  func (*stdClock) Now() time.Time {
    81  	return time.Now()
    82  }
    83  
    84  // NowMonotonic implements Clock.NowMonotonic.
    85  func (s *stdClock) NowMonotonic() MonotonicTime {
    86  	sinceBase := time.Since(s.baseTime)
    87  	if sinceBase < 0 {
    88  		panic(fmt.Sprintf("got negative duration = %s since base time = %s", sinceBase, s.baseTime))
    89  	}
    90  
    91  	monotonicValue := s.monotonicOffset.Add(sinceBase)
    92  
    93  	s.monotonicMU.Lock()
    94  	defer s.monotonicMU.Unlock()
    95  
    96  	// Monotonic time values must never decrease.
    97  	if s.maxMonotonic.Before(monotonicValue) {
    98  		s.maxMonotonic = monotonicValue
    99  	}
   100  
   101  	return s.maxMonotonic
   102  }
   103  
   104  // AfterFunc implements Clock.AfterFunc.
   105  func (*stdClock) AfterFunc(d time.Duration, f func()) Timer {
   106  	return &stdTimer{
   107  		t: time.AfterFunc(d, f),
   108  	}
   109  }
   110  
   111  type stdTimer struct {
   112  	t *time.Timer
   113  }
   114  
   115  var _ Timer = (*stdTimer)(nil)
   116  
   117  // Stop implements Timer.Stop.
   118  func (st *stdTimer) Stop() bool {
   119  	return st.t.Stop()
   120  }
   121  
   122  // Reset implements Timer.Reset.
   123  func (st *stdTimer) Reset(d time.Duration) {
   124  	st.t.Reset(d)
   125  }
   126  
   127  // NewStdTimer returns a Timer implemented with the time package.
   128  func NewStdTimer(t *time.Timer) Timer {
   129  	return &stdTimer{t: t}
   130  }