Commit 21656d09 authored by Keith Randall's avatar Keith Randall

runtime: convert exit to use pthread library on Darwin

Now we no longer need to mess with TLS on Darwin 386/amd64, we always
rely on the pthread library to set it up. We now just use one entry
in the TLS for the G.
Return from mstart to let the pthread library clean up the OS thread.

Change-Id: Iccf58049d545515d9b1d090b161f420e40ffd244
Reviewed-on: https://go-review.googlesource.com/110215Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 6f7ec484
...@@ -228,6 +228,10 @@ needtls: ...@@ -228,6 +228,10 @@ needtls:
// skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases // skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases
JMP ok JMP ok
#endif #endif
#ifdef GOOS_darwin
// skip runtime·ldt0setup(SB) on Darwin
JMP ok
#endif
// set up %gs // set up %gs
CALL runtime·ldt0setup(SB) CALL runtime·ldt0setup(SB)
......
...@@ -188,6 +188,10 @@ needtls: ...@@ -188,6 +188,10 @@ needtls:
// skip TLS setup on Solaris // skip TLS setup on Solaris
JMP ok JMP ok
#endif #endif
#ifdef GOOS_darwin
// skip TLS setup on Darwin
JMP ok
#endif
LEAQ runtime·m0+m_tls(SB), DI LEAQ runtime·m0+m_tls(SB), DI
CALL runtime·settls(SB) CALL runtime·settls(SB)
......
...@@ -135,11 +135,14 @@ func newosproc(mp *m) { ...@@ -135,11 +135,14 @@ func newosproc(mp *m) {
exit(1) exit(1)
} }
// Set the stack we want to use. // Set the stack size we want to use. 64KB for now.
if pthread_attr_setstack(&attr, unsafe.Pointer(mp.g0.stack.lo), mp.g0.stack.hi-mp.g0.stack.lo) != 0 { // TODO: just use OS default size?
const stackSize = 1 << 16
if pthread_attr_setstacksize(&attr, stackSize) != 0 {
write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
exit(1) exit(1)
} }
//mSysStatInc(&memstats.stacks_sys, stackSize) //TODO: do this?
// Tell the pthread library we won't join with this thread. // Tell the pthread library we won't join with this thread.
if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
...@@ -169,12 +172,6 @@ func mstart_stub() ...@@ -169,12 +172,6 @@ func mstart_stub()
// //
//go:nosplit //go:nosplit
func newosproc0(stacksize uintptr, fn uintptr) { func newosproc0(stacksize uintptr, fn uintptr) {
stack := sysAlloc(stacksize, &memstats.stacks_sys)
if stack == nil {
write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
exit(1)
}
// Initialize an attribute object. // Initialize an attribute object.
var attr pthreadattr var attr pthreadattr
var err int32 var err int32
...@@ -185,10 +182,11 @@ func newosproc0(stacksize uintptr, fn uintptr) { ...@@ -185,10 +182,11 @@ func newosproc0(stacksize uintptr, fn uintptr) {
} }
// Set the stack we want to use. // Set the stack we want to use.
if pthread_attr_setstack_trampoline(&attr, stack, stacksize) != 0 { if pthread_attr_setstacksize_trampoline(&attr, stacksize) != 0 {
write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
exit(1) exit(1)
} }
mSysStatInc(&memstats.stacks_sys, stacksize)
// Tell the pthread library we won't join with this thread. // Tell the pthread library we won't join with this thread.
if pthread_attr_setdetachstate_trampoline(&attr, _PTHREAD_CREATE_DETACHED) != 0 { if pthread_attr_setdetachstate_trampoline(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
......
...@@ -1195,8 +1195,8 @@ func mstart() { ...@@ -1195,8 +1195,8 @@ func mstart() {
mstart1() mstart1()
// Exit this thread. // Exit this thread.
if GOOS == "windows" || GOOS == "solaris" || GOOS == "plan9" { if GOOS == "windows" || GOOS == "solaris" || GOOS == "plan9" || (GOOS == "darwin" && (GOARCH == "amd64" || GOARCH == "386")) {
// Window, Solaris and Plan 9 always system-allocate // Window, Solaris, Darwin and Plan 9 always system-allocate
// the stack, but put it in _g_.stack before mstart, // the stack, but put it in _g_.stack before mstart,
// so the logic above hasn't set osStack yet. // so the logic above hasn't set osStack yet.
osStack = true osStack = true
...@@ -1517,9 +1517,9 @@ func allocm(_p_ *p, fn func()) *m { ...@@ -1517,9 +1517,9 @@ func allocm(_p_ *p, fn func()) *m {
mp.mstartfn = fn mp.mstartfn = fn
mcommoninit(mp) mcommoninit(mp)
// In case of cgo or Solaris, pthread_create will make us a stack. // In case of cgo or Solaris or Darwin, pthread_create will make us a stack.
// Windows and Plan 9 will layout sched stack on OS stack. // Windows and Plan 9 will layout sched stack on OS stack.
if iscgo || GOOS == "solaris" || GOOS == "windows" || GOOS == "plan9" { if iscgo || GOOS == "solaris" || GOOS == "windows" || GOOS == "plan9" || (GOOS == "darwin" && (GOARCH == "386" || GOARCH == "amd64")) {
mp.g0 = malg(-1) mp.g0 = malg(-1)
} else { } else {
mp.g0 = malg(8192 * sys.StackGuardMultiplier) mp.g0 = malg(8192 * sys.StackGuardMultiplier)
......
...@@ -21,15 +21,15 @@ func pthread_attr_init(attr *pthreadattr) (errno int32) { ...@@ -21,15 +21,15 @@ func pthread_attr_init(attr *pthreadattr) (errno int32) {
func pthread_attr_init_trampoline(attr *pthreadattr) int32 func pthread_attr_init_trampoline(attr *pthreadattr) int32
//go:nowritebarrier //go:nowritebarrier
func pthread_attr_setstack(attr *pthreadattr, addr unsafe.Pointer, size uintptr) (errno int32) { func pthread_attr_setstacksize(attr *pthreadattr, size uintptr) (errno int32) {
systemstack(func() { systemstack(func() {
errno = pthread_attr_setstack_trampoline(attr, addr, size) errno = pthread_attr_setstacksize_trampoline(attr, size)
}) })
return return
} }
//go:noescape //go:noescape
func pthread_attr_setstack_trampoline(attr *pthreadattr, addr unsafe.Pointer, size uintptr) int32 func pthread_attr_setstacksize_trampoline(attr *pthreadattr, size uintptr) int32
//go:nowritebarrier //go:nowritebarrier
func pthread_attr_setdetachstate(attr *pthreadattr, state int) (errno int32) { func pthread_attr_setdetachstate(attr *pthreadattr, state int) (errno int32) {
...@@ -57,9 +57,10 @@ func pthread_create_trampoline(t *pthread, attr *pthreadattr, start uintptr, arg ...@@ -57,9 +57,10 @@ func pthread_create_trampoline(t *pthread, attr *pthreadattr, start uintptr, arg
// in a system library, with the libc_ prefix missing. // in a system library, with the libc_ prefix missing.
//go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_pthread_attr_setstacksize pthread_attr_setstacksize "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_create pthread_create "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib"
// Magic incantation to get libSystem actually dynamically linked. // Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210 // TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
......
...@@ -11,46 +11,23 @@ ...@@ -11,46 +11,23 @@
#include "textflag.h" #include "textflag.h"
// Exit the entire program (like C exit) // Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$0 TEXT runtime·exit(SB),NOSPLIT,$0-4
MOVL $1, AX MOVL code+0(FP), AX
INT $0x80 PUSHL BP
MOVL $0xf1, 0xf1 // crash MOVL SP, BP
RET SUBL $4, SP // allocate space for callee args
ANDL $~15, SP // align stack
// Exit this OS thread (like pthread_exit, which eventually MOVL AX, 0(SP)
// calls __bsdthread_terminate). CALL libc_exit(SB)
TEXT exit1<>(SB),NOSPLIT,$16-0
// __bsdthread_terminate takes 4 word-size arguments.
// Set them all to 0. (None are an exit status.)
MOVL $0, 0(SP)
MOVL $0, 4(SP)
MOVL $0, 8(SP)
MOVL $0, 12(SP)
MOVL $361, AX
INT $0x80
JAE 2(PC)
MOVL $0xf1, 0xf1 // crash MOVL $0xf1, 0xf1 // crash
MOVL BP, SP
POPL BP
RET RET
GLOBL exitStack<>(SB),RODATA,$(4*4) // Not used on Darwin.
DATA exitStack<>+0x00(SB)/4, $0
DATA exitStack<>+0x04(SB)/4, $0
DATA exitStack<>+0x08(SB)/4, $0
DATA exitStack<>+0x0c(SB)/4, $0
// func exitThread(wait *uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4 TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVL wait+0(FP), AX
// We're done using the stack.
MOVL $0, (AX)
// __bsdthread_terminate takes 4 arguments, which it expects
// on the stack. They should all be 0, so switch over to a
// fake stack of 0s. It won't write to the stack.
MOVL $exitStack<>(SB), SP
MOVL $361, AX // __bsdthread_terminate
INT $0x80
MOVL $0xf1, 0xf1 // crash MOVL $0xf1, 0xf1 // crash
JMP 0(PC) RET
TEXT runtime·open(SB),NOSPLIT,$0 TEXT runtime·open(SB),NOSPLIT,$0
MOVL $5, AX MOVL $5, AX
...@@ -437,38 +414,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 ...@@ -437,38 +414,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
RET RET
// func setldt(entry int, address int, limit int) // func setldt(entry int, address int, limit int)
// entry and limit are ignored.
TEXT runtime·setldt(SB),NOSPLIT,$32 TEXT runtime·setldt(SB),NOSPLIT,$32
MOVL address+4(FP), BX // aka base // Nothing to do on Darwin, pthread already set thread-local storage up.
/*
* When linking against the system libraries,
* we use its pthread_create and let it set up %gs
* for us. When we do that, the private storage
* we get is not at 0(GS) but at 0x18(GS).
* The linker rewrites 0(TLS) into 0x18(GS) for us.
* To accommodate that rewrite, we translate the
* address here so that 0x18(GS) maps to 0(address).
*
* Constant must match the one in cmd/link/internal/ld/sym.go.
*/
SUBL $0x18, BX
/*
* Must set up as USER_CTHREAD segment because
* Darwin forces that value into %gs for signal handlers,
* and if we don't set one up, we'll get a recursive
* fault trying to get into the signal handler.
* Since we have to set one up anyway, it might as
* well be the value we want. So don't bother with
* i386_set_ldt.
*/
MOVL BX, 4(SP)
MOVL $3, AX // thread_fast_set_cthread_self - machdep call #3
INT $0x82 // sic: 0x82, not 0x80, for machdep call
XORL AX, AX
MOVW GS, AX
RET RET
TEXT runtime·sysctl(SB),NOSPLIT,$0 TEXT runtime·sysctl(SB),NOSPLIT,$0
...@@ -531,11 +478,11 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 ...@@ -531,11 +478,11 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
// Someday the convention will be D is always cleared. // Someday the convention will be D is always cleared.
CLD CLD
CALL runtime·stackcheck(SB) // just in case
CALL runtime·mstart(SB) CALL runtime·mstart(SB)
// mstart shouldn't ever return, and if it does, we shouldn't ever join to this thread // Go is all done with this OS thread.
// to get its return status. But tell pthread everything is ok, just in case. // Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX XORL AX, AX
RET RET
...@@ -565,26 +512,24 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0-8 ...@@ -565,26 +512,24 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0-8
MOVL AX, ret+4(FP) MOVL AX, ret+4(FP)
RET RET
TEXT runtime·pthread_attr_setstack_trampoline(SB),NOSPLIT,$0-16 TEXT runtime·pthread_attr_setstacksize_trampoline(SB),NOSPLIT,$0-12
MOVL attr+0(FP), AX MOVL attr+0(FP), AX
MOVL addr+4(FP), CX MOVL size+4(FP), CX
MOVL size+8(FP), DX
PUSHL BP PUSHL BP
MOVL SP, BP MOVL SP, BP
SUBL $12, SP SUBL $8, SP
ANDL $~15, SP ANDL $~15, SP
MOVL AX, 0(SP) MOVL AX, 0(SP)
MOVL CX, 4(SP) MOVL CX, 4(SP)
MOVL DX, 8(SP) CALL libc_pthread_attr_setstacksize(SB)
CALL libc_pthread_attr_setstack(SB)
MOVL BP, SP MOVL BP, SP
POPL BP POPL BP
MOVL AX, ret+12(FP) MOVL AX, ret+8(FP)
RET RET
TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0-12 TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0-12
......
...@@ -16,35 +16,22 @@ ...@@ -16,35 +16,22 @@
#include "textflag.h" #include "textflag.h"
// Exit the entire program (like C exit) // Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$0 TEXT runtime·exit(SB),NOSPLIT,$0-4
MOVL code+0(FP), DI // arg 1 exit status MOVL code+0(FP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry PUSHQ BP
SYSCALL MOVQ SP, BP
ANDQ $~15, SP // align stack
CALL libc_exit(SB)
MOVL $0xf1, 0xf1 // crash MOVL $0xf1, 0xf1 // crash
MOVQ BP, SP
POPQ BP
RET RET
// Exit this OS thread (like pthread_exit, which eventually // Not used on Darwin.
// calls __bsdthread_terminate). TEXT runtime·exitThread(SB),NOSPLIT,$0-8
TEXT exit1<>(SB),NOSPLIT,$0
// Because of exitThread below, this must not use the stack.
// __bsdthread_terminate takes 4 word-size arguments.
// Set them all to 0. (None are an exit status.)
MOVL $0, DI
MOVL $0, SI
MOVL $0, DX
MOVL $0, R10
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
MOVL $0xf1, 0xf1 // crash MOVL $0xf1, 0xf1 // crash
RET RET
// func exitThread(wait *uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVQ wait+0(FP), AX
// We're done using the stack.
MOVL $0, (AX)
JMP exit1<>(SB)
TEXT runtime·open(SB),NOSPLIT,$0 TEXT runtime·open(SB),NOSPLIT,$0
MOVQ name+0(FP), DI // arg 1 pathname MOVQ name+0(FP), DI // arg 1 pathname
MOVL mode+8(FP), SI // arg 2 flags MOVL mode+8(FP), SI // arg 2 flags
...@@ -490,16 +477,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 ...@@ -490,16 +477,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
MOVL AX, ret+8(FP) MOVL AX, ret+8(FP)
RET RET
// set tls base to DI
TEXT runtime·settls(SB),NOSPLIT,$32 TEXT runtime·settls(SB),NOSPLIT,$32
/* // Nothing to do on Darwin, pthread already set thread-local storage up.
* Same as in sys_darwin_386.s, but a different constant.
* Constant must match the one in cmd/link/internal/ld/sym.go.
*/
SUBQ $0x30, DI
MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3
SYSCALL
RET RET
TEXT runtime·sysctl(SB),NOSPLIT,$0 TEXT runtime·sysctl(SB),NOSPLIT,$0
...@@ -571,11 +550,11 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 ...@@ -571,11 +550,11 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
// Someday the convention will be D is always cleared. // Someday the convention will be D is always cleared.
CLD CLD
CALL runtime·stackcheck(SB) // just in case
CALL runtime·mstart(SB) CALL runtime·mstart(SB)
// mstart shouldn't ever return, and if it does, we shouldn't ever join to this thread // Go is all done with this OS thread.
// to get its return status. But tell pthread everything is ok, just in case. // Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX XORL AX, AX
RET RET
...@@ -591,17 +570,16 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0-12 ...@@ -591,17 +570,16 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0-12
MOVL AX, ret+8(FP) MOVL AX, ret+8(FP)
RET RET
TEXT runtime·pthread_attr_setstack_trampoline(SB),NOSPLIT,$0-28 TEXT runtime·pthread_attr_setstacksize_trampoline(SB),NOSPLIT,$0-20
MOVQ attr+0(FP), DI MOVQ attr+0(FP), DI
MOVQ addr+8(FP), SI MOVQ size+8(FP), SI
MOVQ size+16(FP), DX
PUSHQ BP PUSHQ BP
MOVQ SP, BP MOVQ SP, BP
ANDQ $~15, SP ANDQ $~15, SP
CALL libc_pthread_attr_setstack(SB) CALL libc_pthread_attr_setstacksize(SB)
MOVQ BP, SP MOVQ BP, SP
POPQ BP POPQ BP
MOVL AX, ret+24(FP) MOVL AX, ret+16(FP)
RET RET
TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0-20 TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0-20
......
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