unix: add support for timerfd syscalls on Linux
timerfd_create, timerfd_gettime and timerfd_settime syscalls have been added.
Fixes golang/go#38733
Change-Id: I306d68103b6efb2515c74f384646210c4b68f66e
Reviewed-on: https://go-review.googlesource.com/c/sys/+/230798
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/linux/types.go b/unix/linux/types.go
index 50466d2..d72e7ad 100644
--- a/unix/linux/types.go
+++ b/unix/linux/types.go
@@ -46,6 +46,7 @@
#include <sys/statvfs.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
+#include <sys/timerfd.h>
#include <sys/times.h>
#include <sys/timex.h>
#include <sys/un.h>
@@ -410,6 +411,8 @@
type Timex C.struct_timex
+type ItimerSpec C.struct_itimerspec
+
const (
TIME_OK = C.TIME_OK
TIME_INS = C.TIME_INS
diff --git a/unix/mkerrors.sh b/unix/mkerrors.sh
index ab09aaf..780e387 100755
--- a/unix/mkerrors.sh
+++ b/unix/mkerrors.sh
@@ -187,6 +187,7 @@
#include <sys/select.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
+#include <sys/timerfd.h>
#include <sys/uio.h>
#include <sys/xattr.h>
#include <linux/bpf.h>
@@ -480,7 +481,7 @@
$2 ~ /^(MS|MNT|UMOUNT)_/ ||
$2 ~ /^NS_GET_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
- $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ ||
+ $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ ||
$2 ~ /^KEXEC_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index bbe1abb..4326a81 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -1757,6 +1757,9 @@
//sys Syncfs(fd int) (err error)
//sysnb Sysinfo(info *Sysinfo_t) (err error)
//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
+//sysnb TimerfdCreate(clockid int, flags int) (fd int, err error)
+//sysnb TimerfdGettime(fd int, currValue *ItimerSpec) (err error)
+//sysnb TimerfdSettime(fd int, flags int, newValue *ItimerSpec, oldValue *ItimerSpec) (err error)
//sysnb Tgkill(tgid int, tid int, sig syscall.Signal) (err error)
//sysnb Times(tms *Tms) (ticks uintptr, err error)
//sysnb Umask(mask int) (oldmask int)
@@ -2178,7 +2181,6 @@
// TimerGetoverrun
// TimerGettime
// TimerSettime
-// Timerfd
// Tkill (obsolete)
// Tuxcall
// Umount2
diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go
index e572376..a8221d3 100644
--- a/unix/syscall_linux_test.go
+++ b/unix/syscall_linux_test.go
@@ -19,6 +19,7 @@
"strings"
"testing"
"time"
+ "unsafe"
"golang.org/x/sys/unix"
)
@@ -663,3 +664,53 @@
t.Fatalf("unexpected return from prctl; got %v, expected %v", v, 1)
}
}
+
+func TestTimerfd(t *testing.T) {
+ var now unix.Timespec
+ if err := unix.ClockGettime(unix.CLOCK_REALTIME, &now); err != nil {
+ t.Fatalf("ClockGettime: %v", err)
+ }
+
+ tfd, err := unix.TimerfdCreate(unix.CLOCK_REALTIME, 0)
+ if err == unix.ENOSYS {
+ t.Skip("timerfd_create system call not implemented")
+ } else if err != nil {
+ t.Fatalf("TimerfdCreate: %v", err)
+ }
+ defer unix.Close(tfd)
+
+ var timeSpec unix.ItimerSpec
+ if err := unix.TimerfdGettime(tfd, &timeSpec); err != nil {
+ t.Fatalf("TimerfdGettime: %v", err)
+ }
+
+ if timeSpec.Value.Nsec != 0 || timeSpec.Value.Sec != 0 {
+ t.Fatalf("TimerfdGettime: timer is already set, but shouldn't be")
+ }
+
+ timeSpec = unix.ItimerSpec{
+ Interval: unix.NsecToTimespec(int64(time.Millisecond)),
+ Value: now,
+ }
+
+ if err := unix.TimerfdSettime(tfd, unix.TFD_TIMER_ABSTIME, &timeSpec, nil); err != nil {
+ t.Fatalf("TimerfdSettime: %v", err)
+ }
+
+ const totalTicks = 10
+ const bufferLength = 8
+
+ buffer := make([]byte, bufferLength)
+
+ var count uint64 = 0
+ for count < totalTicks {
+ n, err := unix.Read(tfd, buffer)
+ if err != nil {
+ t.Fatalf("Timerfd: %v", err)
+ } else if n != bufferLength {
+ t.Fatalf("Timerfd: got %d bytes from timerfd, expected %d bytes", n, bufferLength)
+ }
+
+ count += *(*uint64)(unsafe.Pointer(&buffer))
+ }
+}
diff --git a/unix/zerrors_linux.go b/unix/zerrors_linux.go
index 2197394..6e3cfec 100644
--- a/unix/zerrors_linux.go
+++ b/unix/zerrors_linux.go
@@ -2165,6 +2165,8 @@
TCP_USER_TIMEOUT = 0x12
TCP_WINDOW_CLAMP = 0xa
TCP_ZEROCOPY_RECEIVE = 0x23
+ TFD_TIMER_ABSTIME = 0x1
+ TFD_TIMER_CANCEL_ON_SET = 0x2
TIMER_ABSTIME = 0x1
TIOCM_DTR = 0x2
TIOCM_LE = 0x1
diff --git a/unix/zerrors_linux_386.go b/unix/zerrors_linux_386.go
index 028c9d8..5e97411 100644
--- a/unix/zerrors_linux_386.go
+++ b/unix/zerrors_linux_386.go
@@ -342,6 +342,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_amd64.go b/unix/zerrors_linux_amd64.go
index 005970f..47a57fe 100644
--- a/unix/zerrors_linux_amd64.go
+++ b/unix/zerrors_linux_amd64.go
@@ -343,6 +343,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_arm.go b/unix/zerrors_linux_arm.go
index 0541f36..df2eea4 100644
--- a/unix/zerrors_linux_arm.go
+++ b/unix/zerrors_linux_arm.go
@@ -349,6 +349,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_arm64.go b/unix/zerrors_linux_arm64.go
index 9ee8d1b..4e12142 100644
--- a/unix/zerrors_linux_arm64.go
+++ b/unix/zerrors_linux_arm64.go
@@ -336,6 +336,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_mips.go b/unix/zerrors_linux_mips.go
index 4826bd7..a23b080 100644
--- a/unix/zerrors_linux_mips.go
+++ b/unix/zerrors_linux_mips.go
@@ -339,6 +339,8 @@
TCSETSW = 0x540f
TCSETSW2 = 0x8030542c
TCXONC = 0x5406
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x80
TIOCCBRK = 0x5428
TIOCCONS = 0x80047478
TIOCEXCL = 0x740d
diff --git a/unix/zerrors_linux_mips64.go b/unix/zerrors_linux_mips64.go
index 2346dc5..a5a921e 100644
--- a/unix/zerrors_linux_mips64.go
+++ b/unix/zerrors_linux_mips64.go
@@ -339,6 +339,8 @@
TCSETSW = 0x540f
TCSETSW2 = 0x8030542c
TCXONC = 0x5406
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x80
TIOCCBRK = 0x5428
TIOCCONS = 0x80047478
TIOCEXCL = 0x740d
diff --git a/unix/zerrors_linux_mips64le.go b/unix/zerrors_linux_mips64le.go
index e758b61..d088e19 100644
--- a/unix/zerrors_linux_mips64le.go
+++ b/unix/zerrors_linux_mips64le.go
@@ -339,6 +339,8 @@
TCSETSW = 0x540f
TCSETSW2 = 0x8030542c
TCXONC = 0x5406
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x80
TIOCCBRK = 0x5428
TIOCCONS = 0x80047478
TIOCEXCL = 0x740d
diff --git a/unix/zerrors_linux_mipsle.go b/unix/zerrors_linux_mipsle.go
index 2dfe6bb..0ddf9d5 100644
--- a/unix/zerrors_linux_mipsle.go
+++ b/unix/zerrors_linux_mipsle.go
@@ -339,6 +339,8 @@
TCSETSW = 0x540f
TCSETSW2 = 0x8030542c
TCXONC = 0x5406
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x80
TIOCCBRK = 0x5428
TIOCCONS = 0x80047478
TIOCEXCL = 0x740d
diff --git a/unix/zerrors_linux_ppc64.go b/unix/zerrors_linux_ppc64.go
index 5185866..a93ffc1 100644
--- a/unix/zerrors_linux_ppc64.go
+++ b/unix/zerrors_linux_ppc64.go
@@ -393,6 +393,8 @@
TCSETSF = 0x802c7416
TCSETSW = 0x802c7415
TCXONC = 0x2000741e
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_ppc64le.go b/unix/zerrors_linux_ppc64le.go
index 4231b20..c1ea48b 100644
--- a/unix/zerrors_linux_ppc64le.go
+++ b/unix/zerrors_linux_ppc64le.go
@@ -393,6 +393,8 @@
TCSETSF = 0x802c7416
TCSETSW = 0x802c7415
TCXONC = 0x2000741e
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_riscv64.go b/unix/zerrors_linux_riscv64.go
index 6a0b2d2..7def950 100644
--- a/unix/zerrors_linux_riscv64.go
+++ b/unix/zerrors_linux_riscv64.go
@@ -330,6 +330,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_s390x.go b/unix/zerrors_linux_s390x.go
index 95e950f..d39293c 100644
--- a/unix/zerrors_linux_s390x.go
+++ b/unix/zerrors_linux_s390x.go
@@ -403,6 +403,8 @@
TCSETXF = 0x5434
TCSETXW = 0x5435
TCXONC = 0x540a
+ TFD_CLOEXEC = 0x80000
+ TFD_NONBLOCK = 0x800
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
diff --git a/unix/zerrors_linux_sparc64.go b/unix/zerrors_linux_sparc64.go
index 079762f..3ff3ec6 100644
--- a/unix/zerrors_linux_sparc64.go
+++ b/unix/zerrors_linux_sparc64.go
@@ -392,6 +392,8 @@
TCSETSW = 0x8024540a
TCSETSW2 = 0x802c540e
TCXONC = 0x20005406
+ TFD_CLOEXEC = 0x400000
+ TFD_NONBLOCK = 0x4000
TIOCCBRK = 0x2000747a
TIOCCONS = 0x20007424
TIOCEXCL = 0x2000740d
diff --git a/unix/zsyscall_linux.go b/unix/zsyscall_linux.go
index fd2dae8..df21782 100644
--- a/unix/zsyscall_linux.go
+++ b/unix/zsyscall_linux.go
@@ -1450,6 +1450,37 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func TimerfdCreate(clockid int, flags int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIMERFD_CREATE, uintptr(clockid), uintptr(flags), 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func TimerfdGettime(fd int, currValue *ItimerSpec) (err error) {
+ _, _, e1 := RawSyscall(SYS_TIMERFD_GETTIME, uintptr(fd), uintptr(unsafe.Pointer(currValue)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func TimerfdSettime(fd int, flags int, newValue *ItimerSpec, oldValue *ItimerSpec) (err error) {
+ _, _, e1 := RawSyscall6(SYS_TIMERFD_SETTIME, uintptr(fd), uintptr(flags), uintptr(unsafe.Pointer(newValue)), uintptr(unsafe.Pointer(oldValue)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
if e1 != 0 {
diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go
index af5ab45..416f776 100644
--- a/unix/ztypes_linux.go
+++ b/unix/ztypes_linux.go
@@ -18,6 +18,11 @@
_C_long_long int64
)
+type ItimerSpec struct {
+ Interval Timespec
+ Value Timespec
+}
+
const (
TIME_OK = 0x0
TIME_INS = 0x1