2020-07-30 20:28:21 +00:00
|
|
|
// Copyright 2020 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.
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
// Package faketime provides a fake clock that implements tcpip.Clock interface.
|
|
|
|
package faketime
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"container/heap"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/dpjacques/clockwork"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
|
|
)
|
|
|
|
|
2020-09-29 18:27:43 +00:00
|
|
|
// NullClock implements a clock that never advances.
|
|
|
|
type NullClock struct{}
|
|
|
|
|
|
|
|
var _ tcpip.Clock = (*NullClock)(nil)
|
|
|
|
|
|
|
|
// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
|
|
|
|
func (*NullClock) NowNanoseconds() int64 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// NowMonotonic implements tcpip.Clock.NowMonotonic.
|
|
|
|
func (*NullClock) NowMonotonic() int64 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// AfterFunc implements tcpip.Clock.AfterFunc.
|
|
|
|
func (*NullClock) AfterFunc(time.Duration, func()) tcpip.Timer {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
// ManualClock implements tcpip.Clock and only advances manually with Advance
|
|
|
|
// method.
|
|
|
|
type ManualClock struct {
|
2020-07-30 20:28:21 +00:00
|
|
|
clock clockwork.FakeClock
|
|
|
|
|
|
|
|
// mu protects the fields below.
|
|
|
|
mu sync.RWMutex
|
|
|
|
|
|
|
|
// times is min-heap of times. A heap is used for quick retrieval of the next
|
|
|
|
// upcoming time of scheduled work.
|
|
|
|
times *timeHeap
|
|
|
|
|
|
|
|
// waitGroups stores one WaitGroup for all work scheduled to execute at the
|
|
|
|
// same time via AfterFunc. This allows parallel execution of all functions
|
|
|
|
// passed to AfterFunc scheduled for the same time.
|
|
|
|
waitGroups map[time.Time]*sync.WaitGroup
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
// NewManualClock creates a new ManualClock instance.
|
|
|
|
func NewManualClock() *ManualClock {
|
|
|
|
return &ManualClock{
|
2020-07-30 20:28:21 +00:00
|
|
|
clock: clockwork.NewFakeClock(),
|
|
|
|
times: &timeHeap{},
|
|
|
|
waitGroups: make(map[time.Time]*sync.WaitGroup),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
var _ tcpip.Clock = (*ManualClock)(nil)
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (mc *ManualClock) NowNanoseconds() int64 {
|
|
|
|
return mc.clock.Now().UnixNano()
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NowMonotonic implements tcpip.Clock.NowMonotonic.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (mc *ManualClock) NowMonotonic() int64 {
|
|
|
|
return mc.NowNanoseconds()
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AfterFunc implements tcpip.Clock.AfterFunc.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (mc *ManualClock) AfterFunc(d time.Duration, f func()) tcpip.Timer {
|
|
|
|
until := mc.clock.Now().Add(d)
|
|
|
|
wg := mc.addWait(until)
|
|
|
|
return &manualTimer{
|
|
|
|
clock: mc,
|
2020-07-30 20:28:21 +00:00
|
|
|
until: until,
|
2020-09-22 19:43:28 +00:00
|
|
|
timer: mc.clock.AfterFunc(d, func() {
|
2020-07-30 20:28:21 +00:00
|
|
|
defer wg.Done()
|
|
|
|
f()
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// addWait adds an additional wait to the WaitGroup for parallel execution of
|
|
|
|
// all work scheduled for t. Returns a reference to the WaitGroup modified.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (mc *ManualClock) addWait(t time.Time) *sync.WaitGroup {
|
|
|
|
mc.mu.RLock()
|
|
|
|
wg, ok := mc.waitGroups[t]
|
|
|
|
mc.mu.RUnlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
if ok {
|
|
|
|
wg.Add(1)
|
|
|
|
return wg
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.Lock()
|
|
|
|
heap.Push(mc.times, t)
|
|
|
|
mc.mu.Unlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
wg = &sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.Lock()
|
|
|
|
mc.waitGroups[t] = wg
|
|
|
|
mc.mu.Unlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
return wg
|
|
|
|
}
|
|
|
|
|
|
|
|
// removeWait removes a wait from the WaitGroup for parallel execution of all
|
|
|
|
// work scheduled for t.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (mc *ManualClock) removeWait(t time.Time) {
|
|
|
|
mc.mu.RLock()
|
|
|
|
defer mc.mu.RUnlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
wg := mc.waitGroups[t]
|
2020-07-30 20:28:21 +00:00
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
// Advance executes all work that have been scheduled to execute within d from
|
|
|
|
// the current time. Blocks until all work has completed execution.
|
|
|
|
func (mc *ManualClock) Advance(d time.Duration) {
|
2020-07-30 20:28:21 +00:00
|
|
|
// Block until all the work is done
|
2020-09-22 19:43:28 +00:00
|
|
|
until := mc.clock.Now().Add(d)
|
2020-07-30 20:28:21 +00:00
|
|
|
for {
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.Lock()
|
|
|
|
if mc.times.Len() == 0 {
|
|
|
|
mc.mu.Unlock()
|
|
|
|
break
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
t := heap.Pop(mc.times).(time.Time)
|
2020-07-30 20:28:21 +00:00
|
|
|
if t.After(until) {
|
|
|
|
// No work to do
|
2020-09-22 19:43:28 +00:00
|
|
|
heap.Push(mc.times, t)
|
|
|
|
mc.mu.Unlock()
|
|
|
|
break
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.Unlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
diff := t.Sub(mc.clock.Now())
|
|
|
|
mc.clock.Advance(diff)
|
2020-07-30 20:28:21 +00:00
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.RLock()
|
|
|
|
wg := mc.waitGroups[t]
|
|
|
|
mc.mu.RUnlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
mc.mu.Lock()
|
|
|
|
delete(mc.waitGroups, t)
|
|
|
|
mc.mu.Unlock()
|
|
|
|
}
|
|
|
|
if now := mc.clock.Now(); until.After(now) {
|
|
|
|
mc.clock.Advance(until.Sub(now))
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
type manualTimer struct {
|
|
|
|
clock *ManualClock
|
2020-07-30 20:28:21 +00:00
|
|
|
timer clockwork.Timer
|
|
|
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
until time.Time
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
var _ tcpip.Timer = (*manualTimer)(nil)
|
2020-07-30 20:28:21 +00:00
|
|
|
|
|
|
|
// Reset implements tcpip.Timer.Reset.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (t *manualTimer) Reset(d time.Duration) {
|
|
|
|
if !t.timer.Reset(d) {
|
2020-07-30 20:28:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
t.mu.Lock()
|
|
|
|
defer t.mu.Unlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
t.clock.removeWait(t.until)
|
|
|
|
t.until = t.clock.clock.Now().Add(d)
|
|
|
|
t.clock.addWait(t.until)
|
2020-07-30 20:28:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stop implements tcpip.Timer.Stop.
|
2020-09-22 19:43:28 +00:00
|
|
|
func (t *manualTimer) Stop() bool {
|
|
|
|
if !t.timer.Stop() {
|
2020-07-30 20:28:21 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
t.mu.RLock()
|
|
|
|
defer t.mu.RUnlock()
|
2020-07-30 20:28:21 +00:00
|
|
|
|
2020-09-22 19:43:28 +00:00
|
|
|
t.clock.removeWait(t.until)
|
2020-07-30 20:28:21 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
type timeHeap []time.Time
|
|
|
|
|
|
|
|
var _ heap.Interface = (*timeHeap)(nil)
|
|
|
|
|
|
|
|
func (h timeHeap) Len() int {
|
|
|
|
return len(h)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h timeHeap) Less(i, j int) bool {
|
|
|
|
return h[i].Before(h[j])
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h timeHeap) Swap(i, j int) {
|
|
|
|
h[i], h[j] = h[j], h[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *timeHeap) Push(x interface{}) {
|
|
|
|
*h = append(*h, x.(time.Time))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *timeHeap) Pop() interface{} {
|
|
|
|
last := (*h)[len(*h)-1]
|
|
|
|
*h = (*h)[:len(*h)-1]
|
|
|
|
return last
|
|
|
|
}
|