stdclock.go raw

   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  // +stateify savable
  95  type stdTimer struct {
  96  	t *time.Timer
  97  }
  98  
  99  var _ Timer = (*stdTimer)(nil)
 100  
 101  // Stop implements Timer.Stop.
 102  func (st *stdTimer) Stop() bool {
 103  	return st.t.Stop()
 104  }
 105  
 106  // Reset implements Timer.Reset.
 107  func (st *stdTimer) Reset(d time.Duration) {
 108  	st.t.Reset(d)
 109  }
 110  
 111  // NewStdTimer returns a Timer implemented with the time package.
 112  func NewStdTimer(t *time.Timer) Timer {
 113  	return &stdTimer{t: t}
 114  }
 115