summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/time/time.go
diff options
context:
space:
mode:
authorJamie Liu <jamieliu@google.com>2018-10-17 15:48:55 -0700
committerShentubot <shentubot@google.com>2018-10-17 15:50:02 -0700
commitb2a88ff4713325fca736f6a3bf200be02d2d72a7 (patch)
tree489e54828c2bfe0bf326976920e5d5e612f877a0 /pkg/sentry/kernel/time/time.go
parent6922eee6499212a009fdc254224f916bd1c46f29 (diff)
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
Diffstat (limited to 'pkg/sentry/kernel/time/time.go')
-rw-r--r--pkg/sentry/kernel/time/time.go35
1 files changed, 26 insertions, 9 deletions
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 {