| // 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} |
| } |