Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/runtime/defs2_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
EINTR = C.EINTR
EAGAIN = C.EAGAIN
ENOMEM = C.ENOMEM
ENOSYS = C.ENOSYS

PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
EINTR = C.EINTR
EAGAIN = C.EAGAIN
ENOMEM = C.ENOMEM
ENOSYS = C.ENOSYS

PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
Expand Down
23 changes: 19 additions & 4 deletions src/runtime/defs_linux_386.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down Expand Up @@ -136,16 +137,30 @@ type fpstate struct {
anon0 [48]byte
}

type timespec struct {
// The timespec structs and types are defined in Linux in
// include/uapi/linux/time_types.h and include/uapi/asm-generic/posix_types.h.
type timespec32 struct {
tv_sec int32
tv_nsec int32
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
func (ts *timespec32) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}

type timespec struct {
tv_sec int64
tv_nsec int64
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
var newNS int32
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
ts.tv_nsec = int64(newNS)
}

type timeval struct {
tv_sec int32
tv_usec int32
Expand Down Expand Up @@ -223,8 +238,8 @@ type ucontext struct {
}

type itimerspec struct {
it_interval timespec
it_value timespec
it_interval timespec32
it_value timespec32
}

type itimerval struct {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
23 changes: 19 additions & 4 deletions src/runtime/defs_linux_arm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
_EINTR = 0x4
_ENOMEM = 0xc
_EAGAIN = 0xb
_ENOSYS = 0x26

_PROT_NONE = 0
_PROT_READ = 0x1
Expand Down Expand Up @@ -95,16 +96,30 @@ const (
_SOCK_DGRAM = 0x2
)

type timespec struct {
// The timespec structs and types are defined in Linux in
// include/uapi/linux/time_types.h and include/uapi/asm-generic/posix_types.h.
type timespec32 struct {
tv_sec int32
tv_nsec int32
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
func (ts *timespec32) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}

type timespec struct {
tv_sec int64
tv_nsec int64
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
var newNS int32
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
ts.tv_nsec = int64(newNS)
}

type stackt struct {
ss_sp *byte
ss_flags int32
Expand Down Expand Up @@ -155,8 +170,8 @@ func (tv *timeval) set_usec(x int32) {
}

type itimerspec struct {
it_interval timespec
it_value timespec
it_interval timespec32
it_value timespec32
}

type itimerval struct {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_loong64.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_mips64x.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
23 changes: 19 additions & 4 deletions src/runtime/defs_linux_mipsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down Expand Up @@ -93,16 +94,30 @@ const (
_SIGEV_THREAD_ID = 0x4
)

type timespec struct {
// The timespec structs and types are defined in Linux in
// include/uapi/linux/time_types.h and include/uapi/asm-generic/posix_types.h.
type timespec32 struct {
tv_sec int32
tv_nsec int32
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
func (ts *timespec32) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}

type timespec struct {
tv_sec int64
tv_nsec int64
}

//go:nosplit
func (ts *timespec) setNsec(ns int64) {
var newNS int32
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
ts.tv_nsec = int64(newNS)
}

type timeval struct {
tv_sec int32
tv_usec int32
Expand Down Expand Up @@ -138,8 +153,8 @@ type siginfo struct {
}

type itimerspec struct {
it_interval timespec
it_value timespec
it_interval timespec32
it_value timespec32
}

type itimerval struct {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_ppc64.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_ppc64le.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_riscv64.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
1 change: 1 addition & 0 deletions src/runtime/defs_linux_s390x.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_ENOSYS = 0x26

_PROT_NONE = 0x0
_PROT_READ = 0x1
Expand Down
5 changes: 1 addition & 4 deletions src/runtime/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ type mOS struct {
waitsema uint32 // semaphore for parking on locks
}

//go:noescape
func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32

// Linux futex.
//
// futexsleep(uint32 *addr, uint32 val)
Expand Down Expand Up @@ -79,7 +76,7 @@ func futexsleep(addr *uint32, val uint32, ns int64) {

var ts timespec
ts.setNsec(ns)
futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, unsafe.Pointer(&ts), nil, 0)
futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, &ts, nil, 0)
}

// If any procs are sleeping on addr, wake up at most cnt.
Expand Down
40 changes: 40 additions & 0 deletions src/runtime/os_linux_futex32.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 || ppc)

package runtime

import (
"internal/runtime/atomic"
"unsafe"
)

//go:noescape
func futex_time32(addr unsafe.Pointer, op int32, val uint32, ts *timespec32, addr2 unsafe.Pointer, val3 uint32) int32

//go:noescape
func futex_time64(addr unsafe.Pointer, op int32, val uint32, ts *timespec, addr2 unsafe.Pointer, val3 uint32) int32

var is32bitOnly atomic.Bool

//go:nosplit
func futex(addr unsafe.Pointer, op int32, val uint32, ts *timespec, addr2 unsafe.Pointer, val3 uint32) int32 {
if !is32bitOnly.Load() {
ret := futex_time64(addr, op, val, ts, addr2, val3)
// futex_time64 is only supported on Linux 5.0+
if ret != -_ENOSYS {
return ret
}
is32bitOnly.Store(true)
}
// Downgrade ts.
var ts32 timespec32
var pts32 *timespec32
if ts != nil {
ts32.setNsec(ts.tv_sec*1e9 + ts.tv_nsec)
pts32 = &ts32
}
return futex_time32(addr, op, val, pts32, addr2, val3)
}
14 changes: 14 additions & 0 deletions src/runtime/os_linux_futex64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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 || ppc || s390)

package runtime

import (
"unsafe"
)

//go:noescape
func futex(addr unsafe.Pointer, op int32, val uint32, ts *timespec, addr2 unsafe.Pointer, val3 uint32) int32
21 changes: 19 additions & 2 deletions src/runtime/sys_linux_386.s
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#define SYS_madvise 219
#define SYS_gettid 224
#define SYS_futex 240
#define SYS_futex_time64 422
#define SYS_sched_getaffinity 242
#define SYS_set_thread_area 243
#define SYS_exit_group 252
Expand Down Expand Up @@ -532,9 +533,10 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
MOVL AX, ret+12(FP)
RET

// Linux: kernel/futex/syscalls.c, requiring COMPAT_32BIT_TIME
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex(SB),NOSPLIT,$0
// struct old_timespec32 *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex_time32(SB),NOSPLIT,$0
MOVL $SYS_futex, AX
MOVL addr+0(FP), BX
MOVL op+4(FP), CX
Expand All @@ -546,6 +548,21 @@ TEXT runtime·futex(SB),NOSPLIT,$0
MOVL AX, ret+24(FP)
RET

// Linux: kernel/futex/syscalls.c
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex_time64(SB),NOSPLIT,$0
MOVL $SYS_futex_time64, AX
MOVL addr+0(FP), BX
MOVL op+4(FP), CX
MOVL val+8(FP), DX
MOVL ts+12(FP), SI
MOVL addr2+16(FP), DI
MOVL val3+20(FP), BP
INVOKE_SYSCALL
MOVL AX, ret+24(FP)
RET

// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0
MOVL $SYS_clone, AX
Expand Down
21 changes: 19 additions & 2 deletions src/runtime/sys_linux_arm.s
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#define SYS_sigaltstack (SYS_BASE + 186)
#define SYS_mmap2 (SYS_BASE + 192)
#define SYS_futex (SYS_BASE + 240)
#define SYS_futex_time64 (SYS_BASE + 422)
#define SYS_exit_group (SYS_BASE + 248)
#define SYS_munmap (SYS_BASE + 91)
#define SYS_madvise (SYS_BASE + 220)
Expand Down Expand Up @@ -403,9 +404,10 @@ finish:

RET

// Linux: kernel/futex/syscalls.c, requiring COMPAT_32BIT_TIME
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex(SB),NOSPLIT,$0
// struct old_timespec32 *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex_time32(SB),NOSPLIT,$0
MOVW addr+0(FP), R0
MOVW op+4(FP), R1
MOVW val+8(FP), R2
Expand All @@ -417,6 +419,21 @@ TEXT runtime·futex(SB),NOSPLIT,$0
MOVW R0, ret+24(FP)
RET

// Linux: kernel/futex/syscalls.c
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex_time64(SB),NOSPLIT,$0
MOVW addr+0(FP), R0
MOVW op+4(FP), R1
MOVW val+8(FP), R2
MOVW ts+12(FP), R3
MOVW addr2+16(FP), R4
MOVW val3+20(FP), R5
MOVW $SYS_futex_time64, R7
SWI $0
MOVW R0, ret+24(FP)
RET

// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0
MOVW flags+0(FP), R0
Expand Down
Loading