Skip to content

Commit 85d56c3

Browse files
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 <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent f18aeb3 commit 85d56c3

File tree

6 files changed

+123
-249
lines changed

6 files changed

+123
-249
lines changed

src/runtime/os_darwin.go

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ package runtime
77
import "unsafe"
88

99
type mOS struct {
10-
initialized bool
11-
mutex pthreadmutex
12-
cond pthreadcond
13-
count int
10+
sema uintptr
1411
}
1512

1613
func unimplemented(name string) {
@@ -20,59 +17,32 @@ func unimplemented(name string) {
2017

2118
//go:nosplit
2219
func semacreate(mp *m) {
23-
if mp.initialized {
24-
return
25-
}
26-
mp.initialized = true
27-
if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
28-
throw("pthread_mutex_init")
29-
}
30-
if err := pthread_cond_init(&mp.cond, nil); err != 0 {
31-
throw("pthread_cond_init")
20+
if mp.sema == 0 {
21+
mp.sema = dispatch_semaphore_create(0)
3222
}
3323
}
3424

25+
const (
26+
_DISPATCH_TIME_NOW = uint64(0)
27+
_DISPATCH_TIME_FOREVER = ^uint64(0)
28+
)
29+
3530
//go:nosplit
3631
func semasleep(ns int64) int32 {
37-
var start int64
32+
mp := getg().m
33+
t := _DISPATCH_TIME_FOREVER
3834
if ns >= 0 {
39-
start = nanotime()
35+
t = dispatch_time(_DISPATCH_TIME_NOW, ns)
4036
}
41-
mp := getg().m
42-
pthread_mutex_lock(&mp.mutex)
43-
for {
44-
if mp.count > 0 {
45-
mp.count--
46-
pthread_mutex_unlock(&mp.mutex)
47-
return 0
48-
}
49-
if ns >= 0 {
50-
spent := nanotime() - start
51-
if spent >= ns {
52-
pthread_mutex_unlock(&mp.mutex)
53-
return -1
54-
}
55-
var t timespec
56-
t.setNsec(ns - spent)
57-
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
58-
if err == _ETIMEDOUT {
59-
pthread_mutex_unlock(&mp.mutex)
60-
return -1
61-
}
62-
} else {
63-
pthread_cond_wait(&mp.cond, &mp.mutex)
64-
}
37+
if dispatch_semaphore_wait(mp.sema, t) != 0 {
38+
return -1
6539
}
40+
return 0
6641
}
6742

6843
//go:nosplit
6944
func semawakeup(mp *m) {
70-
pthread_mutex_lock(&mp.mutex)
71-
mp.count++
72-
if mp.count > 0 {
73-
pthread_cond_signal(&mp.cond)
74-
}
75-
pthread_mutex_unlock(&mp.mutex)
45+
dispatch_semaphore_signal(mp.sema)
7646
}
7747

7848
// BSD interface for threading.

src/runtime/sys_darwin.go

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -339,52 +339,33 @@ func kevent_trampoline()
339339

340340
//go:nosplit
341341
//go:cgo_unsafe_args
342-
func pthread_mutex_init(m *pthreadmutex, attr *pthreadmutexattr) int32 {
343-
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
344-
}
345-
func pthread_mutex_init_trampoline()
346-
347-
//go:nosplit
348-
//go:cgo_unsafe_args
349-
func pthread_mutex_lock(m *pthreadmutex) int32 {
350-
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
351-
}
352-
func pthread_mutex_lock_trampoline()
353-
354-
//go:nosplit
355-
//go:cgo_unsafe_args
356-
func pthread_mutex_unlock(m *pthreadmutex) int32 {
357-
return libcCall(unsafe.Pointer(funcPC(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
358-
}
359-
func pthread_mutex_unlock_trampoline()
360-
361-
//go:nosplit
362-
//go:cgo_unsafe_args
363-
func pthread_cond_init(c *pthreadcond, attr *pthreadcondattr) int32 {
364-
return libcCall(unsafe.Pointer(funcPC(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
342+
func dispatch_semaphore_create(val int) (sema uintptr) {
343+
libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_create_trampoline)), unsafe.Pointer(&val))
344+
return
365345
}
366-
func pthread_cond_init_trampoline()
346+
func dispatch_semaphore_create_trampoline()
367347

368348
//go:nosplit
369349
//go:cgo_unsafe_args
370-
func pthread_cond_wait(c *pthreadcond, m *pthreadmutex) int32 {
371-
return libcCall(unsafe.Pointer(funcPC(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
350+
func dispatch_semaphore_wait(sema uintptr, t uint64) int32 {
351+
return libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_wait_trampoline)), unsafe.Pointer(&sema))
372352
}
373-
func pthread_cond_wait_trampoline()
353+
func dispatch_semaphore_wait_trampoline()
374354

375355
//go:nosplit
376356
//go:cgo_unsafe_args
377-
func pthread_cond_timedwait_relative_np(c *pthreadcond, m *pthreadmutex, t *timespec) int32 {
378-
return libcCall(unsafe.Pointer(funcPC(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
357+
func dispatch_semaphore_signal(sema uintptr) {
358+
libcCall(unsafe.Pointer(funcPC(dispatch_semaphore_signal_trampoline)), unsafe.Pointer(&sema))
379359
}
380-
func pthread_cond_timedwait_relative_np_trampoline()
360+
func dispatch_semaphore_signal_trampoline()
381361

382362
//go:nosplit
383363
//go:cgo_unsafe_args
384-
func pthread_cond_signal(c *pthreadcond) int32 {
385-
return libcCall(unsafe.Pointer(funcPC(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
364+
func dispatch_time(base uint64, delta int64) (result uint64) {
365+
libcCall(unsafe.Pointer(funcPC(dispatch_time_trampoline)), unsafe.Pointer(&base))
366+
return
386367
}
387-
func pthread_cond_signal_trampoline()
368+
func dispatch_time_trampoline()
388369

389370
// Not used on Darwin, but must be defined.
390371
func exitThread(wait *uint32) {
@@ -430,13 +411,10 @@ func closeonexec(fd int32) {
430411
//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib"
431412
//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib"
432413

433-
//go:cgo_import_dynamic libc_pthread_mutex_init pthread_mutex_init "/usr/lib/libSystem.B.dylib"
434-
//go:cgo_import_dynamic libc_pthread_mutex_lock pthread_mutex_lock "/usr/lib/libSystem.B.dylib"
435-
//go:cgo_import_dynamic libc_pthread_mutex_unlock pthread_mutex_unlock "/usr/lib/libSystem.B.dylib"
436-
//go:cgo_import_dynamic libc_pthread_cond_init pthread_cond_init "/usr/lib/libSystem.B.dylib"
437-
//go:cgo_import_dynamic libc_pthread_cond_wait pthread_cond_wait "/usr/lib/libSystem.B.dylib"
438-
//go:cgo_import_dynamic libc_pthread_cond_timedwait_relative_np pthread_cond_timedwait_relative_np "/usr/lib/libSystem.B.dylib"
439-
//go:cgo_import_dynamic libc_pthread_cond_signal pthread_cond_signal "/usr/lib/libSystem.B.dylib"
414+
//go:cgo_import_dynamic libc_dispatch_semaphore_create dispatch_semaphore_create "/usr/lib/libSystem.B.dylib"
415+
//go:cgo_import_dynamic libc_dispatch_semaphore_wait dispatch_semaphore_wait "/usr/lib/libSystem.B.dylib"
416+
//go:cgo_import_dynamic libc_dispatch_semaphore_signal dispatch_semaphore_signal "/usr/lib/libSystem.B.dylib"
417+
//go:cgo_import_dynamic libc_dispatch_time dispatch_time "/usr/lib/libSystem.B.dylib"
440418

441419
// Magic incantation to get libSystem actually dynamically linked.
442420
// TODO: Why does the code require this? See cmd/link/internal/ld/go.go

src/runtime/sys_darwin_386.s

Lines changed: 26 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -532,96 +532,63 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
532532
POPL BP
533533
RET
534534

535-
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
535+
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
536536
PUSHL BP
537537
MOVL SP, BP
538538
SUBL $8, SP
539-
MOVL 16(SP), CX
540-
MOVL 0(CX), AX // arg 1 mutex
541-
MOVL AX, 0(SP)
542-
MOVL 4(CX), AX // arg 2 attr
543-
MOVL AX, 4(SP)
544-
CALL libc_pthread_mutex_init(SB)
545-
MOVL BP, SP
546-
POPL BP
547-
RET
548-
549-
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
550-
PUSHL BP
551-
MOVL SP, BP
552-
SUBL $8, SP
553-
MOVL 16(SP), CX
554-
MOVL 0(CX), AX // arg 1 mutex
555-
MOVL AX, 0(SP)
556-
CALL libc_pthread_mutex_lock(SB)
557-
MOVL BP, SP
558-
POPL BP
559-
RET
560-
561-
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
562-
PUSHL BP
563-
MOVL SP, BP
564-
SUBL $8, SP
565-
MOVL 16(SP), CX
566-
MOVL 0(CX), AX // arg 1 mutex
539+
MOVL 16(SP), BX
540+
MOVL 0(BX), AX // arg 1 value
567541
MOVL AX, 0(SP)
568-
CALL libc_pthread_mutex_unlock(SB)
542+
CALL libc_dispatch_semaphore_create(SB)
543+
MOVL AX, 4(BX) // result sema
569544
MOVL BP, SP
570545
POPL BP
571546
RET
572547

573-
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
548+
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
574549
PUSHL BP
575550
MOVL SP, BP
576-
SUBL $8, SP
577-
MOVL 16(SP), CX
578-
MOVL 0(CX), AX // arg 1 cond
551+
SUBL $24, SP
552+
MOVL 32(SP), CX
553+
MOVL 0(CX), AX // arg 1 sema
579554
MOVL AX, 0(SP)
580-
MOVL 4(CX), AX // arg 2 attr
555+
MOVL 4(CX), AX // arg 2 timeout/0
581556
MOVL AX, 4(SP)
582-
CALL libc_pthread_cond_init(SB)
557+
MOVL 8(CX), AX // arg 2 timeout/1
558+
MOVL AX, 8(SP)
559+
CALL libc_dispatch_semaphore_wait(SB)
583560
MOVL BP, SP
584561
POPL BP
585562
RET
586563

587-
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
564+
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
588565
PUSHL BP
589566
MOVL SP, BP
590567
SUBL $8, SP
591568
MOVL 16(SP), CX
592-
MOVL 0(CX), AX // arg 1 cond
569+
MOVL 0(CX), AX // arg 1 sema
593570
MOVL AX, 0(SP)
594-
MOVL 4(CX), AX // arg 2 mutex
595-
MOVL AX, 4(SP)
596-
CALL libc_pthread_cond_wait(SB)
571+
CALL libc_dispatch_semaphore_signal(SB)
597572
MOVL BP, SP
598573
POPL BP
599574
RET
600575

601-
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
576+
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
602577
PUSHL BP
603578
MOVL SP, BP
604579
SUBL $24, SP
605-
MOVL 32(SP), CX
606-
MOVL 0(CX), AX // arg 1 cond
580+
MOVL 32(SP), BX
581+
MOVL 0(BX), AX // arg 1 base/0
607582
MOVL AX, 0(SP)
608-
MOVL 4(CX), AX // arg 2 mutex
583+
MOVL 4(BX), AX // arg 1 base/1
609584
MOVL AX, 4(SP)
610-
MOVL 8(CX), AX // arg 3 timeout
585+
MOVL 8(BX), AX // arg 2 delta/0
611586
MOVL AX, 8(SP)
612-
CALL libc_pthread_cond_timedwait_relative_np(SB)
613-
MOVL BP, SP
614-
POPL BP
615-
RET
616-
617-
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
618-
PUSHL BP
619-
MOVL SP, BP
620-
SUBL $8, SP
621-
MOVL 16(SP), CX
622-
MOVL 0(CX), AX // arg 1 cond
623-
MOVL AX, 0(SP)
624-
CALL libc_pthread_cond_signal(SB)
587+
MOVL 12(BX), AX // arg 2 delta/1
588+
MOVL AX, 12(SP)
589+
CALL libc_dispatch_time(SB)
590+
MOVL AX, 16(BX) // result/0
591+
MOVL DX, 20(BX) // result/1
625592
MOVL BP, SP
626593
POPL BP
627594
RET

src/runtime/sys_darwin_amd64.s

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -482,64 +482,44 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
482482
POPQ BP
483483
RET
484484

485-
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
485+
TEXT runtime·dispatch_semaphore_create_trampoline(SB),NOSPLIT,$0
486486
PUSHQ BP
487487
MOVQ SP, BP
488-
MOVQ 8(DI), SI // arg 2 attr
489-
MOVQ 0(DI), DI // arg 1 mutex
490-
CALL libc_pthread_mutex_init(SB)
491-
POPQ BP
492-
RET
493-
494-
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
495-
PUSHQ BP
496-
MOVQ SP, BP
497-
MOVQ 0(DI), DI // arg 1 mutex
498-
CALL libc_pthread_mutex_lock(SB)
499-
POPQ BP
500-
RET
501-
502-
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
503-
PUSHQ BP
504-
MOVQ SP, BP
505-
MOVQ 0(DI), DI // arg 1 mutex
506-
CALL libc_pthread_mutex_unlock(SB)
507-
POPQ BP
508-
RET
509-
510-
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
511-
PUSHQ BP
512-
MOVQ SP, BP
513-
MOVQ 8(DI), SI // arg 2 attr
514-
MOVQ 0(DI), DI // arg 1 cond
515-
CALL libc_pthread_cond_init(SB)
488+
MOVQ DI, BX
489+
MOVQ 0(BX), DI // arg 1 value
490+
CALL libc_dispatch_semaphore_create(SB)
491+
MOVQ AX, 8(BX) // result sema
516492
POPQ BP
517493
RET
518494

519-
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
495+
TEXT runtime·dispatch_semaphore_wait_trampoline(SB),NOSPLIT,$0
520496
PUSHQ BP
521497
MOVQ SP, BP
522-
MOVQ 8(DI), SI // arg 2 mutex
523-
MOVQ 0(DI), DI // arg 1 cond
524-
CALL libc_pthread_cond_wait(SB)
498+
MOVQ 8(DI), SI // arg 2 timeout
499+
MOVQ 0(DI), DI // arg 1 sema
500+
CALL libc_dispatch_semaphore_wait(SB)
501+
TESTQ AX, AX // For safety convert 64-bit result to int32 0 or 1.
502+
JEQ 2(PC)
503+
MOVL $1, AX
525504
POPQ BP
526505
RET
527506

528-
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
507+
TEXT runtime·dispatch_semaphore_signal_trampoline(SB),NOSPLIT,$0
529508
PUSHQ BP
530509
MOVQ SP, BP
531-
MOVQ 8(DI), SI // arg 2 mutex
532-
MOVQ 16(DI), DX // arg 3 timeout
533-
MOVQ 0(DI), DI // arg 1 cond
534-
CALL libc_pthread_cond_timedwait_relative_np(SB)
510+
MOVQ 0(DI), DI // arg 1 sema
511+
CALL libc_dispatch_semaphore_signal(SB)
535512
POPQ BP
536513
RET
537514

538-
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
515+
TEXT runtime·dispatch_time_trampoline(SB),NOSPLIT,$0
539516
PUSHQ BP
540517
MOVQ SP, BP
541-
MOVQ 0(DI), DI // arg 1 cond
542-
CALL libc_pthread_cond_signal(SB)
518+
MOVQ DI, BX
519+
MOVQ 0(BX), DI // arg 1 base
520+
MOVQ 8(BX), SI // arg 2 delta
521+
CALL libc_dispatch_time(SB)
522+
MOVQ AX, 16(BX)
543523
POPQ BP
544524
RET
545525

0 commit comments

Comments
 (0)