From 1f5687305801d4db70d30c51ccc82bf644f9e4d6 Mon Sep 17 00:00:00 2001 From: Maxim Pugachev Date: Wed, 29 Apr 2020 19:47:37 +0200 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Tobias Klauser --- unix/linux/types.go | 3 ++ unix/mkerrors.sh | 3 +- unix/syscall_linux.go | 4 ++- unix/syscall_linux_test.go | 51 ++++++++++++++++++++++++++++++++++ unix/zerrors_linux.go | 2 ++ unix/zerrors_linux_386.go | 2 ++ unix/zerrors_linux_amd64.go | 2 ++ unix/zerrors_linux_arm.go | 2 ++ unix/zerrors_linux_arm64.go | 2 ++ unix/zerrors_linux_mips.go | 2 ++ unix/zerrors_linux_mips64.go | 2 ++ unix/zerrors_linux_mips64le.go | 2 ++ unix/zerrors_linux_mipsle.go | 2 ++ unix/zerrors_linux_ppc64.go | 2 ++ unix/zerrors_linux_ppc64le.go | 2 ++ unix/zerrors_linux_riscv64.go | 2 ++ unix/zerrors_linux_s390x.go | 2 ++ unix/zerrors_linux_sparc64.go | 2 ++ unix/zsyscall_linux.go | 31 +++++++++++++++++++++ unix/ztypes_linux.go | 5 ++++ 20 files changed, 123 insertions(+), 2 deletions(-) diff --git a/unix/linux/types.go b/unix/linux/types.go index 50466d2c..d72e7ad2 100644 --- a/unix/linux/types.go +++ b/unix/linux/types.go @@ -46,6 +46,7 @@ package unix #include #include #include +#include #include #include #include @@ -410,6 +411,8 @@ type Timeval C.struct_timeval 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 ab09aafc..780e387e 100755 --- a/unix/mkerrors.sh +++ b/unix/mkerrors.sh @@ -187,6 +187,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -480,7 +481,7 @@ ccflags="$@" $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 bbe1abbc..4326a811 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -1757,6 +1757,9 @@ func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) { //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 @@ func Klogset(typ int, arg int) (err error) { // TimerGetoverrun // TimerGettime // TimerSettime -// Timerfd // Tkill (obsolete) // Tuxcall // Umount2 diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index e572376f..a8221d31 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -19,6 +19,7 @@ import ( "strings" "testing" "time" + "unsafe" "golang.org/x/sys/unix" ) @@ -663,3 +664,53 @@ func TestPrctlRetInt(t *testing.T) { 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 21973940..6e3cfec4 100644 --- a/unix/zerrors_linux.go +++ b/unix/zerrors_linux.go @@ -2165,6 +2165,8 @@ const ( 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 028c9d87..5e974110 100644 --- a/unix/zerrors_linux_386.go +++ b/unix/zerrors_linux_386.go @@ -342,6 +342,8 @@ const ( 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 005970f7..47a57fe4 100644 --- a/unix/zerrors_linux_amd64.go +++ b/unix/zerrors_linux_amd64.go @@ -343,6 +343,8 @@ const ( 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 0541f36e..df2eea4b 100644 --- a/unix/zerrors_linux_arm.go +++ b/unix/zerrors_linux_arm.go @@ -349,6 +349,8 @@ const ( 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 9ee8d1bc..4e121421 100644 --- a/unix/zerrors_linux_arm64.go +++ b/unix/zerrors_linux_arm64.go @@ -336,6 +336,8 @@ const ( 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 4826bd70..a23b0802 100644 --- a/unix/zerrors_linux_mips.go +++ b/unix/zerrors_linux_mips.go @@ -339,6 +339,8 @@ const ( 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 2346dc55..a5a921e4 100644 --- a/unix/zerrors_linux_mips64.go +++ b/unix/zerrors_linux_mips64.go @@ -339,6 +339,8 @@ const ( 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 e758b61e..d088e197 100644 --- a/unix/zerrors_linux_mips64le.go +++ b/unix/zerrors_linux_mips64le.go @@ -339,6 +339,8 @@ const ( 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 2dfe6bba..0ddf9d5f 100644 --- a/unix/zerrors_linux_mipsle.go +++ b/unix/zerrors_linux_mipsle.go @@ -339,6 +339,8 @@ const ( 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 51858667..a93ffc18 100644 --- a/unix/zerrors_linux_ppc64.go +++ b/unix/zerrors_linux_ppc64.go @@ -393,6 +393,8 @@ const ( 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 4231b20b..c1ea48b9 100644 --- a/unix/zerrors_linux_ppc64le.go +++ b/unix/zerrors_linux_ppc64le.go @@ -393,6 +393,8 @@ const ( 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 6a0b2d29..7def950b 100644 --- a/unix/zerrors_linux_riscv64.go +++ b/unix/zerrors_linux_riscv64.go @@ -330,6 +330,8 @@ const ( 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 95e950fc..d39293c8 100644 --- a/unix/zerrors_linux_s390x.go +++ b/unix/zerrors_linux_s390x.go @@ -403,6 +403,8 @@ const ( 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 079762fa..3ff3ec68 100644 --- a/unix/zerrors_linux_sparc64.go +++ b/unix/zerrors_linux_sparc64.go @@ -392,6 +392,8 @@ const ( 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 fd2dae8e..df217825 100644 --- a/unix/zsyscall_linux.go +++ b/unix/zsyscall_linux.go @@ -1450,6 +1450,37 @@ func Sysinfo(info *Sysinfo_t) (err error) { // 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 af5ab455..416f7767 100644 --- a/unix/ztypes_linux.go +++ b/unix/ztypes_linux.go @@ -18,6 +18,11 @@ type ( _C_long_long int64 ) +type ItimerSpec struct { + Interval Timespec + Value Timespec +} + const ( TIME_OK = 0x0 TIME_INS = 0x1