Commit 85d56c30 authored by Ian Lance Taylor's avatar Ian Lance Taylor

runtime: use dispatch semaphores on Darwin

Changes Darwin semaphore support from using pthread mutexes and
condition variables to using dispatch semaphores. Signaling a dispatch
semaphore is async-signal-safe.

Fixes #31264

Change-Id: If0ce47623501db13e3804b14ace5f4d8eaef461e
Reviewed-on: https://go-review.googlesource.com/c/go/+/182258Reviewed-by: default avatarElias Naur <mail@eliasnaur.com>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent f18aeb3a
......@@ -7,10 +7,7 @@ package runtime
import "unsafe"
type mOS struct {
initialized bool
mutex pthreadmutex
cond pthreadcond
count int
sema uintptr
}
func unimplemented(name string) {
......@@ -20,59 +17,32 @@ func unimplemented(name string) {
//go:nosplit
func semacreate(mp *m) {
if mp.initialized {
return
}
mp.initialized = true
if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
throw("pthread_mutex_init")
}
if err := pthread_cond_init(&mp.cond, nil); err != 0 {
throw("pthread_cond_init")
if mp.sema == 0 {
mp.sema = dispatch_semaphore_create(0)
}
}
const (
_DISPATCH_TIME_NOW = uint64(0)
_DISPATCH_TIME_FOREVER = ^uint64(0)
)
//go:nosplit
func semasleep(ns int64) int32 {
var start int64
mp := getg().m
t := _DISPATCH_TIME_FOREVER
if ns >= 0 {
start = nanotime()
t = dispatch_time(_DISPATCH_TIME_NOW, ns)
}
mp := getg().m
pthread_mutex_lock(&mp.mutex)
for {
if mp.count > 0 {
mp.count--
pthread_mutex_unlock(&mp.mutex)
return 0
}
if ns >= 0 {
spent := nanotime() - start
if spent >= ns {
pthread_mutex_unlock(&mp.mutex)
return -1
}
var t timespec
t.setNsec(ns - spent)
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
if err == _ETIMEDOUT {
pthread_mutex_unlock(&mp.mutex)
return -1
}
} else {
pthread_cond_wait(&mp.cond, &mp.mutex)
}
if dispatch_semaphore_wait(mp.sema, t) != 0 {
return -1
}
return 0
}
//go:nosplit
func semawakeup(mp *m) {
pthread_mutex_lock(&mp.mutex)
mp.count++
if mp.count > 0 {
pthread_cond_signal(&mp.cond)
}
pthread_mutex_unlock(&mp.mutex)
dispatch_semaphore_signal(mp.sema)
}
// BSD interface for threading.
......
......@@ -339,52 +339,33 @@ func kevent_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_mutex_init(m *pthreadmutex, attr *pthreadmutexattr) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
}
func pthread_mutex_init_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_mutex_lock(m *pthreadmutex) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
}
func pthread_mutex_lock_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_mutex_unlock(m *pthreadmutex) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
}
func pthread_mutex_unlock_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_cond_init(c *pthreadcond, attr *pthreadcondattr) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
func dispatch_semaphore_create(val int) (sema uintptr) {
libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_create_trampoline)), unsafe.Pointer(&val))
return
}
func pthread_cond_init_trampoline()
func dispatch_semaphore_create_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_cond_wait(c *pthreadcond, m *pthreadmutex) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
func dispatch_semaphore_wait(sema uintptr, t uint64) int32 {
return libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_wait_trampoline)), unsafe.Pointer(&sema))
}
func pthread_cond_wait_trampoline()
func dispatch_semaphore_wait_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_cond_timedwait_relative_np(c *pthreadcond, m *pthreadmutex, t *timespec) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
func dispatch_semaphore_signal(sema uintptr) {
libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_signal_trampoline)), unsafe.Pointer(&sema))
}
func pthread_cond_timedwait_relative_np_trampoline()
func dispatch_semaphore_signal_trampoline()
//go:nosplit
//go:cgo_unsafe_args
func pthread_cond_signal(c *pthreadcond) int32 {
return libcCall(unsafe.Pointer(funcPC(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
func dispatch_time(base uint64, delta int64) (result uint64) {
libcCall(unsafe.Pointer(funcPC(dispatch_time_trampoline)), unsafe.Pointer(&base))
return
}
func pthread_cond_signal_trampoline()
func dispatch_time_trampoline()
// Not used on Darwin, but must be defined.
func exitThread(wait *uint32) {
......@@ -430,13 +411,10 @@ func closeonexec(fd int32) {
//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_mutex_init pthread_mutex_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_mutex_lock pthread_mutex_lock "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_mutex_unlock pthread_mutex_unlock "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_init pthread_cond_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_wait pthread_cond_wait "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_timedwait_relative_np pthread_cond_timedwait_relative_np "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_signal pthread_cond_signal "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_dispatch_semaphore_create dispatch_semaphore_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_dispatch_semaphore_wait dispatch_semaphore_wait "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_dispatch_semaphore_signal dispatch_semaphore_signal "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_dispatch_time dispatch_time "/usr/lib/libSystem.B.dylib"
// Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/link/internal/ld/go.go
......
......@@ -532,96 +532,63 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
POPL BP
RET
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 mutex
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 attr
MOVL AX, 4(SP)
CALL libc_pthread_mutex_init(SB)
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 mutex
MOVL AX, 0(SP)
CALL libc_pthread_mutex_lock(SB)
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 mutex
MOVL 16(SP), BX
MOVL 0(BX), AX // arg 1 value
MOVL AX, 0(SP)
CALL libc_pthread_mutex_unlock(SB)
CALL libc_dispatch_semaphore_create(SB)
MOVL AX, 4(BX) // result sema
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 cond
SUBL $24, SP
MOVL 32(SP), CX
MOVL 0(CX), AX // arg 1 sema
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 attr
MOVL 4(CX), AX // arg 2 timeout/0
MOVL AX, 4(SP)
CALL libc_pthread_cond_init(SB)
MOVL 8(CX), AX // arg 2 timeout/1
MOVL AX, 8(SP)
CALL libc_dispatch_semaphore_wait(SB)
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 cond
MOVL 0(CX), AX // arg 1 sema
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 mutex
MOVL AX, 4(SP)
CALL libc_pthread_cond_wait(SB)
CALL libc_dispatch_semaphore_signal(SB)
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $24, SP
MOVL 32(SP), CX
MOVL 0(CX), AX // arg 1 cond
MOVL 32(SP), BX
MOVL 0(BX), AX // arg 1 base/0
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 mutex
MOVL 4(BX), AX // arg 1 base/1
MOVL AX, 4(SP)
MOVL 8(CX), AX // arg 3 timeout
MOVL 8(BX), AX // arg 2 delta/0
MOVL AX, 8(SP)
CALL libc_pthread_cond_timedwait_relative_np(SB)
MOVL BP, SP
POPL BP
RET
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 cond
MOVL AX, 0(SP)
CALL libc_pthread_cond_signal(SB)
MOVL 12(BX), AX // arg 2 delta/1
MOVL AX, 12(SP)
CALL libc_dispatch_time(SB)
MOVL AX, 16(BX) // result/0
MOVL DX, 20(BX) // result/1
MOVL BP, SP
POPL BP
RET
......
......@@ -482,64 +482,44 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 8(DI), SI // arg 2 attr
MOVQ 0(DI), DI // arg 1 mutex
CALL libc_pthread_mutex_init(SB)
POPQ BP
RET
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 0(DI), DI // arg 1 mutex
CALL libc_pthread_mutex_lock(SB)
POPQ BP
RET
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 0(DI), DI // arg 1 mutex
CALL libc_pthread_mutex_unlock(SB)
POPQ BP
RET
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 8(DI), SI // arg 2 attr
MOVQ 0(DI), DI // arg 1 cond
CALL libc_pthread_cond_init(SB)
MOVQ DI, BX
MOVQ 0(BX), DI // arg 1 value
CALL libc_dispatch_semaphore_create(SB)
MOVQ AX, 8(BX) // result sema
POPQ BP
RET
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 8(DI), SI // arg 2 mutex
MOVQ 0(DI), DI // arg 1 cond
CALL libc_pthread_cond_wait(SB)
MOVQ 8(DI), SI // arg 2 timeout
MOVQ 0(DI), DI // arg 1 sema
CALL libc_dispatch_semaphore_wait(SB)
TESTQ AX, AX // For safety convert 64-bit result to int32 0 or 1.
JEQ 2(PC)
MOVL $1, AX
POPQ BP
RET
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 8(DI), SI // arg 2 mutex
MOVQ 16(DI), DX // arg 3 timeout
MOVQ 0(DI), DI // arg 1 cond
CALL libc_pthread_cond_timedwait_relative_np(SB)
MOVQ 0(DI), DI // arg 1 sema
CALL libc_dispatch_semaphore_signal(SB)
POPQ BP
RET
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ 0(DI), DI // arg 1 cond
CALL libc_pthread_cond_signal(SB)
MOVQ DI, BX
MOVQ 0(BX), DI // arg 1 base
MOVQ 8(BX), SI // arg 2 delta
CALL libc_dispatch_time(SB)
MOVQ AX, 16(BX)
POPQ BP
RET
......
......@@ -343,44 +343,34 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
BL libc_raise(SB)
RET
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 attr
MOVW 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_init(SB)
RET
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_lock(SB)
RET
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_unlock(SB)
RET
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 attr
MOVW 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_init(SB)
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
MOVW R0, R8
MOVW 0(R8), R0 // arg 1 value
BL libc_dispatch_semaphore_create(SB)
MOVW R0, 4(R8) // result sema
RET
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 mutex
MOVW 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_wait(SB)
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 timeout/0
MOVW 8(R0), R2 // arg 2 timeout/1
MOVW 0(R0), R0 // arg 1 sema
BL libc_dispatch_semaphore_wait(SB)
RET
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 mutex
MOVW 8(R0), R2 // arg 3 timeout
MOVW 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_timedwait_relative_np(SB)
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 sema
BL libc_dispatch_semaphore_signal(SB)
RET
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_signal(SB)
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
MOVW R0, R8
MOVW 0(R8), R0 // arg 1 base/0
MOVW 4(R8), R1 // arg 1 base/1
MOVW 8(R8), R2 // arg 2 delta/0
MOVW 12(R8), R3 // arg 2 delta/1
BL libc_dispatch_time(SB)
MOVW R0, 16(R8) // result/0
MOVW R1, 20(R8) // result/1
RET
// syscall calls a function in libc on behalf of the syscall package.
......
......@@ -409,44 +409,33 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
BL libc_raise(SB)
RET
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 attr
MOVD 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_init(SB)
RET
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_lock(SB)
RET
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 mutex
BL libc_pthread_mutex_unlock(SB)
RET
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 attr
MOVD 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_init(SB)
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
MOVD R0, R19
MOVD 0(R19), R0 // arg 1 value
BL libc_dispatch_semaphore_create(SB)
MOVD R0, 8(R19) // result sema
RET
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 mutex
MOVD 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_wait(SB)
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 timeout
MOVD 0(R0), R0 // arg 1 sema
BL libc_dispatch_semaphore_wait(SB)
CMP $0, R0 // For safety convert 64-bit result to int32 0 or 1.
BEQ 2(PC)
MOVW $1, R0
RET
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 mutex
MOVD 16(R0), R2 // arg 3 timeout
MOVD 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_timedwait_relative_np(SB)
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 sema
BL libc_dispatch_semaphore_signal(SB)
RET
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 cond
BL libc_pthread_cond_signal(SB)
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
MOVD R0, R19
MOVD 0(R19), R0 // arg 1 base
MOVD 8(R19), R1 // arg 2 delta
BL libc_dispatch_time(SB)
MOVD R0, 16(R19) // result
RET
// syscall calls a function in libc on behalf of the syscall package.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment