From 64403265a04aa0c8be3ebb652a09f6e2d7a84ca7 Mon Sep 17 00:00:00 2001
From: Jamie Liu <jamieliu@google.com>
Date: Thu, 23 Aug 2018 16:31:25 -0700
Subject: Implement POSIX per-process interval timers.

PiperOrigin-RevId: 210021612
Change-Id: If7c161e6fd08cf17942bfb6bc5a8d2c4e271c61e
---
 pkg/sentry/syscalls/linux/linux64.go     | 10 ++--
 pkg/sentry/syscalls/linux/sys_timer.go   | 85 ++++++++++++++++++++++++++++++++
 pkg/sentry/syscalls/linux/sys_timerfd.go | 33 ++++---------
 3 files changed, 100 insertions(+), 28 deletions(-)

(limited to 'pkg/sentry/syscalls/linux')

diff --git a/pkg/sentry/syscalls/linux/linux64.go b/pkg/sentry/syscalls/linux/linux64.go
index c102af101..4465549ad 100644
--- a/pkg/sentry/syscalls/linux/linux64.go
+++ b/pkg/sentry/syscalls/linux/linux64.go
@@ -266,11 +266,11 @@ var AMD64 = &kernel.SyscallTable{
 		219: RestartSyscall,
 		//     220: Semtimedop, TODO
 		221: Fadvise64,
-		//     222: TimerCreate, TODO
-		//     223: TimerSettime, TODO
-		//     224: TimerGettime, TODO
-		//     225: TimerGetoverrun, TODO
-		//     226: TimerDelete, TODO
+		222: TimerCreate,
+		223: TimerSettime,
+		224: TimerGettime,
+		225: TimerGetoverrun,
+		226: TimerDelete,
 		227: ClockSettime,
 		228: ClockGettime,
 		229: ClockGetres,
diff --git a/pkg/sentry/syscalls/linux/sys_timer.go b/pkg/sentry/syscalls/linux/sys_timer.go
index 4ed077626..aaed75c81 100644
--- a/pkg/sentry/syscalls/linux/sys_timer.go
+++ b/pkg/sentry/syscalls/linux/sys_timer.go
@@ -166,3 +166,88 @@ func Alarm(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
 
 	return uintptr(sec), nil, nil
 }
+
+// TimerCreate implements linux syscall timer_create(2).
+func TimerCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+	clockID := args[0].Int()
+	sevp := args[1].Pointer()
+	timerIDp := args[2].Pointer()
+
+	c, err := getClock(t, clockID)
+	if err != nil {
+		return 0, nil, err
+	}
+
+	var sev *linux.Sigevent
+	if sevp != 0 {
+		sev = &linux.Sigevent{}
+		if _, err = t.CopyIn(sevp, sev); err != nil {
+			return 0, nil, err
+		}
+	}
+
+	id, err := t.IntervalTimerCreate(c, sev)
+	if err != nil {
+		return 0, nil, err
+	}
+
+	if _, err := t.CopyOut(timerIDp, &id); err != nil {
+		t.IntervalTimerDelete(id)
+		return 0, nil, err
+	}
+
+	return uintptr(id), nil, nil
+}
+
+// TimerSettime implements linux syscall timer_settime(2).
+func TimerSettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+	timerID := linux.TimerID(args[0].Value)
+	flags := args[1].Int()
+	newValAddr := args[2].Pointer()
+	oldValAddr := args[3].Pointer()
+
+	var newVal linux.Itimerspec
+	if _, err := t.CopyIn(newValAddr, &newVal); err != nil {
+		return 0, nil, err
+	}
+	oldVal, err := t.IntervalTimerSettime(timerID, newVal, flags&linux.TIMER_ABSTIME != 0)
+	if err != nil {
+		return 0, nil, err
+	}
+	if oldValAddr != 0 {
+		if _, err := t.CopyOut(oldValAddr, &oldVal); err != nil {
+			return 0, nil, err
+		}
+	}
+	return 0, nil, nil
+}
+
+// TimerGettime implements linux syscall timer_gettime(2).
+func TimerGettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+	timerID := linux.TimerID(args[0].Value)
+	curValAddr := args[1].Pointer()
+
+	curVal, err := t.IntervalTimerGettime(timerID)
+	if err != nil {
+		return 0, nil, err
+	}
+	_, err = t.CopyOut(curValAddr, &curVal)
+	return 0, nil, err
+}
+
+// TimerGetoverrun implements linux syscall timer_getoverrun(2).
+func TimerGetoverrun(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+	timerID := linux.TimerID(args[0].Value)
+
+	o, err := t.IntervalTimerGetoverrun(timerID)
+	if err != nil {
+		return 0, nil, err
+	}
+	return uintptr(o), nil, nil
+}
+
+// TimerDelete implements linux syscall timer_delete(2).
+func TimerDelete(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+	timerID := linux.TimerID(args[0].Value)
+	return 0, nil, t.IntervalTimerDelete(timerID)
+}
diff --git a/pkg/sentry/syscalls/linux/sys_timerfd.go b/pkg/sentry/syscalls/linux/sys_timerfd.go
index cb81d42b9..92c6a3d60 100644
--- a/pkg/sentry/syscalls/linux/sys_timerfd.go
+++ b/pkg/sentry/syscalls/linux/sys_timerfd.go
@@ -85,28 +85,18 @@ func TimerfdSettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne
 	if _, err := t.CopyIn(newValAddr, &newVal); err != nil {
 		return 0, nil, err
 	}
-	var s ktime.Setting
-	var err error
-	if flags&linux.TFD_TIMER_ABSTIME != 0 {
-		s, err = ktime.SettingFromAbsSpec(ktime.FromTimespec(newVal.Value),
-			newVal.Interval.ToDuration())
-	} else {
-		s, err = ktime.SettingFromSpec(newVal.Value.ToDuration(),
-			newVal.Interval.ToDuration(), tf.Clock())
-	}
+	newS, err := ktime.SettingFromItimerspec(newVal, flags&linux.TFD_TIMER_ABSTIME != 0, tf.Clock())
 	if err != nil {
 		return 0, nil, err
 	}
-	valueNS, intervalNS := ktime.SpecFromSetting(tf.SetTime(s))
-	if oldValAddr == 0 {
-		return 0, nil, nil
-	}
-	oldVal := linux.Itimerspec{
-		Interval: linux.DurationToTimespec(intervalNS),
-		Value:    linux.DurationToTimespec(valueNS),
+	tm, oldS := tf.SetTime(newS)
+	if oldValAddr != 0 {
+		oldVal := ktime.ItimerspecFromSetting(tm, oldS)
+		if _, err := t.CopyOut(oldValAddr, &oldVal); err != nil {
+			return 0, nil, err
+		}
 	}
-	_, err = t.CopyOut(oldValAddr, &oldVal)
-	return 0, nil, err
+	return 0, nil, nil
 }
 
 // TimerfdGettime implements Linux syscall timerfd_gettime(2).
@@ -125,11 +115,8 @@ func TimerfdGettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne
 		return 0, nil, syserror.EINVAL
 	}
 
-	valueNS, intervalNS := ktime.SpecFromSetting(tf.GetTime())
-	curVal := linux.Itimerspec{
-		Interval: linux.DurationToTimespec(intervalNS),
-		Value:    linux.DurationToTimespec(valueNS),
-	}
+	tm, s := tf.GetTime()
+	curVal := ktime.ItimerspecFromSetting(tm, s)
 	_, err := t.CopyOut(curValAddr, &curVal)
 	return 0, nil, err
 }
-- 
cgit v1.2.3