github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/timekeeper_test.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 kernel 16 17 import ( 18 "testing" 19 20 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 21 "github.com/SagerNet/gvisor/pkg/hostarch" 22 "github.com/SagerNet/gvisor/pkg/sentry/contexttest" 23 "github.com/SagerNet/gvisor/pkg/sentry/pgalloc" 24 sentrytime "github.com/SagerNet/gvisor/pkg/sentry/time" 25 "github.com/SagerNet/gvisor/pkg/sentry/usage" 26 ) 27 28 // mockClocks is a sentrytime.Clocks that simply returns the times in the 29 // struct. 30 type mockClocks struct { 31 monotonic int64 32 realtime int64 33 } 34 35 // Update implements sentrytime.Clocks.Update. It does nothing. 36 func (*mockClocks) Update() (monotonicParams sentrytime.Parameters, monotonicOk bool, realtimeParam sentrytime.Parameters, realtimeOk bool) { 37 return 38 } 39 40 // Update implements sentrytime.Clocks.GetTime. 41 func (c *mockClocks) GetTime(id sentrytime.ClockID) (int64, error) { 42 switch id { 43 case sentrytime.Monotonic: 44 return c.monotonic, nil 45 case sentrytime.Realtime: 46 return c.realtime, nil 47 default: 48 return 0, linuxerr.EINVAL 49 } 50 } 51 52 // stateTestClocklessTimekeeper returns a test Timekeeper which has not had 53 // SetClocks called. 54 func stateTestClocklessTimekeeper(tb testing.TB) *Timekeeper { 55 ctx := contexttest.Context(tb) 56 mfp := pgalloc.MemoryFileProviderFromContext(ctx) 57 fr, err := mfp.MemoryFile().Allocate(hostarch.PageSize, usage.Anonymous) 58 if err != nil { 59 tb.Fatalf("failed to allocate memory: %v", err) 60 } 61 return &Timekeeper{ 62 params: NewVDSOParamPage(mfp, fr), 63 } 64 } 65 66 func stateTestTimekeeper(tb testing.TB) *Timekeeper { 67 t := stateTestClocklessTimekeeper(tb) 68 t.SetClocks(sentrytime.NewCalibratedClocks()) 69 return t 70 } 71 72 // TestTimekeeperMonotonicZero tests that monotonic time starts at zero. 73 func TestTimekeeperMonotonicZero(t *testing.T) { 74 c := &mockClocks{ 75 monotonic: 100000, 76 } 77 78 tk := stateTestClocklessTimekeeper(t) 79 tk.SetClocks(c) 80 defer tk.Destroy() 81 82 now, err := tk.GetTime(sentrytime.Monotonic) 83 if err != nil { 84 t.Errorf("GetTime err got %v want nil", err) 85 } 86 if now != 0 { 87 t.Errorf("GetTime got %d want 0", now) 88 } 89 90 c.monotonic += 10 91 92 now, err = tk.GetTime(sentrytime.Monotonic) 93 if err != nil { 94 t.Errorf("GetTime err got %v want nil", err) 95 } 96 if now != 10 { 97 t.Errorf("GetTime got %d want 10", now) 98 } 99 } 100 101 // TestTimekeeperMonotonicJumpForward tests that monotonic time jumps forward 102 // after restore. 103 func TestTimekeeperMonotonicForward(t *testing.T) { 104 c := &mockClocks{ 105 monotonic: 900000, 106 realtime: 600000, 107 } 108 109 tk := stateTestClocklessTimekeeper(t) 110 tk.restored = make(chan struct{}) 111 tk.saveMonotonic = 100000 112 tk.saveRealtime = 400000 113 tk.SetClocks(c) 114 defer tk.Destroy() 115 116 // The monotonic clock should jump ahead by 200000 to 300000. 117 // 118 // The new system monotonic time (900000) is irrelevant to what the app 119 // sees. 120 now, err := tk.GetTime(sentrytime.Monotonic) 121 if err != nil { 122 t.Errorf("GetTime err got %v want nil", err) 123 } 124 if now != 300000 { 125 t.Errorf("GetTime got %d want 300000", now) 126 } 127 } 128 129 // TestTimekeeperMonotonicJumpBackwards tests that monotonic time does not jump 130 // backwards when realtime goes backwards. 131 func TestTimekeeperMonotonicJumpBackwards(t *testing.T) { 132 c := &mockClocks{ 133 monotonic: 900000, 134 realtime: 400000, 135 } 136 137 tk := stateTestClocklessTimekeeper(t) 138 tk.restored = make(chan struct{}) 139 tk.saveMonotonic = 100000 140 tk.saveRealtime = 600000 141 tk.SetClocks(c) 142 defer tk.Destroy() 143 144 // The monotonic clock should remain at 100000. 145 // 146 // The new system monotonic time (900000) is irrelevant to what the app 147 // sees and we don't want to jump the monotonic clock backwards like 148 // realtime did. 149 now, err := tk.GetTime(sentrytime.Monotonic) 150 if err != nil { 151 t.Errorf("GetTime err got %v want nil", err) 152 } 153 if now != 100000 { 154 t.Errorf("GetTime got %d want 100000", now) 155 } 156 }