Linux introduced new syscalls to fix the year 2038 issue.
To still be able to use the old ones, the Kconfig option
COMPAT_32BIT_TIME would be necessary.
Use the new 64-bit syscall for timer_settime by default.
Add a fallback to use the 32-bit syscall when the
64-bit version returns _ENOSYS.
Fixes #75133
Change-Id: Iccb8831b67f665067ee526e93c3ff2f4f5392edf
GitHub-Last-Rev:
6c3d62d60e5ff02ebe61e56e06d6365e530ec39e
GitHub-Pull-Request: golang/go#75957
Reviewed-on: https://go-review.googlesource.com/c/go/+/712642
Reviewed-by: Jorropo <jorropo.pgm@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Jorropo <jorropo.pgm@gmail.com>
uc_sigmask uint32
}
-type itimerspec struct {
+type itimerspec32 struct {
it_interval timespec32
it_value timespec32
}
+type itimerspec struct {
+ it_interval timespec
+ it_value timespec
+}
type itimerval struct {
it_interval timeval
tv.tv_usec = x
}
-type itimerspec struct {
+type itimerspec32 struct {
it_interval timespec32
it_value timespec32
}
+type itimerspec struct {
+ it_interval timespec
+ it_value timespec
+}
+
type itimerval struct {
it_interval timeval
it_value timeval
_ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
}
-type itimerspec struct {
+type itimerspec32 struct {
it_interval timespec32
it_value timespec32
}
+type itimerspec struct {
+ it_interval timespec
+ it_value timespec
+}
+
type itimerval struct {
it_interval timeval
it_value timeval
//go:noescape
func timer_create(clockid int32, sevp *sigevent, timerid *int32) int32
-//go:noescape
-func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32
-
//go:noescape
func timer_delete(timerid int32) int32
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && (386 || arm || mips || mipsle)
+
+package runtime
+
+import "internal/runtime/atomic"
+
+var timer32bitOnly atomic.Bool
+
+//go:noescape
+func timer_settime32(timerid int32, flags int32, new, old *itimerspec32) int32
+
+//go:noescape
+func timer_settime64(timerid int32, flags int32, new, old *itimerspec) int32
+
+//go:nosplit
+func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32 {
+ if !timer32bitOnly.Load() {
+ ret := timer_settime64(timerid, flags, new, old)
+ // timer_settime64 is only supported on Linux 5.0+
+ if ret != -_ENOSYS {
+ return ret
+ }
+ timer32bitOnly.Store(true)
+ }
+
+ var newts,oldts itimerspec32
+ var new32,old32 *itimerspec32
+
+ if new != nil {
+ newts.it_interval.setNsec(new.it_interval.tv_sec*1e9 + new.it_interval.tv_nsec)
+ newts.it_value.setNsec(new.it_value.tv_sec*1e9 + new.it_value.tv_nsec)
+ new32 = &newts
+ }
+
+ if old != nil {
+ oldts.it_interval.setNsec(old.it_interval.tv_sec*1e9 + old.it_interval.tv_nsec)
+ oldts.it_value.setNsec(old.it_value.tv_sec*1e9 + old.it_value.tv_nsec)
+ old32 = &oldts
+ }
+
+ // Fall back to 32-bit timer
+ return timer_settime32(timerid, flags, new32, old32)
+}
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && !(386 || arm || mips || mipsle)
+
+package runtime
+
+//go:noescape
+func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32
#define SYS_exit_group 252
#define SYS_timer_create 259
#define SYS_timer_settime 260
+#define SYS_timer_settime64 409
#define SYS_timer_delete 263
#define SYS_clock_gettime 265
#define SYS_tgkill 270
MOVL AX, ret+12(FP)
RET
-TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+// Linux: kernel/time/posix-timer.c, requiring COMPAT_32BIT_TIME
+TEXT runtime·timer_settime32(SB),NOSPLIT,$0-20
MOVL $SYS_timer_settime, AX
MOVL timerid+0(FP), BX
MOVL flags+4(FP), CX
MOVL AX, ret+16(FP)
RET
+TEXT runtime·timer_settime64(SB),NOSPLIT,$0-20
+ MOVL $SYS_timer_settime64, AX
+ MOVL timerid+0(FP), BX
+ MOVL flags+4(FP), CX
+ MOVL new+8(FP), DX
+ MOVL old+12(FP), SI
+ INVOKE_SYSCALL
+ MOVL AX, ret+16(FP)
+ RET
+
TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
MOVL $SYS_timer_delete, AX
MOVL timerid+0(FP), BX
#define SYS_clock_gettime (SYS_BASE + 263)
#define SYS_timer_create (SYS_BASE + 257)
#define SYS_timer_settime (SYS_BASE + 258)
+#define SYS_timer_settime64 (SYS_BASE + 409)
#define SYS_timer_delete (SYS_BASE + 261)
#define SYS_pipe2 (SYS_BASE + 359)
#define SYS_access (SYS_BASE + 33)
SWI $0
MOVW R0, ret+12(FP)
RET
-
-TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+// Linux: kernel/time/posix-timer.c, requiring COMPAT_32BIT_TIME.
+TEXT runtime·timer_settime32(SB),NOSPLIT,$0-20
MOVW timerid+0(FP), R0
MOVW flags+4(FP), R1
MOVW new+8(FP), R2
MOVW R0, ret+16(FP)
RET
+TEXT runtime·timer_settime64(SB),NOSPLIT,$0-20
+ MOVW timerid+0(FP), R0
+ MOVW flags+4(FP), R1
+ MOVW new+8(FP), R2
+ MOVW old+12(FP), R3
+ MOVW $SYS_timer_settime64, R7
+ SWI $0
+ MOVW R0, ret+16(FP)
+ RET
+
TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
MOVW timerid+0(FP), R0
MOVW $SYS_timer_delete, R7
#define SYS_exit_group 4246
#define SYS_timer_create 4257
#define SYS_timer_settime 4258
+#define SYS_timer_settime64 4409
#define SYS_timer_delete 4261
#define SYS_clock_gettime 4263
#define SYS_tgkill 4266
MOVW R2, ret+12(FP)
RET
-TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+// Linux: kernel/time/posix-timer.c, requiring COMPAT_32BIT_TIME
+TEXT runtime·timer_settime32(SB),NOSPLIT,$0-20
MOVW timerid+0(FP), R4
MOVW flags+4(FP), R5
MOVW new+8(FP), R6
MOVW R2, ret+16(FP)
RET
+TEXT runtime·timer_settime64(SB),NOSPLIT,$0-20
+ MOVW timerid+0(FP), R4
+ MOVW flags+4(FP), R5
+ MOVW new+8(FP), R6
+ MOVW old+12(FP), R7
+ MOVW $SYS_timer_settime64, R2
+ SYSCALL
+ MOVW R2, ret+16(FP)
+ RET
+
TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
MOVW timerid+0(FP), R4
MOVW $SYS_timer_delete, R2