From b2a88ff4713325fca736f6a3bf200be02d2d72a7 Mon Sep 17 00:00:00 2001 From: Jamie Liu Date: Wed, 17 Oct 2018 15:48:55 -0700 Subject: Check thread group CPU timers in the CPU clock ticker. This reduces the number of goroutines and runtime timers when ITIMER_VIRTUAL or ITIMER_PROF are enabled, or when RLIMIT_CPU is set. This also ensures that thread group CPU timers only advance if running tasks are observed at the time the CPU clock advances, mostly eliminating the possibility that a CPU timer expiration observes no running tasks and falls back to the group leader. PiperOrigin-RevId: 217603396 Change-Id: Ia24ce934d5574334857d9afb5ad8ca0b6a6e65f4 --- pkg/sentry/kernel/time/time.go | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'pkg/sentry/kernel/time/time.go') diff --git a/pkg/sentry/kernel/time/time.go b/pkg/sentry/kernel/time/time.go index 1f6fed007..52e0dfba1 100644 --- a/pkg/sentry/kernel/time/time.go +++ b/pkg/sentry/kernel/time/time.go @@ -307,6 +307,12 @@ type Setting struct { // SettingFromSpec converts a (value, interval) pair to a Setting based on a // reading from c. value is interpreted as a time relative to c.Now(). func SettingFromSpec(value time.Duration, interval time.Duration, c Clock) (Setting, error) { + return SettingFromSpecAt(value, interval, c.Now()) +} + +// SettingFromSpecAt converts a (value, interval) pair to a Setting. value is +// interpreted as a time relative to now. +func SettingFromSpecAt(value time.Duration, interval time.Duration, now Time) (Setting, error) { if value < 0 { return Setting{}, syserror.EINVAL } @@ -315,7 +321,7 @@ func SettingFromSpec(value time.Duration, interval time.Duration, c Clock) (Sett } return Setting{ Enabled: true, - Next: c.Now().Add(value), + Next: now.Add(value), Period: interval, }, nil } @@ -365,14 +371,14 @@ func ItimerspecFromSetting(now Time, s Setting) linux.Itimerspec { } } -// advancedTo returns an updated Setting and a number of expirations after -// the associated Clock indicates a time of now. +// At returns an updated Setting and a number of expirations after the +// associated Clock indicates a time of now. // -// Settings may be created by successive calls to advancedTo with decreasing +// Settings may be created by successive calls to At with decreasing // values of now (i.e. time may appear to go backward). Supporting this is // required to support non-monotonic clocks, as well as allowing // Timer.clock.Now() to be called without holding Timer.mu. -func (s Setting) advancedTo(now Time) (Setting, uint64) { +func (s Setting) At(now Time) (Setting, uint64) { if !s.Enabled { return s, 0 } @@ -519,7 +525,7 @@ func (t *Timer) Tick() { if t.paused { return } - s, exp := t.setting.advancedTo(now) + s, exp := t.setting.At(now) t.setting = s if exp > 0 { t.listener.Notify(exp) @@ -574,7 +580,7 @@ func (t *Timer) Get() (Time, Setting) { if t.paused { panic(fmt.Sprintf("Timer.Get called on paused Timer %p", t)) } - s, exp := t.setting.advancedTo(now) + s, exp := t.setting.At(now) t.setting = s if exp > 0 { t.listener.Notify(exp) @@ -607,14 +613,14 @@ func (t *Timer) SwapAnd(s Setting, f func()) (Time, Setting) { if t.paused { panic(fmt.Sprintf("Timer.SwapAnd called on paused Timer %p", t)) } - oldS, oldExp := t.setting.advancedTo(now) + oldS, oldExp := t.setting.At(now) if oldExp > 0 { t.listener.Notify(oldExp) } if f != nil { f() } - newS, newExp := s.advancedTo(now) + newS, newExp := s.At(now) t.setting = newS if newExp > 0 { t.listener.Notify(newExp) @@ -623,6 +629,17 @@ func (t *Timer) SwapAnd(s Setting, f func()) (Time, Setting) { return now, oldS } +// Atomically invokes f atomically with respect to expirations of t; that is, t +// cannot generate expirations while f is being called. +// +// Preconditions: f cannot call any Timer methods since it is called with the +// Timer mutex locked. +func (t *Timer) Atomically(f func()) { + t.mu.Lock() + defer t.mu.Unlock() + f() +} + // Preconditions: t.mu must be locked. func (t *Timer) resetKickerLocked(now Time) { if t.setting.Enabled { -- cgit v1.2.3