diff options
-rw-r--r-- | pkg/sentry/kernel/time/time.go | 19 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/linux_state_autogen.go | 6 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_time.go | 64 |
3 files changed, 26 insertions, 63 deletions
diff --git a/pkg/sentry/kernel/time/time.go b/pkg/sentry/kernel/time/time.go index f61a8e164..26aa34aa6 100644 --- a/pkg/sentry/kernel/time/time.go +++ b/pkg/sentry/kernel/time/time.go @@ -458,25 +458,6 @@ func NewTimer(clock Clock, listener TimerListener) *Timer { return t } -// After waits for the duration to elapse according to clock and then sends a -// notification on the returned channel. The timer is started immediately and -// will fire exactly once. The second return value is the start time used with -// the duration. -// -// Callers must call Timer.Destroy. -func After(clock Clock, duration time.Duration) (*Timer, Time, <-chan struct{}) { - notifier, tchan := NewChannelNotifier() - t := NewTimer(clock, notifier) - now := clock.Now() - - t.Swap(Setting{ - Enabled: true, - Period: 0, - Next: now.Add(duration), - }) - return t, now, tchan -} - // init initializes Timer state that is not preserved across save/restore. If // init has already been called, calling it again is a no-op. // diff --git a/pkg/sentry/syscalls/linux/linux_state_autogen.go b/pkg/sentry/syscalls/linux/linux_state_autogen.go index 1f55db893..cc577e4ac 100644 --- a/pkg/sentry/syscalls/linux/linux_state_autogen.go +++ b/pkg/sentry/syscalls/linux/linux_state_autogen.go @@ -81,7 +81,7 @@ func (n *clockNanosleepRestartBlock) StateTypeName() string { func (n *clockNanosleepRestartBlock) StateFields() []string { return []string{ "c", - "duration", + "end", "rem", } } @@ -92,7 +92,7 @@ func (n *clockNanosleepRestartBlock) beforeSave() {} func (n *clockNanosleepRestartBlock) StateSave(stateSinkObject state.Sink) { n.beforeSave() stateSinkObject.Save(0, &n.c) - stateSinkObject.Save(1, &n.duration) + stateSinkObject.Save(1, &n.end) stateSinkObject.Save(2, &n.rem) } @@ -101,7 +101,7 @@ func (n *clockNanosleepRestartBlock) afterLoad() {} // +checklocksignore func (n *clockNanosleepRestartBlock) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(0, &n.c) - stateSourceObject.Load(1, &n.duration) + stateSourceObject.Load(1, &n.end) stateSourceObject.Load(2, &n.rem) } diff --git a/pkg/sentry/syscalls/linux/sys_time.go b/pkg/sentry/syscalls/linux/sys_time.go index 83b777bbd..5c3b3dee2 100644 --- a/pkg/sentry/syscalls/linux/sys_time.go +++ b/pkg/sentry/syscalls/linux/sys_time.go @@ -180,21 +180,21 @@ func Time(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC // // +stateify savable type clockNanosleepRestartBlock struct { - c ktime.Clock - duration time.Duration - rem hostarch.Addr + c ktime.Clock + end ktime.Time + rem hostarch.Addr } // Restart implements kernel.SyscallRestartBlock.Restart. func (n *clockNanosleepRestartBlock) Restart(t *kernel.Task) (uintptr, error) { - return 0, clockNanosleepFor(t, n.c, n.duration, n.rem) + return 0, clockNanosleepUntil(t, n.c, n.end, n.rem, true) } // clockNanosleepUntil blocks until a specified time. // // If blocking is interrupted, the syscall is restarted with the original // arguments. -func clockNanosleepUntil(t *kernel.Task, c ktime.Clock, ts linux.Timespec) error { +func clockNanosleepUntil(t *kernel.Task, c ktime.Clock, end ktime.Time, rem hostarch.Addr, needRestartBlock bool) error { notifier, tchan := ktime.NewChannelNotifier() timer := ktime.NewTimer(c, notifier) @@ -202,43 +202,22 @@ func clockNanosleepUntil(t *kernel.Task, c ktime.Clock, ts linux.Timespec) error timer.Swap(ktime.Setting{ Period: 0, Enabled: true, - Next: ktime.FromTimespec(ts), + Next: end, }) err := t.BlockWithTimer(nil, tchan) timer.Destroy() - // Did we just block until the timeout happened? - if err == syserror.ETIMEDOUT { - return nil - } - - return syserror.ConvertIntr(err, syserror.ERESTARTNOHAND) -} - -// clockNanosleepFor blocks for a specified duration. -// -// If blocking is interrupted, the syscall is restarted with the remaining -// duration timeout. -func clockNanosleepFor(t *kernel.Task, c ktime.Clock, dur time.Duration, rem hostarch.Addr) error { - timer, start, tchan := ktime.After(c, dur) - - err := t.BlockWithTimer(nil, tchan) - - after := c.Now() - - timer.Destroy() - switch err { case syserror.ETIMEDOUT: // Slept for entire timeout. return nil case syserror.ErrInterrupted: // Interrupted. - remaining := dur - after.Sub(start) - if remaining < 0 { - remaining = time.Duration(0) + remaining := end.Sub(c.Now()) + if remaining <= 0 { + return nil } // Copy out remaining time. @@ -248,14 +227,16 @@ func clockNanosleepFor(t *kernel.Task, c ktime.Clock, dur time.Duration, rem hos return err } } - - // Arrange for a restart with the remaining duration. - t.SetSyscallRestartBlock(&clockNanosleepRestartBlock{ - c: c, - duration: remaining, - rem: rem, - }) - return syserror.ERESTART_RESTARTBLOCK + if needRestartBlock { + // Arrange for a restart with the remaining duration. + t.SetSyscallRestartBlock(&clockNanosleepRestartBlock{ + c: c, + end: end, + rem: rem, + }) + return syserror.ERESTART_RESTARTBLOCK + } + return syserror.ERESTARTNOHAND default: panic(fmt.Sprintf("Impossible BlockWithTimer error %v", err)) } @@ -278,7 +259,8 @@ func Nanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys // Just like linux, we cap the timeout with the max number that int64 can // represent which is roughly 292 years. dur := time.Duration(ts.ToNsecCapped()) * time.Nanosecond - return 0, nil, clockNanosleepFor(t, t.Kernel().MonotonicClock(), dur, rem) + c := t.Kernel().MonotonicClock() + return 0, nil, clockNanosleepUntil(t, c, c.Now().Add(dur), rem, true) } // ClockNanosleep implements linux syscall clock_nanosleep(2). @@ -312,11 +294,11 @@ func ClockNanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne } if flags&linux.TIMER_ABSTIME != 0 { - return 0, nil, clockNanosleepUntil(t, c, req) + return 0, nil, clockNanosleepUntil(t, c, ktime.FromTimespec(req), 0, false) } dur := time.Duration(req.ToNsecCapped()) * time.Nanosecond - return 0, nil, clockNanosleepFor(t, c, dur, rem) + return 0, nil, clockNanosleepUntil(t, c, c.Now().Add(dur), rem, true) } // Gettimeofday implements linux syscall gettimeofday(2). |