From: Ian Lance Taylor Date: Thu, 13 Jun 2019 19:49:03 +0000 (-0700) Subject: runtime: use dispatch semaphores on Darwin X-Git-Tag: go1.13beta1~70 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=85d56c3096636cebd6e0aea846d78599edbbb9e2;p=gostls13.git 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/+/182258 Reviewed-by: Elias Naur Reviewed-by: Keith Randall --- diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 819aaaca70..4b6dbf6427 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -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. diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index b50d441d92..2aaa0f8546 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -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 diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index 9a0b3607c2..0c54d13b02 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -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 diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index bbe6bc14bf..95ba496cbc 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -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 diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s index 82470bc4df..bb0832f3af 100644 --- a/src/runtime/sys_darwin_arm.s +++ b/src/runtime/sys_darwin_arm.s @@ -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. diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index af03af37bb..4c81b99336 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -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.