summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/timer.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/kernel/timer.go')
-rw-r--r--pkg/sentry/kernel/timer.go290
1 files changed, 0 insertions, 290 deletions
diff --git a/pkg/sentry/kernel/timer.go b/pkg/sentry/kernel/timer.go
deleted file mode 100644
index 534d03d0f..000000000
--- a/pkg/sentry/kernel/timer.go
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// 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 kernel
-
-import (
- "fmt"
- "time"
-
- "gvisor.googlesource.com/gvisor/pkg/abi/linux"
- ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
- "gvisor.googlesource.com/gvisor/pkg/sentry/limits"
- sentrytime "gvisor.googlesource.com/gvisor/pkg/sentry/time"
-)
-
-// timekeeperClock is a ktime.Clock that reads time from a
-// kernel.Timekeeper-managed clock.
-//
-// +stateify savable
-type timekeeperClock struct {
- tk *Timekeeper
- c sentrytime.ClockID
-
- // Implements ktime.Clock.WallTimeUntil.
- ktime.WallRateClock `state:"nosave"`
-
- // Implements waiter.Waitable. (We have no ability to detect
- // discontinuities from external changes to CLOCK_REALTIME).
- ktime.NoClockEvents `state:"nosave"`
-}
-
-// Now implements ktime.Clock.Now.
-func (tc *timekeeperClock) Now() ktime.Time {
- now, err := tc.tk.GetTime(tc.c)
- if err != nil {
- panic(fmt.Sprintf("timekeeperClock(ClockID=%v)).Now: %v", tc.c, err))
- }
- return ktime.FromNanoseconds(now)
-}
-
-// tgClock is a ktime.Clock that measures the time a thread group has spent
-// executing.
-//
-// +stateify savable
-type tgClock struct {
- tg *ThreadGroup
-
- // If includeSys is true, the tgClock includes both time spent executing
- // application code as well as time spent in the sentry. Otherwise, the
- // tgClock includes only time spent executing application code.
- includeSys bool
-
- // Implements waiter.Waitable.
- ktime.ClockEventsQueue `state:"nosave"`
-}
-
-// UserCPUClock returns a ktime.Clock that measures the time that a thread
-// group has spent executing.
-func (tg *ThreadGroup) UserCPUClock() ktime.Clock {
- return tg.tm.virtClock
-}
-
-// CPUClock returns a ktime.Clock that measures the time that a thread group
-// has spent executing, including sentry time.
-func (tg *ThreadGroup) CPUClock() ktime.Clock {
- return tg.tm.profClock
-}
-
-// Now implements ktime.Clock.Now.
-func (tgc *tgClock) Now() ktime.Time {
- stats := tgc.tg.CPUStats()
- if tgc.includeSys {
- return ktime.FromNanoseconds((stats.UserTime + stats.SysTime).Nanoseconds())
- }
- return ktime.FromNanoseconds(stats.UserTime.Nanoseconds())
-}
-
-// WallTimeUntil implements ktime.Clock.WallTimeUntil.
-func (tgc *tgClock) WallTimeUntil(t, now ktime.Time) time.Duration {
- // The assumption here is that the time spent in this process (not matter
- // virtual or prof) should not exceed wall time * active tasks, since
- // Task.exitThreadGroup stops accounting as it transitions to
- // TaskExitInitiated.
- tgc.tg.pidns.owner.mu.RLock()
- n := tgc.tg.activeTasks
- tgc.tg.pidns.owner.mu.RUnlock()
- if n == 0 {
- if t.Before(now) {
- return 0
- }
- // The timer tick raced with thread group exit, after which no more
- // tasks can enter the thread group. So tgc.Now() will never advance
- // again. Return a large delay; the timer should be stopped long before
- // it comes again anyway.
- return time.Hour
- }
- // This is a lower bound on the amount of time that can elapse before an
- // associated timer expires, so returning this value tends to result in a
- // sequence of closely-spaced ticks just before timer expiry. To avoid
- // this, round up to the nearest ClockTick; CPU usage measurements are
- // limited to this resolution anyway.
- remaining := time.Duration(int64(t.Sub(now))/int64(n)) * time.Nanosecond
- return ((remaining + (linux.ClockTick - time.Nanosecond)) / linux.ClockTick) * linux.ClockTick
-}
-
-// taskClock is a ktime.Clock that measures the time that a task has spent
-// executing.
-type taskClock struct {
- t *Task
-
- // If includeSys is true, the taskClock includes both time spent executing
- // application code as well as time spent in the sentry. Otherwise, the
- // taskClock includes only time spent executing application code.
- includeSys bool
-
- // Implements waiter.Waitable. TimeUntil wouldn't change its estimation
- // based on either of the clock events, so there's no event to be
- // notified for.
- ktime.NoClockEvents `state:"nosave"`
-
- // Implements ktime.Clock.WallTimeUntil.
- //
- // As an upper bound, a task's clock cannot advance faster than CPU
- // time. It would have to execute at a rate of more than 1 task-second
- // per 1 CPU-second, which isn't possible.
- ktime.WallRateClock `state:"nosave"`
-}
-
-// UserCPUClock returns a clock measuring the CPU time the task has spent
-// executing application code.
-func (t *Task) UserCPUClock() ktime.Clock {
- return &taskClock{t: t, includeSys: false}
-}
-
-// CPUClock returns a clock measuring the CPU time the task has spent executing
-// application and "kernel" code.
-func (t *Task) CPUClock() ktime.Clock {
- return &taskClock{t: t, includeSys: true}
-}
-
-// Now implements ktime.Clock.Now.
-func (tc *taskClock) Now() ktime.Time {
- stats := tc.t.CPUStats()
- if tc.includeSys {
- return ktime.FromNanoseconds((stats.UserTime + stats.SysTime).Nanoseconds())
- }
- return ktime.FromNanoseconds(stats.UserTime.Nanoseconds())
-}
-
-// signalNotifier is a ktime.Listener that sends signals to a ThreadGroup.
-//
-// +stateify savable
-type signalNotifier struct {
- tg *ThreadGroup
- signal linux.Signal
- realTimer bool
- includeSys bool
-}
-
-// Notify implements ktime.TimerListener.Notify.
-func (s *signalNotifier) Notify(exp uint64) {
- // Since all signals sent using a signalNotifier are standard (not
- // real-time) signals, we can ignore the number of expirations and send
- // only a single signal.
- if s.realTimer {
- // real timer signal sent to leader. See kernel/time/itimer.c:it_real_fn
- s.tg.SendSignal(sigPriv(s.signal))
- } else {
- s.tg.SendTimerSignal(sigPriv(s.signal), s.includeSys)
- }
-}
-
-// Destroy implements ktime.TimerListener.Destroy.
-func (s *signalNotifier) Destroy() {}
-
-// TimerManager is a collection of supported process cpu timers.
-//
-// +stateify savable
-type TimerManager struct {
- // Clocks used to drive thread group execution time timers.
- virtClock *tgClock
- profClock *tgClock
-
- RealTimer *ktime.Timer
- VirtualTimer *ktime.Timer
- ProfTimer *ktime.Timer
- SoftLimitTimer *ktime.Timer
- HardLimitTimer *ktime.Timer
-}
-
-// newTimerManager returns a new instance of TimerManager.
-func newTimerManager(tg *ThreadGroup, monotonicClock ktime.Clock) TimerManager {
- virtClock := &tgClock{tg: tg, includeSys: false}
- profClock := &tgClock{tg: tg, includeSys: true}
- tm := TimerManager{
- virtClock: virtClock,
- profClock: profClock,
- RealTimer: ktime.NewTimer(monotonicClock, &signalNotifier{
- tg: tg,
- signal: linux.SIGALRM,
- realTimer: true,
- includeSys: false,
- }),
- VirtualTimer: ktime.NewTimer(virtClock, &signalNotifier{
- tg: tg,
- signal: linux.SIGVTALRM,
- realTimer: false,
- includeSys: false,
- }),
- ProfTimer: ktime.NewTimer(profClock, &signalNotifier{
- tg: tg,
- signal: linux.SIGPROF,
- realTimer: false,
- includeSys: true,
- }),
- SoftLimitTimer: ktime.NewTimer(profClock, &signalNotifier{
- tg: tg,
- signal: linux.SIGXCPU,
- realTimer: false,
- includeSys: true,
- }),
- HardLimitTimer: ktime.NewTimer(profClock, &signalNotifier{
- tg: tg,
- signal: linux.SIGKILL,
- realTimer: false,
- includeSys: true,
- }),
- }
- tm.applyCPULimits(tg.Limits().Get(limits.CPU))
- return tm
-}
-
-// Save saves this TimerManger.
-
-// destroy destroys all timers.
-func (tm *TimerManager) destroy() {
- tm.RealTimer.Destroy()
- tm.VirtualTimer.Destroy()
- tm.ProfTimer.Destroy()
- tm.SoftLimitTimer.Destroy()
- tm.HardLimitTimer.Destroy()
-}
-
-func (tm *TimerManager) applyCPULimits(l limits.Limit) {
- tm.SoftLimitTimer.Swap(ktime.Setting{
- Enabled: l.Cur != limits.Infinity,
- Next: ktime.FromNanoseconds((time.Duration(l.Cur) * time.Second).Nanoseconds()),
- Period: time.Second,
- })
- tm.HardLimitTimer.Swap(ktime.Setting{
- Enabled: l.Max != limits.Infinity,
- Next: ktime.FromNanoseconds((time.Duration(l.Max) * time.Second).Nanoseconds()),
- })
-}
-
-// kick is called when the number of threads in the thread group associated
-// with tm increases.
-func (tm *TimerManager) kick() {
- tm.virtClock.Notify(ktime.ClockEventRateIncrease)
- tm.profClock.Notify(ktime.ClockEventRateIncrease)
-}
-
-// pause is to pause the timers and stop timer signal delivery.
-func (tm *TimerManager) pause() {
- tm.RealTimer.Pause()
- tm.VirtualTimer.Pause()
- tm.ProfTimer.Pause()
- tm.SoftLimitTimer.Pause()
- tm.HardLimitTimer.Pause()
-}
-
-// resume is to resume the timers and continue timer signal delivery.
-func (tm *TimerManager) resume() {
- tm.RealTimer.Resume()
- tm.VirtualTimer.Resume()
- tm.ProfTimer.Resume()
- tm.SoftLimitTimer.Resume()
- tm.HardLimitTimer.Resume()
-}