131 lines
4.0 KiB
Go
131 lines
4.0 KiB
Go
// Copyright 2018 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package tcpip
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gvisor.dev/gvisor/pkg/sync"
|
|
)
|
|
|
|
// stdClock implements Clock with the time package.
|
|
//
|
|
// +stateify savable
|
|
type stdClock struct {
|
|
// baseTime holds the time when the clock was constructed.
|
|
//
|
|
// This value is used to calculate the monotonic time from the time package.
|
|
// As per https://golang.org/pkg/time/#hdr-Monotonic_Clocks,
|
|
//
|
|
// Operating systems provide both a “wall clock,” which is subject to
|
|
// changes for clock synchronization, and a “monotonic clock,” which is not.
|
|
// The general rule is that the wall clock is for telling time and the
|
|
// monotonic clock is for measuring time. Rather than split the API, in this
|
|
// package the Time returned by time.Now contains both a wall clock reading
|
|
// and a monotonic clock reading; later time-telling operations use the wall
|
|
// clock reading, but later time-measuring operations, specifically
|
|
// comparisons and subtractions, use the monotonic clock reading.
|
|
//
|
|
// ...
|
|
//
|
|
// If Times t and u both contain monotonic clock readings, the operations
|
|
// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out using
|
|
// the monotonic clock readings alone, ignoring the wall clock readings. If
|
|
// either t or u contains no monotonic clock reading, these operations fall
|
|
// back to using the wall clock readings.
|
|
//
|
|
// Given the above, we can safely conclude that time.Since(baseTime) will
|
|
// return monotonically increasing values if we use time.Now() to set baseTime
|
|
// at the time of clock construction.
|
|
//
|
|
// Note that time.Since(t) is shorthand for time.Now().Sub(t), as per
|
|
// https://golang.org/pkg/time/#Since.
|
|
baseTime time.Time `state:"nosave"`
|
|
|
|
// monotonicOffset is the offset applied to the calculated monotonic time.
|
|
//
|
|
// monotonicOffset is assigned maxMonotonic after restore so that the
|
|
// monotonic time will continue from where it "left off" before saving as part
|
|
// of S/R.
|
|
monotonicOffset MonotonicTime `state:"nosave"`
|
|
|
|
// monotonicMU protects maxMonotonic.
|
|
monotonicMU sync.Mutex `state:"nosave"`
|
|
maxMonotonic MonotonicTime
|
|
}
|
|
|
|
// NewStdClock returns an instance of a clock that uses the time package.
|
|
func NewStdClock() Clock {
|
|
return &stdClock{
|
|
baseTime: time.Now(),
|
|
}
|
|
}
|
|
|
|
var _ Clock = (*stdClock)(nil)
|
|
|
|
// Now implements Clock.Now.
|
|
func (*stdClock) Now() time.Time {
|
|
return time.Now()
|
|
}
|
|
|
|
// NowMonotonic implements Clock.NowMonotonic.
|
|
func (s *stdClock) NowMonotonic() MonotonicTime {
|
|
sinceBase := time.Since(s.baseTime)
|
|
if sinceBase < 0 {
|
|
panic(fmt.Sprintf("got negative duration = %s since base time = %s", sinceBase, s.baseTime))
|
|
}
|
|
|
|
monotonicValue := s.monotonicOffset.Add(sinceBase)
|
|
|
|
s.monotonicMU.Lock()
|
|
defer s.monotonicMU.Unlock()
|
|
|
|
// Monotonic time values must never decrease.
|
|
if s.maxMonotonic.Before(monotonicValue) {
|
|
s.maxMonotonic = monotonicValue
|
|
}
|
|
|
|
return s.maxMonotonic
|
|
}
|
|
|
|
// AfterFunc implements Clock.AfterFunc.
|
|
func (*stdClock) AfterFunc(d time.Duration, f func()) Timer {
|
|
return &stdTimer{
|
|
t: time.AfterFunc(d, f),
|
|
}
|
|
}
|
|
|
|
type stdTimer struct {
|
|
t *time.Timer
|
|
}
|
|
|
|
var _ Timer = (*stdTimer)(nil)
|
|
|
|
// Stop implements Timer.Stop.
|
|
func (st *stdTimer) Stop() bool {
|
|
return st.t.Stop()
|
|
}
|
|
|
|
// Reset implements Timer.Reset.
|
|
func (st *stdTimer) Reset(d time.Duration) {
|
|
st.t.Reset(d)
|
|
}
|
|
|
|
// NewStdTimer returns a Timer implemented with the time package.
|
|
func NewStdTimer(t *time.Timer) Timer {
|
|
return &stdTimer{t: t}
|
|
}
|