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