mirror of
https://github.com/golang/go
synced 2024-11-11 18:51:37 -07:00
Revert "runtime/cgo: store M for C-created thread in pthread key"
This reverts CL 481061. Reason for revert: When built with C TSAN, x_cgo_getstackbound triggers race detection on `g->stacklo` because the synchronization is in Go, which isn't instrumented. For #51676. For #59294. For #59678. Change-Id: I38afcda9fcffd6537582a39a5214bc23dc147d47 Reviewed-on: https://go-review.googlesource.com/c/go/+/485275 TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
97e5ca6d4e
commit
94850c6f79
@ -104,7 +104,6 @@ func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
|
|||||||
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
|
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
|
||||||
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
|
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
|
||||||
|
|
||||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||||
func BenchmarkGoString(b *testing.B) { benchGoString(b) }
|
func BenchmarkGoString(b *testing.B) { benchGoString(b) }
|
||||||
func BenchmarkCGoCallback(b *testing.B) { benchCallback(b) }
|
func BenchmarkCGoCallback(b *testing.B) { benchCallback(b) }
|
||||||
func BenchmarkCGoInCThread(b *testing.B) { benchCGoInCthread(b) }
|
|
||||||
|
@ -32,27 +32,3 @@ doAdd(int max, int nthread)
|
|||||||
for(i=0; i<nthread; i++)
|
for(i=0; i<nthread; i++)
|
||||||
pthread_join(thread_id[i], 0);
|
pthread_join(thread_id[i], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
|
||||||
goDummyCallbackThread(void* p)
|
|
||||||
{
|
|
||||||
int i, max;
|
|
||||||
|
|
||||||
max = *(int*)p;
|
|
||||||
for(i=0; i<max; i++)
|
|
||||||
goDummy();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
callGoInCThread(int max)
|
|
||||||
{
|
|
||||||
pthread_t thread;
|
|
||||||
|
|
||||||
if (pthread_create(&thread, NULL, goDummyCallbackThread, (void*)(&max)) != 0)
|
|
||||||
return -1;
|
|
||||||
if (pthread_join(thread, NULL) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
@ -35,25 +35,3 @@ doAdd(int max, int nthread)
|
|||||||
CloseHandle((HANDLE)thread_id[i]);
|
CloseHandle((HANDLE)thread_id[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__stdcall
|
|
||||||
static unsigned int
|
|
||||||
goDummyCallbackThread(void* p)
|
|
||||||
{
|
|
||||||
int i, max;
|
|
||||||
|
|
||||||
max = *(int*)p;
|
|
||||||
for(i=0; i<max; i++)
|
|
||||||
goDummy();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
callGoInCThread(int max)
|
|
||||||
{
|
|
||||||
uintptr_t thread_id;
|
|
||||||
thread_id = _beginthreadex(0, 0, goDummyCallbackThread, &max, 0, 0);
|
|
||||||
WaitForSingleObject((HANDLE)thread_id, INFINITE);
|
|
||||||
CloseHandle((HANDLE)thread_id);
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
/*
|
/*
|
||||||
// threads
|
// threads
|
||||||
extern void doAdd(int, int);
|
extern void doAdd(int, int);
|
||||||
extern int callGoInCThread(int);
|
|
||||||
|
|
||||||
// issue 1328
|
// issue 1328
|
||||||
void IntoC(void);
|
void IntoC(void);
|
||||||
@ -147,10 +146,6 @@ func Add(x int) {
|
|||||||
*p = 2
|
*p = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
//export goDummy
|
|
||||||
func goDummy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCthread(t *testing.T) {
|
func testCthread(t *testing.T) {
|
||||||
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
|
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
|
||||||
t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add")
|
t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add")
|
||||||
@ -164,15 +159,6 @@ func testCthread(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark measuring overhead from C to Go in a C thread.
|
|
||||||
// Create a new C thread and invoke Go function repeatedly in the new C thread.
|
|
||||||
func benchCGoInCthread(b *testing.B) {
|
|
||||||
n := C.callGoInCThread(C.int(b.N))
|
|
||||||
if int(n) != b.N {
|
|
||||||
b.Fatal("unmatch loop times")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// issue 1328
|
// issue 1328
|
||||||
|
|
||||||
//export BackIntoGo
|
//export BackIntoGo
|
||||||
|
@ -1247,57 +1247,3 @@ func TestPreemption(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue 59294. Test calling Go function from C after using some
|
|
||||||
// stack space.
|
|
||||||
func TestDeepStack(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
if !testWork {
|
|
||||||
defer func() {
|
|
||||||
os.Remove("testp9" + exeSuffix)
|
|
||||||
os.Remove("libgo9.a")
|
|
||||||
os.Remove("libgo9.h")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo9.a", "./libgo9")
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
t.Logf("%v\n%s", cmd.Args, out)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
checkLineComments(t, "libgo9.h")
|
|
||||||
checkArchive(t, "libgo9.a")
|
|
||||||
|
|
||||||
// build with -O0 so the C compiler won't optimize out the large stack frame
|
|
||||||
ccArgs := append(cc, "-O0", "-o", "testp9"+exeSuffix, "main9.c", "libgo9.a")
|
|
||||||
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
|
||||||
t.Logf("%v\n%s", ccArgs, out)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
argv := cmdToRun("./testp9")
|
|
||||||
cmd = exec.Command(argv[0], argv[1:]...)
|
|
||||||
sb := new(strings.Builder)
|
|
||||||
cmd.Stdout = sb
|
|
||||||
cmd.Stderr = sb
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
timer := time.AfterFunc(time.Minute,
|
|
||||||
func() {
|
|
||||||
t.Error("test program timed out")
|
|
||||||
cmd.Process.Kill()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer timer.Stop()
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
t.Logf("%v\n%s", cmd.Args, sb)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
14
misc/cgo/testcarchive/testdata/libgo9/a.go
vendored
14
misc/cgo/testcarchive/testdata/libgo9/a.go
vendored
@ -1,14 +0,0 @@
|
|||||||
// Copyright 2023 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.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "runtime"
|
|
||||||
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func main() {}
|
|
||||||
|
|
||||||
//export GoF
|
|
||||||
func GoF() { runtime.GC() }
|
|
24
misc/cgo/testcarchive/testdata/main9.c
vendored
24
misc/cgo/testcarchive/testdata/main9.c
vendored
@ -1,24 +0,0 @@
|
|||||||
// Copyright 2023 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.
|
|
||||||
|
|
||||||
#include "libgo9.h"
|
|
||||||
|
|
||||||
void use(int *x) { (*x)++; }
|
|
||||||
|
|
||||||
void callGoFWithDeepStack() {
|
|
||||||
int x[10000];
|
|
||||||
|
|
||||||
use(&x[0]);
|
|
||||||
use(&x[9999]);
|
|
||||||
|
|
||||||
GoF();
|
|
||||||
|
|
||||||
use(&x[0]);
|
|
||||||
use(&x[9999]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
GoF(); // call GoF without using much stack
|
|
||||||
callGoFWithDeepStack(); // call GoF with a deep stack
|
|
||||||
}
|
|
@ -689,20 +689,7 @@ nosave:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$12-12 // Frame size must match commented places below
|
TEXT ·cgocallback(SB),NOSPLIT,$12-12 // Frame size must match commented places below
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
// If g is nil, Go did not create the current thread.
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVL fn+0(FP), AX
|
|
||||||
CMPL AX, $0
|
|
||||||
JNE loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
get_tls(CX)
|
|
||||||
MOVL frame+4(FP), BX
|
|
||||||
MOVL BX, g(CX)
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// If g is nil, Go did not create the current thread,
|
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -720,9 +707,9 @@ loadg:
|
|||||||
MOVL BP, savedm-4(SP) // saved copy of oldm
|
MOVL BP, savedm-4(SP) // saved copy of oldm
|
||||||
JMP havem
|
JMP havem
|
||||||
needm:
|
needm:
|
||||||
MOVL $runtime·needAndBindM(SB), AX
|
MOVL $runtime·needm(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
MOVL $0, savedm-4(SP)
|
MOVL $0, savedm-4(SP) // dropm on return
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
MOVL g(CX), BP
|
MOVL g(CX), BP
|
||||||
MOVL g_m(BP), BP
|
MOVL g_m(BP), BP
|
||||||
@ -797,29 +784,13 @@ havem:
|
|||||||
MOVL 0(SP), AX
|
MOVL 0(SP), AX
|
||||||
MOVL AX, (g_sched+gobuf_sp)(SI)
|
MOVL AX, (g_sched+gobuf_sp)(SI)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVL savedm-4(SP), DX
|
MOVL savedm-4(SP), DX
|
||||||
CMPL DX, $0
|
CMPL DX, $0
|
||||||
JNE droppedm
|
JNE 3(PC)
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVL _cgo_pthread_key_created(SB), DX
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CMPL DX, $0
|
|
||||||
JEQ dropm
|
|
||||||
CMPL (DX), $0
|
|
||||||
JNE droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVL $runtime·dropm(SB), AX
|
MOVL $runtime·dropm(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
droppedm:
|
|
||||||
|
|
||||||
// Done!
|
// Done!
|
||||||
RET
|
RET
|
||||||
|
@ -918,20 +918,7 @@ GLOBL zeroTLS<>(SB),RODATA,$const_tlsSize
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
// If g is nil, Go did not create the current thread.
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVQ fn+0(FP), AX
|
|
||||||
CMPQ AX, $0
|
|
||||||
JNE loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
get_tls(CX)
|
|
||||||
MOVQ frame+8(FP), BX
|
|
||||||
MOVQ BX, g(CX)
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// If g is nil, Go did not create the current thread,
|
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one m for temporary use.
|
// Call needm to obtain one m for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -969,9 +956,9 @@ needm:
|
|||||||
// a bad value in there, in case needm tries to use it.
|
// a bad value in there, in case needm tries to use it.
|
||||||
XORPS X15, X15
|
XORPS X15, X15
|
||||||
XORQ R14, R14
|
XORQ R14, R14
|
||||||
MOVQ $runtime·needAndBindM<ABIInternal>(SB), AX
|
MOVQ $runtime·needm<ABIInternal>(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
MOVQ $0, savedm-8(SP)
|
MOVQ $0, savedm-8(SP) // dropm on return
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
MOVQ g(CX), BX
|
MOVQ g(CX), BX
|
||||||
MOVQ g_m(BX), BX
|
MOVQ g_m(BX), BX
|
||||||
@ -1060,26 +1047,11 @@ havem:
|
|||||||
MOVQ 0(SP), AX
|
MOVQ 0(SP), AX
|
||||||
MOVQ AX, (g_sched+gobuf_sp)(SI)
|
MOVQ AX, (g_sched+gobuf_sp)(SI)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVQ savedm-8(SP), BX
|
MOVQ savedm-8(SP), BX
|
||||||
CMPQ BX, $0
|
CMPQ BX, $0
|
||||||
JNE done
|
JNE done
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVQ _cgo_pthread_key_created(SB), AX
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CMPQ AX, $0
|
|
||||||
JEQ dropm
|
|
||||||
CMPQ (AX), $0
|
|
||||||
JNE done
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVQ $runtime·dropm(SB), AX
|
MOVQ $runtime·dropm(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
#ifdef GOOS_windows
|
#ifdef GOOS_windows
|
||||||
|
@ -630,16 +630,6 @@ nosave:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$12-12
|
TEXT ·cgocallback(SB),NOSPLIT,$12-12
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVW fn+0(FP), R1
|
|
||||||
CMP $0, R1
|
|
||||||
B.NE loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVW frame+4(FP), g
|
|
||||||
B dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
#ifdef GOOS_openbsd
|
#ifdef GOOS_openbsd
|
||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
@ -649,8 +639,7 @@ loadg:
|
|||||||
BL.NE runtime·load_g(SB)
|
BL.NE runtime·load_g(SB)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -664,7 +653,7 @@ loadg:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVW g, savedm-4(SP) // g is zero, so is m.
|
MOVW g, savedm-4(SP) // g is zero, so is m.
|
||||||
MOVW $runtime·needAndBindM(SB), R0
|
MOVW $runtime·needm(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
|
|
||||||
// Set m->g0->sched.sp = SP, so that if a panic happens
|
// Set m->g0->sched.sp = SP, so that if a panic happens
|
||||||
@ -735,31 +724,14 @@ havem:
|
|||||||
MOVW savedsp-12(SP), R4 // must match frame size
|
MOVW savedsp-12(SP), R4 // must match frame size
|
||||||
MOVW R4, (g_sched+gobuf_sp)(g)
|
MOVW R4, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVW savedm-4(SP), R6
|
MOVW savedm-4(SP), R6
|
||||||
CMP $0, R6
|
CMP $0, R6
|
||||||
B.NE done
|
B.NE 3(PC)
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVW _cgo_pthread_key_created(SB), R6
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CMP $0, R6
|
|
||||||
B.EQ dropm
|
|
||||||
MOVW (R6), R6
|
|
||||||
CMP $0, R6
|
|
||||||
B.NE done
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVW $runtime·dropm(SB), R0
|
MOVW $runtime·dropm(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
|
|
||||||
done:
|
|
||||||
// Done!
|
// Done!
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
@ -1014,20 +1014,10 @@ nosave:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVD fn+0(FP), R1
|
|
||||||
CBNZ R1, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVD frame+8(FP), g
|
|
||||||
B dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load g from thread-local storage.
|
// Load g from thread-local storage.
|
||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -1040,7 +1030,7 @@ loadg:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVD g, savedm-8(SP) // g is zero, so is m.
|
MOVD g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOVD $runtime·needAndBindM(SB), R0
|
MOVD $runtime·needm(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
|
|
||||||
// Set m->g0->sched.sp = SP, so that if a panic happens
|
// Set m->g0->sched.sp = SP, so that if a panic happens
|
||||||
@ -1121,24 +1111,10 @@ havem:
|
|||||||
MOVD savedsp-16(SP), R4
|
MOVD savedsp-16(SP), R4
|
||||||
MOVD R4, (g_sched+gobuf_sp)(g)
|
MOVD R4, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVD savedm-8(SP), R6
|
MOVD savedm-8(SP), R6
|
||||||
CBNZ R6, droppedm
|
CBNZ R6, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVD _cgo_pthread_key_created(SB), R6
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CBZ R6, dropm
|
|
||||||
MOVD (R6), R6
|
|
||||||
CBNZ R6, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVD $runtime·dropm(SB), R0
|
MOVD $runtime·dropm(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -460,23 +460,13 @@ g0:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVV fn+0(FP), R5
|
|
||||||
BNE R5, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVV frame+8(FP), g
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVB runtime·iscgo(SB), R19
|
MOVB runtime·iscgo(SB), R19
|
||||||
BEQ R19, nocgo
|
BEQ R19, nocgo
|
||||||
JAL runtime·load_g(SB)
|
JAL runtime·load_g(SB)
|
||||||
nocgo:
|
nocgo:
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -489,7 +479,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVV g, savedm-8(SP) // g is zero, so is m.
|
MOVV g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOVV $runtime·needAndBindM(SB), R4
|
MOVV $runtime·needm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
|
|
||||||
// Set m->sched.sp = SP, so that if a panic happens
|
// Set m->sched.sp = SP, so that if a panic happens
|
||||||
@ -561,24 +551,10 @@ havem:
|
|||||||
MOVV savedsp-24(SP), R13 // must match frame size
|
MOVV savedsp-24(SP), R13 // must match frame size
|
||||||
MOVV R13, (g_sched+gobuf_sp)(g)
|
MOVV R13, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVV savedm-8(SP), R12
|
MOVV savedm-8(SP), R12
|
||||||
BNE R12, droppedm
|
BNE R12, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVV _cgo_pthread_key_created(SB), R12
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
BEQ R12, dropm
|
|
||||||
MOVV (R12), R12
|
|
||||||
BNE R12, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVV $runtime·dropm(SB), R4
|
MOVV $runtime·dropm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -469,23 +469,13 @@ g0:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVV fn+0(FP), R5
|
|
||||||
BNE R5, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVV frame+8(FP), g
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVB runtime·iscgo(SB), R1
|
MOVB runtime·iscgo(SB), R1
|
||||||
BEQ R1, nocgo
|
BEQ R1, nocgo
|
||||||
JAL runtime·load_g(SB)
|
JAL runtime·load_g(SB)
|
||||||
nocgo:
|
nocgo:
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -498,7 +488,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVV g, savedm-8(SP) // g is zero, so is m.
|
MOVV g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOVV $runtime·needAndBindM(SB), R4
|
MOVV $runtime·needm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
|
|
||||||
// Set m->sched.sp = SP, so that if a panic happens
|
// Set m->sched.sp = SP, so that if a panic happens
|
||||||
@ -569,24 +559,10 @@ havem:
|
|||||||
MOVV savedsp-24(SP), R2 // must match frame size
|
MOVV savedsp-24(SP), R2 // must match frame size
|
||||||
MOVV R2, (g_sched+gobuf_sp)(g)
|
MOVV R2, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVV savedm-8(SP), R3
|
MOVV savedm-8(SP), R3
|
||||||
BNE R3, droppedm
|
BNE R3, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVV _cgo_pthread_key_created(SB), R3
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
BEQ R3, dropm
|
|
||||||
MOVV (R3), R3
|
|
||||||
BNE R3, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVV $runtime·dropm(SB), R4
|
MOVV $runtime·dropm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -459,23 +459,13 @@ g0:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$12-12
|
TEXT ·cgocallback(SB),NOSPLIT,$12-12
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVW fn+0(FP), R5
|
|
||||||
BNE R5, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVW frame+4(FP), g
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVB runtime·iscgo(SB), R1
|
MOVB runtime·iscgo(SB), R1
|
||||||
BEQ R1, nocgo
|
BEQ R1, nocgo
|
||||||
JAL runtime·load_g(SB)
|
JAL runtime·load_g(SB)
|
||||||
nocgo:
|
nocgo:
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -488,7 +478,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVW g, savedm-4(SP) // g is zero, so is m.
|
MOVW g, savedm-4(SP) // g is zero, so is m.
|
||||||
MOVW $runtime·needAndBindM(SB), R4
|
MOVW $runtime·needm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
|
|
||||||
// Set m->sched.sp = SP, so that if a panic happens
|
// Set m->sched.sp = SP, so that if a panic happens
|
||||||
@ -559,24 +549,10 @@ havem:
|
|||||||
MOVW savedsp-12(SP), R2 // must match frame size
|
MOVW savedsp-12(SP), R2 // must match frame size
|
||||||
MOVW R2, (g_sched+gobuf_sp)(g)
|
MOVW R2, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVW savedm-4(SP), R3
|
MOVW savedm-4(SP), R3
|
||||||
BNE R3, droppedm
|
BNE R3, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVW _cgo_pthread_key_created(SB), R3
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
BEQ R3, dropm
|
|
||||||
MOVW (R3), R3
|
|
||||||
BNE R3, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVW $runtime·dropm(SB), R4
|
MOVW $runtime·dropm(SB), R4
|
||||||
JAL (R4)
|
JAL (R4)
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -628,16 +628,6 @@ g0:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVD fn+0(FP), R5
|
|
||||||
CMP R5, $0
|
|
||||||
BNE loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVD frame+8(FP), g
|
|
||||||
BR dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVBZ runtime·iscgo(SB), R3
|
MOVBZ runtime·iscgo(SB), R3
|
||||||
CMP R3, $0
|
CMP R3, $0
|
||||||
@ -645,8 +635,7 @@ loadg:
|
|||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
nocgo:
|
nocgo:
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -660,7 +649,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVD g, savedm-8(SP) // g is zero, so is m.
|
MOVD g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOVD $runtime·needAndBindM(SB), R12
|
MOVD $runtime·needm(SB), R12
|
||||||
MOVD R12, CTR
|
MOVD R12, CTR
|
||||||
BL (CTR)
|
BL (CTR)
|
||||||
|
|
||||||
@ -735,27 +724,11 @@ havem:
|
|||||||
MOVD savedsp-24(SP), R4 // must match frame size
|
MOVD savedsp-24(SP), R4 // must match frame size
|
||||||
MOVD R4, (g_sched+gobuf_sp)(g)
|
MOVD R4, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVD savedm-8(SP), R6
|
MOVD savedm-8(SP), R6
|
||||||
CMP R6, $0
|
CMP R6, $0
|
||||||
BNE droppedm
|
BNE droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVD _cgo_pthread_key_created(SB), R6
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CMP R6, $0
|
|
||||||
BEQ dropm
|
|
||||||
MOVD (R6), R6
|
|
||||||
CMP R6, $0
|
|
||||||
BNE droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVD $runtime·dropm(SB), R12
|
MOVD $runtime·dropm(SB), R12
|
||||||
MOVD R12, CTR
|
MOVD R12, CTR
|
||||||
BL (CTR)
|
BL (CTR)
|
||||||
|
@ -519,23 +519,13 @@ TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOV fn+0(FP), X7
|
|
||||||
BNE ZERO, X7, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOV frame+8(FP), g
|
|
||||||
JMP dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVBU runtime·iscgo(SB), X5
|
MOVBU runtime·iscgo(SB), X5
|
||||||
BEQ ZERO, X5, nocgo
|
BEQ ZERO, X5, nocgo
|
||||||
CALL runtime·load_g(SB)
|
CALL runtime·load_g(SB)
|
||||||
nocgo:
|
nocgo:
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -548,7 +538,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOV g, savedm-8(SP) // g is zero, so is m.
|
MOV g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOV $runtime·needAndBindM(SB), X6
|
MOV $runtime·needm(SB), X6
|
||||||
JALR RA, X6
|
JALR RA, X6
|
||||||
|
|
||||||
// Set m->sched.sp = SP, so that if a panic happens
|
// Set m->sched.sp = SP, so that if a panic happens
|
||||||
@ -619,24 +609,10 @@ havem:
|
|||||||
MOV savedsp-24(SP), X6 // must match frame size
|
MOV savedsp-24(SP), X6 // must match frame size
|
||||||
MOV X6, (g_sched+gobuf_sp)(g)
|
MOV X6, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOV savedm-8(SP), X5
|
MOV savedm-8(SP), X5
|
||||||
BNE ZERO, X5, droppedm
|
BNE ZERO, X5, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOV _cgo_pthread_key_created(SB), X5
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
BEQ ZERO, X5, dropm
|
|
||||||
MOV (X5), X5
|
|
||||||
BNE ZERO, X5, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOV $runtime·dropm(SB), X6
|
MOV $runtime·dropm(SB), X6
|
||||||
JALR RA, X6
|
JALR RA, X6
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -564,23 +564,13 @@ g0:
|
|||||||
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback(SB),NOSPLIT,$24-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
|
|
||||||
// It is used to dropm while thread is exiting.
|
|
||||||
MOVD fn+0(FP), R1
|
|
||||||
CMPBNE R1, $0, loadg
|
|
||||||
// Restore the g from frame.
|
|
||||||
MOVD frame+8(FP), g
|
|
||||||
BR dropm
|
|
||||||
|
|
||||||
loadg:
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
MOVB runtime·iscgo(SB), R3
|
MOVB runtime·iscgo(SB), R3
|
||||||
CMPBEQ R3, $0, nocgo
|
CMPBEQ R3, $0, nocgo
|
||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
|
|
||||||
nocgo:
|
nocgo:
|
||||||
// If g is nil, Go did not create the current thread,
|
// If g is nil, Go did not create the current thread.
|
||||||
// or if this thread never called into Go on pthread platforms.
|
|
||||||
// Call needm to obtain one for temporary use.
|
// Call needm to obtain one for temporary use.
|
||||||
// In this case, we're running on the thread stack, so there's
|
// In this case, we're running on the thread stack, so there's
|
||||||
// lots of space, but the linker doesn't know. Hide the call from
|
// lots of space, but the linker doesn't know. Hide the call from
|
||||||
@ -593,7 +583,7 @@ nocgo:
|
|||||||
|
|
||||||
needm:
|
needm:
|
||||||
MOVD g, savedm-8(SP) // g is zero, so is m.
|
MOVD g, savedm-8(SP) // g is zero, so is m.
|
||||||
MOVD $runtime·needAndBindM(SB), R3
|
MOVD $runtime·needm(SB), R3
|
||||||
BL (R3)
|
BL (R3)
|
||||||
|
|
||||||
// Set m->sched.sp = SP, so that if a panic happens
|
// Set m->sched.sp = SP, so that if a panic happens
|
||||||
@ -664,24 +654,10 @@ havem:
|
|||||||
MOVD savedsp-24(SP), R4 // must match frame size
|
MOVD savedsp-24(SP), R4 // must match frame size
|
||||||
MOVD R4, (g_sched+gobuf_sp)(g)
|
MOVD R4, (g_sched+gobuf_sp)(g)
|
||||||
|
|
||||||
// If the m on entry was nil, we called needm above to borrow an m,
|
// If the m on entry was nil, we called needm above to borrow an m
|
||||||
// 1. for the duration of the call on non-pthread platforms,
|
// for the duration of the call. Since the call is over, return it with dropm.
|
||||||
// 2. or the duration of the C thread alive on pthread platforms.
|
|
||||||
// If the m on entry wasn't nil,
|
|
||||||
// 1. the thread might be a Go thread,
|
|
||||||
// 2. or it's wasn't the first call from a C thread on pthread platforms,
|
|
||||||
// since the we skip dropm to resue the m in the first call.
|
|
||||||
MOVD savedm-8(SP), R6
|
MOVD savedm-8(SP), R6
|
||||||
CMPBNE R6, $0, droppedm
|
CMPBNE R6, $0, droppedm
|
||||||
|
|
||||||
// Skip dropm to reuse it in the next call, when a pthread key has been created.
|
|
||||||
MOVD _cgo_pthread_key_created(SB), R6
|
|
||||||
// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
|
|
||||||
CMPBEQ R6, $0, dropm
|
|
||||||
MOVD (R6), R6
|
|
||||||
CMPBNE R6, $0, droppedm
|
|
||||||
|
|
||||||
dropm:
|
|
||||||
MOVD $runtime·dropm(SB), R3
|
MOVD $runtime·dropm(SB), R3
|
||||||
BL (R3)
|
BL (R3)
|
||||||
droppedm:
|
droppedm:
|
||||||
|
@ -17,9 +17,6 @@ import "unsafe"
|
|||||||
//go:linkname _cgo_callers _cgo_callers
|
//go:linkname _cgo_callers _cgo_callers
|
||||||
//go:linkname _cgo_set_context_function _cgo_set_context_function
|
//go:linkname _cgo_set_context_function _cgo_set_context_function
|
||||||
//go:linkname _cgo_yield _cgo_yield
|
//go:linkname _cgo_yield _cgo_yield
|
||||||
//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created
|
|
||||||
//go:linkname _cgo_bindm _cgo_bindm
|
|
||||||
//go:linkname _cgo_getstackbound _cgo_getstackbound
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_cgo_init unsafe.Pointer
|
_cgo_init unsafe.Pointer
|
||||||
@ -29,17 +26,11 @@ var (
|
|||||||
_cgo_callers unsafe.Pointer
|
_cgo_callers unsafe.Pointer
|
||||||
_cgo_set_context_function unsafe.Pointer
|
_cgo_set_context_function unsafe.Pointer
|
||||||
_cgo_yield unsafe.Pointer
|
_cgo_yield unsafe.Pointer
|
||||||
_cgo_pthread_key_created unsafe.Pointer
|
|
||||||
_cgo_bindm unsafe.Pointer
|
|
||||||
_cgo_getstackbound unsafe.Pointer
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// iscgo is set to true by the runtime/cgo package
|
// iscgo is set to true by the runtime/cgo package
|
||||||
var iscgo bool
|
var iscgo bool
|
||||||
|
|
||||||
// set_crosscall2 is set by the runtime/cgo package
|
|
||||||
var set_crosscall2 func()
|
|
||||||
|
|
||||||
// cgoHasExtraM is set on startup when an extra M is created for cgo.
|
// cgoHasExtraM is set on startup when an extra M is created for cgo.
|
||||||
// The extra M must be created before any C/C++ code calls cgocallback.
|
// The extra M must be created before any C/C++ code calls cgocallback.
|
||||||
var cgoHasExtraM bool
|
var cgoHasExtraM bool
|
||||||
|
@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVL _crosscall2_ptr(SB), AX
|
|
||||||
MOVL $crosscall2(SB), BX
|
|
||||||
MOVL BX, (AX)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -5,14 +5,6 @@
|
|||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
#include "abi_amd64.h"
|
#include "abi_amd64.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVQ _crosscall2_ptr(SB), AX
|
|
||||||
MOVQ $crosscall2(SB), BX
|
|
||||||
MOVQ BX, (AX)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVW _crosscall2_ptr(SB), R1
|
|
||||||
MOVW $crosscall2(SB), R2
|
|
||||||
MOVW R2, (R1)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -5,14 +5,6 @@
|
|||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
#include "abi_arm64.h"
|
#include "abi_arm64.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVD _crosscall2_ptr(SB), R1
|
|
||||||
MOVD $crosscall2(SB), R2
|
|
||||||
MOVD R2, (R1)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -5,14 +5,6 @@
|
|||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
#include "abi_loong64.h"
|
#include "abi_loong64.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVV _crosscall2_ptr(SB), R5
|
|
||||||
MOVV $crosscall2(SB), R6
|
|
||||||
MOVV R6, (R5)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -6,14 +6,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVV _crosscall2_ptr(SB), R5
|
|
||||||
MOVV $crosscall2(SB), R6
|
|
||||||
MOVV R6, (R5)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -6,14 +6,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVW _crosscall2_ptr(SB), R5
|
|
||||||
MOVW $crosscall2(SB), R6
|
|
||||||
MOVW R6, (R5)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -7,26 +7,6 @@
|
|||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
#include "asm_ppc64x.h"
|
#include "asm_ppc64x.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVD _crosscall2_ptr(SB), R5
|
|
||||||
#ifdef GOARCH_ppc64
|
|
||||||
MOVD $_crosscall2<>(SB), R6
|
|
||||||
#else
|
|
||||||
MOVD $crosscall2(SB), R6
|
|
||||||
#endif
|
|
||||||
MOVD R6, (R5)
|
|
||||||
RET
|
|
||||||
|
|
||||||
#ifdef GO_PPC64X_HAS_FUNCDESC
|
|
||||||
// _crosscall2<> is a function descriptor to the real crosscall2.
|
|
||||||
DATA _crosscall2<>+0(SB)/8, $crosscall2(SB)
|
|
||||||
DATA _crosscall2<>+8(SB)/8, $TOC(SB)
|
|
||||||
DATA _crosscall2<>+16(SB)/8, $0
|
|
||||||
GLOBL _crosscall2<>(SB), NOPTR, $24
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
@ -52,12 +32,8 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
|||||||
|
|
||||||
#ifdef GO_PPC64X_HAS_FUNCDESC
|
#ifdef GO_PPC64X_HAS_FUNCDESC
|
||||||
// Load the real entry address from the first slot of the function descriptor.
|
// Load the real entry address from the first slot of the function descriptor.
|
||||||
// The first argument fn might be null, that means dropm in pthread key destructor.
|
|
||||||
CMP R3, $0
|
|
||||||
BEQ nil_fn
|
|
||||||
MOVD 8(R3), R2
|
MOVD 8(R3), R2
|
||||||
MOVD (R3), R3
|
MOVD (R3), R3
|
||||||
nil_fn:
|
|
||||||
#endif
|
#endif
|
||||||
MOVD R3, FIXED_FRAME+0(R1) // fn unsafe.Pointer
|
MOVD R3, FIXED_FRAME+0(R1) // fn unsafe.Pointer
|
||||||
MOVD R4, FIXED_FRAME+8(R1) // a unsafe.Pointer
|
MOVD R4, FIXED_FRAME+8(R1) // a unsafe.Pointer
|
||||||
|
@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOV _crosscall2_ptr(SB), X7
|
|
||||||
MOV $crosscall2(SB), X8
|
|
||||||
MOV X8, (X7)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
MOVD _crosscall2_ptr(SB), R1
|
|
||||||
MOVD $crosscall2(SB), R2
|
|
||||||
MOVD R2, (R1)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Called by C code generated by cmd/cgo.
|
// Called by C code generated by cmd/cgo.
|
||||||
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
@ -4,8 +4,5 @@
|
|||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
|
|
||||||
UNDEF
|
|
||||||
|
|
||||||
TEXT crosscall2(SB), NOSPLIT, $0
|
TEXT crosscall2(SB), NOSPLIT, $0
|
||||||
UNDEF
|
UNDEF
|
||||||
|
@ -71,42 +71,6 @@ var _cgo_thread_start = &x_cgo_thread_start
|
|||||||
var x_cgo_sys_thread_create byte
|
var x_cgo_sys_thread_create byte
|
||||||
var _cgo_sys_thread_create = &x_cgo_sys_thread_create
|
var _cgo_sys_thread_create = &x_cgo_sys_thread_create
|
||||||
|
|
||||||
// Indicates whether a dummy thread key has been created or not.
|
|
||||||
//
|
|
||||||
// When calling go exported function from C, we register a destructor
|
|
||||||
// callback, for a dummy thread key, by using pthread_key_create.
|
|
||||||
|
|
||||||
//go:cgo_import_static x_cgo_pthread_key_created
|
|
||||||
//go:linkname x_cgo_pthread_key_created x_cgo_pthread_key_created
|
|
||||||
//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created
|
|
||||||
var x_cgo_pthread_key_created byte
|
|
||||||
var _cgo_pthread_key_created = &x_cgo_pthread_key_created
|
|
||||||
|
|
||||||
// Export crosscall2 to a c function pointer variable.
|
|
||||||
// Used to dropm in pthread key destructor, while C thread is exiting.
|
|
||||||
|
|
||||||
//go:cgo_import_static x_crosscall2_ptr
|
|
||||||
//go:linkname x_crosscall2_ptr x_crosscall2_ptr
|
|
||||||
//go:linkname _crosscall2_ptr _crosscall2_ptr
|
|
||||||
var x_crosscall2_ptr byte
|
|
||||||
var _crosscall2_ptr = &x_crosscall2_ptr
|
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
// It's for the runtime package to call at init time.
|
|
||||||
func set_crosscall2()
|
|
||||||
|
|
||||||
//go:linkname _set_crosscall2 runtime.set_crosscall2
|
|
||||||
var _set_crosscall2 = set_crosscall2
|
|
||||||
|
|
||||||
// Store the g into the thread-specific value.
|
|
||||||
// So that pthread_key_destructor will dropm when the thread is exiting.
|
|
||||||
|
|
||||||
//go:cgo_import_static x_cgo_bindm
|
|
||||||
//go:linkname x_cgo_bindm x_cgo_bindm
|
|
||||||
//go:linkname _cgo_bindm _cgo_bindm
|
|
||||||
var x_cgo_bindm byte
|
|
||||||
var _cgo_bindm = &x_cgo_bindm
|
|
||||||
|
|
||||||
// Notifies that the runtime has been initialized.
|
// Notifies that the runtime has been initialized.
|
||||||
//
|
//
|
||||||
// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
|
// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
|
||||||
@ -141,12 +105,3 @@ var _cgo_yield unsafe.Pointer
|
|||||||
|
|
||||||
//go:cgo_export_static _cgo_topofstack
|
//go:cgo_export_static _cgo_topofstack
|
||||||
//go:cgo_export_dynamic _cgo_topofstack
|
//go:cgo_export_dynamic _cgo_topofstack
|
||||||
|
|
||||||
// x_cgo_getstackbound gets the thread's C stack size and
|
|
||||||
// set the G's stack bound based on the stack size.
|
|
||||||
|
|
||||||
//go:cgo_import_static x_cgo_getstackbound
|
|
||||||
//go:linkname x_cgo_getstackbound x_cgo_getstackbound
|
|
||||||
//go:linkname _cgo_getstackbound _cgo_getstackbound
|
|
||||||
var x_cgo_getstackbound byte
|
|
||||||
var _cgo_getstackbound = &x_cgo_getstackbound
|
|
||||||
|
@ -17,14 +17,6 @@ static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
|
|||||||
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static int runtime_init_done;
|
static int runtime_init_done;
|
||||||
|
|
||||||
// pthread_g is a pthread specific key, for storing the g that binded to the C thread.
|
|
||||||
// The registered pthread_key_destructor will dropm, when the pthread-specified value g is not NULL,
|
|
||||||
// while a C thread is exiting.
|
|
||||||
static pthread_key_t pthread_g;
|
|
||||||
static void pthread_key_destructor(void* g);
|
|
||||||
uintptr_t x_cgo_pthread_key_created;
|
|
||||||
void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
|
|
||||||
|
|
||||||
// The context function, used when tracing back C calls into Go.
|
// The context function, used when tracing back C calls into Go.
|
||||||
static void (*cgo_context_function)(struct context_arg*);
|
static void (*cgo_context_function)(struct context_arg*);
|
||||||
|
|
||||||
@ -47,12 +39,6 @@ _cgo_wait_runtime_init_done(void) {
|
|||||||
pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
|
pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The key and x_cgo_pthread_key_created are for the whole program,
|
|
||||||
// whereas the specific and destructor is per thread.
|
|
||||||
if (x_cgo_pthread_key_created == 0 && pthread_key_create(&pthread_g, pthread_key_destructor) == 0) {
|
|
||||||
x_cgo_pthread_key_created = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(iant): For the case of a new C thread calling into Go, such
|
// TODO(iant): For the case of a new C thread calling into Go, such
|
||||||
// as when using -buildmode=c-archive, we know that Go runtime
|
// as when using -buildmode=c-archive, we know that Go runtime
|
||||||
// initialization is complete but we do not know that all Go init
|
// initialization is complete but we do not know that all Go init
|
||||||
@ -75,16 +61,6 @@ _cgo_wait_runtime_init_done(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the g into a thread-specific value associated with the pthread key pthread_g.
|
|
||||||
// And pthread_key_destructor will dropm when the thread is exiting.
|
|
||||||
void x_cgo_bindm(void* g) {
|
|
||||||
// We assume this will always succeed, otherwise, there might be extra M leaking,
|
|
||||||
// when a C thread exits after a cgo call.
|
|
||||||
// We only invoke this function once per thread in runtime.needAndBindM,
|
|
||||||
// and the next calls just reuse the bound m.
|
|
||||||
pthread_setspecific(pthread_g, g);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
x_cgo_notify_runtime_init_done(void* dummy __attribute__ ((unused))) {
|
x_cgo_notify_runtime_init_done(void* dummy __attribute__ ((unused))) {
|
||||||
pthread_mutex_lock(&runtime_init_mu);
|
pthread_mutex_lock(&runtime_init_mu);
|
||||||
@ -134,14 +110,3 @@ _cgo_try_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*p
|
|||||||
}
|
}
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
pthread_key_destructor(void* g) {
|
|
||||||
if (x_crosscall2_ptr != NULL) {
|
|
||||||
// fn == NULL means dropm.
|
|
||||||
// We restore g by using the stored g, before dropm in runtime.cgocallback,
|
|
||||||
// since the g stored in the TLS by Go might be cleared in some platforms,
|
|
||||||
// before this destructor invoked.
|
|
||||||
x_crosscall2_ptr(NULL, g, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -30,9 +30,6 @@ static CRITICAL_SECTION runtime_init_cs;
|
|||||||
static HANDLE runtime_init_wait;
|
static HANDLE runtime_init_wait;
|
||||||
static int runtime_init_done;
|
static int runtime_init_done;
|
||||||
|
|
||||||
uintptr_t x_cgo_pthread_key_created;
|
|
||||||
void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
|
|
||||||
|
|
||||||
// Pre-initialize the runtime synchronization objects
|
// Pre-initialize the runtime synchronization objects
|
||||||
void
|
void
|
||||||
_cgo_preinit_init() {
|
_cgo_preinit_init() {
|
||||||
@ -94,12 +91,6 @@ _cgo_wait_runtime_init_done(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should not be used since x_cgo_pthread_key_created will always be zero.
|
|
||||||
void x_cgo_bindm(void* dummy) {
|
|
||||||
fprintf(stderr, "unexpected cgo_bindm on Windows\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
x_cgo_notify_runtime_init_done(void* dummy) {
|
x_cgo_notify_runtime_init_done(void* dummy) {
|
||||||
_cgo_maybe_run_preinit();
|
_cgo_maybe_run_preinit();
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright 2023 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.
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "libcgo.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
x_cgo_getstackbound(G *g)
|
|
||||||
{
|
|
||||||
void* addr;
|
|
||||||
size_t size;
|
|
||||||
pthread_t p;
|
|
||||||
|
|
||||||
p = pthread_self();
|
|
||||||
addr = pthread_get_stackaddr_np(p); // high address (!)
|
|
||||||
size = pthread_get_stacksize_np(p);
|
|
||||||
g->stacklo = (uintptr)addr - size;
|
|
||||||
// NOTE: don't change g->stackhi. We are called from asmcgocall
|
|
||||||
// which saves the stack depth based on g->stackhi.
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2023 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 unix && !darwin
|
|
||||||
|
|
||||||
#ifndef _GNU_SOURCE // pthread_getattr_np
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "libcgo.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
x_cgo_getstackbound(G *g)
|
|
||||||
{
|
|
||||||
pthread_attr_t attr;
|
|
||||||
void *addr;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) || defined(__sun)
|
|
||||||
pthread_getattr_np(pthread_self(), &attr); // GNU extension
|
|
||||||
pthread_attr_getstack(&attr, &addr, &size); // low address
|
|
||||||
#else
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_getstacksize(&attr, &size);
|
|
||||||
addr = __builtin_frame_address(0) + 4096 - size;
|
|
||||||
#endif
|
|
||||||
pthread_attr_destroy(&attr);
|
|
||||||
|
|
||||||
g->stacklo = (uintptr)addr;
|
|
||||||
// NOTE: don't change g->stackhi. We are called from asmcgocall
|
|
||||||
// which saves the stack depth based on g->stackhi.
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
// Copyright 2023 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.
|
|
||||||
|
|
||||||
#include "libcgo.h"
|
|
||||||
|
|
||||||
void x_cgo_getstackbound(G *g) {} // no-op for now
|
|
@ -51,11 +51,6 @@ extern void (*_cgo_thread_start)(ThreadStart *ts);
|
|||||||
*/
|
*/
|
||||||
extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
|
extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
|
||||||
|
|
||||||
/*
|
|
||||||
* Indicates whether a dummy pthread per-thread variable is allocated.
|
|
||||||
*/
|
|
||||||
extern uintptr_t *_cgo_pthread_key_created;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates the new operating system thread (OS, arch dependent).
|
* Creates the new operating system thread (OS, arch dependent).
|
||||||
*/
|
*/
|
||||||
|
@ -229,9 +229,6 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
|||||||
savedpc := gp.syscallpc
|
savedpc := gp.syscallpc
|
||||||
exitsyscall() // coming out of cgo call
|
exitsyscall() // coming out of cgo call
|
||||||
gp.m.incgo = false
|
gp.m.incgo = false
|
||||||
if gp.m.isextra {
|
|
||||||
gp.m.isExtraInC = false
|
|
||||||
}
|
|
||||||
|
|
||||||
osPreemptExtExit(gp.m)
|
osPreemptExtExit(gp.m)
|
||||||
|
|
||||||
@ -242,9 +239,6 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
|||||||
// This is enforced by checking incgo in the schedule function.
|
// This is enforced by checking incgo in the schedule function.
|
||||||
|
|
||||||
gp.m.incgo = true
|
gp.m.incgo = true
|
||||||
if gp.m.isextra {
|
|
||||||
gp.m.isExtraInC = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if gp.m != checkm {
|
if gp.m != checkm {
|
||||||
throw("m changed unexpectedly in cgocallbackg")
|
throw("m changed unexpectedly in cgocallbackg")
|
||||||
|
@ -777,16 +777,3 @@ func TestCgoSigfwd(t *testing.T) {
|
|||||||
t.Fatalf("expected %q, but got:\n%s", want, got)
|
t.Fatalf("expected %q, but got:\n%s", want, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnsureBindM(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows", "plan9":
|
|
||||||
t.Skipf("skipping bindm test on %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
got := runTestProg(t, "testprogcgo", "EnsureBindM")
|
|
||||||
want := "OK\n"
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("expected %q, got %v", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -208,10 +208,6 @@ func main() {
|
|||||||
|
|
||||||
main_init_done = make(chan bool)
|
main_init_done = make(chan bool)
|
||||||
if iscgo {
|
if iscgo {
|
||||||
if _cgo_pthread_key_created == nil {
|
|
||||||
throw("_cgo_pthread_key_created missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _cgo_thread_start == nil {
|
if _cgo_thread_start == nil {
|
||||||
throw("_cgo_thread_start missing")
|
throw("_cgo_thread_start missing")
|
||||||
}
|
}
|
||||||
@ -226,13 +222,6 @@ func main() {
|
|||||||
if _cgo_notify_runtime_init_done == nil {
|
if _cgo_notify_runtime_init_done == nil {
|
||||||
throw("_cgo_notify_runtime_init_done missing")
|
throw("_cgo_notify_runtime_init_done missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
|
||||||
if set_crosscall2 == nil {
|
|
||||||
throw("set_crosscall2 missing")
|
|
||||||
}
|
|
||||||
set_crosscall2()
|
|
||||||
|
|
||||||
// Start the template thread in case we enter Go from
|
// Start the template thread in case we enter Go from
|
||||||
// a C-created thread and need to create a new thread.
|
// a C-created thread and need to create a new thread.
|
||||||
startTemplateThread()
|
startTemplateThread()
|
||||||
@ -1890,15 +1879,11 @@ func allocm(pp *p, fn func(), id int64) *m {
|
|||||||
// pressed into service as the scheduling stack and current
|
// pressed into service as the scheduling stack and current
|
||||||
// goroutine for the duration of the cgo callback.
|
// goroutine for the duration of the cgo callback.
|
||||||
//
|
//
|
||||||
// It calls dropm to put the m back on the list,
|
// When the callback is done with the m, it calls dropm to
|
||||||
// 1. when the callback is done with the m in non-pthread platforms,
|
// put the m back on the list.
|
||||||
// 2. or when the C thread exiting on pthread platforms.
|
|
||||||
//
|
|
||||||
// The signal argument indicates whether we're called from a signal
|
|
||||||
// handler.
|
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func needm(signal bool) {
|
func needm() {
|
||||||
if (iscgo || GOOS == "windows") && !cgoHasExtraM {
|
if (iscgo || GOOS == "windows") && !cgoHasExtraM {
|
||||||
// Can happen if C/C++ code calls Go from a global ctor.
|
// Can happen if C/C++ code calls Go from a global ctor.
|
||||||
// Can also happen on Windows if a global ctor uses a
|
// Can also happen on Windows if a global ctor uses a
|
||||||
@ -1947,30 +1932,16 @@ func needm(signal bool) {
|
|||||||
osSetupTLS(mp)
|
osSetupTLS(mp)
|
||||||
|
|
||||||
// Install g (= m->g0) and set the stack bounds
|
// Install g (= m->g0) and set the stack bounds
|
||||||
// to match the current stack. If we don't actually know
|
// to match the current stack. We don't actually know
|
||||||
// how big the stack is, like we don't know how big any
|
// how big the stack is, like we don't know how big any
|
||||||
// scheduling stack is, but we assume there's at least 32 kB.
|
// scheduling stack is, but we assume there's at least 32 kB,
|
||||||
// If we can get a more accurate stack bound from pthread,
|
// which is more than enough for us.
|
||||||
// use that.
|
|
||||||
setg(mp.g0)
|
setg(mp.g0)
|
||||||
gp := getg()
|
gp := getg()
|
||||||
gp.stack.hi = getcallersp() + 1024
|
gp.stack.hi = getcallersp() + 1024
|
||||||
gp.stack.lo = getcallersp() - 32*1024
|
gp.stack.lo = getcallersp() - 32*1024
|
||||||
if !signal && _cgo_getstackbound != nil {
|
|
||||||
// Don't adjust if called from the signal handler.
|
|
||||||
// We are on the signal stack, not the pthread stack.
|
|
||||||
// (We could get the stack bounds from sigaltstack, but
|
|
||||||
// we're getting out of the signal handler very soon
|
|
||||||
// anyway. Not worth it.)
|
|
||||||
asmcgocall(_cgo_getstackbound, unsafe.Pointer(gp))
|
|
||||||
}
|
|
||||||
gp.stackguard0 = gp.stack.lo + _StackGuard
|
gp.stackguard0 = gp.stack.lo + _StackGuard
|
||||||
|
|
||||||
// Should mark we are already in Go now.
|
|
||||||
// Otherwise, we may call needm again when we get a signal, before cgocallbackg1,
|
|
||||||
// which means the extram list may be empty, that will cause a deadlock.
|
|
||||||
mp.isExtraInC = false
|
|
||||||
|
|
||||||
// Initialize this thread to use the m.
|
// Initialize this thread to use the m.
|
||||||
asminit()
|
asminit()
|
||||||
minit()
|
minit()
|
||||||
@ -1980,17 +1951,6 @@ func needm(signal bool) {
|
|||||||
sched.ngsys.Add(-1)
|
sched.ngsys.Add(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire an extra m and bind it to the C thread when a pthread key has been created.
|
|
||||||
//
|
|
||||||
//go:nosplit
|
|
||||||
func needAndBindM() {
|
|
||||||
needm(false)
|
|
||||||
|
|
||||||
if _cgo_pthread_key_created != nil && *(*uintptr)(_cgo_pthread_key_created) != 0 {
|
|
||||||
cgoBindM()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newextram allocates m's and puts them on the extra list.
|
// newextram allocates m's and puts them on the extra list.
|
||||||
// It is called with a working local m, so that it can do things
|
// It is called with a working local m, so that it can do things
|
||||||
// like call schedlock and allocate.
|
// like call schedlock and allocate.
|
||||||
@ -2035,8 +1995,6 @@ func oneNewExtraM() {
|
|||||||
gp.m = mp
|
gp.m = mp
|
||||||
mp.curg = gp
|
mp.curg = gp
|
||||||
mp.isextra = true
|
mp.isextra = true
|
||||||
// mark we are in C by default.
|
|
||||||
mp.isExtraInC = true
|
|
||||||
mp.lockedInt++
|
mp.lockedInt++
|
||||||
mp.lockedg.set(gp)
|
mp.lockedg.set(gp)
|
||||||
gp.lockedm.set(mp)
|
gp.lockedm.set(mp)
|
||||||
@ -2069,11 +2027,9 @@ func oneNewExtraM() {
|
|||||||
unlockextra(mp)
|
unlockextra(mp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dropm puts the current m back onto the extra list.
|
|
||||||
//
|
|
||||||
// 1. On systems without pthreads, like Windows
|
|
||||||
// dropm is called when a cgo callback has called needm but is now
|
// dropm is called when a cgo callback has called needm but is now
|
||||||
// done with the callback and returning back into the non-Go thread.
|
// done with the callback and returning back into the non-Go thread.
|
||||||
|
// It puts the current m back onto the extra list.
|
||||||
//
|
//
|
||||||
// The main expense here is the call to signalstack to release the
|
// The main expense here is the call to signalstack to release the
|
||||||
// m's signal stack, and then the call to needm on the next callback
|
// m's signal stack, and then the call to needm on the next callback
|
||||||
@ -2085,18 +2041,15 @@ func oneNewExtraM() {
|
|||||||
// call. These should typically not be scheduling operations, just a few
|
// call. These should typically not be scheduling operations, just a few
|
||||||
// atomics, so the cost should be small.
|
// atomics, so the cost should be small.
|
||||||
//
|
//
|
||||||
// 2. On systems with pthreads
|
// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
|
||||||
// dropm is called while a non-Go thread is exiting.
|
// variable using pthread_key_create. Unlike the pthread keys we already use
|
||||||
// We allocate a pthread per-thread variable using pthread_key_create,
|
// on OS X, this dummy key would never be read by Go code. It would exist
|
||||||
// to register a thread-exit-time destructor.
|
// only so that we could register at thread-exit-time destructor.
|
||||||
// And store the g into a thread-specific value associated with the pthread key,
|
// That destructor would put the m back onto the extra list.
|
||||||
// when first return back to C.
|
// This is purely a performance optimization. The current version,
|
||||||
// So that the destructor would invoke dropm while the non-Go thread is exiting.
|
// in which dropm happens on each cgo call, is still correct too.
|
||||||
// This is much faster since it avoids expensive signal-related syscalls.
|
// We may have to keep the current version on systems with cgo
|
||||||
//
|
// but without pthreads, like Windows.
|
||||||
// NOTE: this always runs without a P, so, nowritebarrierrec required.
|
|
||||||
//
|
|
||||||
//go:nowritebarrierrec
|
|
||||||
func dropm() {
|
func dropm() {
|
||||||
// Clear m and g, and return m to the extra list.
|
// Clear m and g, and return m to the extra list.
|
||||||
// After the call to setg we can only call nosplit functions
|
// After the call to setg we can only call nosplit functions
|
||||||
@ -2128,39 +2081,6 @@ func dropm() {
|
|||||||
msigrestore(sigmask)
|
msigrestore(sigmask)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindm store the g0 of the current m into a thread-specific value.
|
|
||||||
//
|
|
||||||
// We allocate a pthread per-thread variable using pthread_key_create,
|
|
||||||
// to register a thread-exit-time destructor.
|
|
||||||
// We are here setting the thread-specific value of the pthread key, to enable the destructor.
|
|
||||||
// So that the pthread_key_destructor would dropm while the C thread is exiting.
|
|
||||||
//
|
|
||||||
// And the saved g will be used in pthread_key_destructor,
|
|
||||||
// since the g stored in the TLS by Go might be cleared in some platforms,
|
|
||||||
// before the destructor invoked, so, we restore g by the stored g, before dropm.
|
|
||||||
//
|
|
||||||
// We store g0 instead of m, to make the assembly code simpler,
|
|
||||||
// since we need to restore g0 in runtime.cgocallback.
|
|
||||||
//
|
|
||||||
// On systems without pthreads, like Windows, bindm shouldn't be used.
|
|
||||||
//
|
|
||||||
// NOTE: this always runs without a P, so, nowritebarrierrec required.
|
|
||||||
//
|
|
||||||
//go:nosplit
|
|
||||||
//go:nowritebarrierrec
|
|
||||||
func cgoBindM() {
|
|
||||||
if GOOS == "windows" || GOOS == "plan9" {
|
|
||||||
fatal("bindm in unexpected GOOS")
|
|
||||||
}
|
|
||||||
g := getg()
|
|
||||||
if g.m.g0 != g {
|
|
||||||
fatal("the current g is not g0")
|
|
||||||
}
|
|
||||||
if _cgo_bindm != nil {
|
|
||||||
asmcgocall(_cgo_bindm, unsafe.Pointer(g))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A helper function for EnsureDropM.
|
// A helper function for EnsureDropM.
|
||||||
func getm() uintptr {
|
func getm() uintptr {
|
||||||
return uintptr(unsafe.Pointer(getg().m))
|
return uintptr(unsafe.Pointer(getg().m))
|
||||||
|
@ -561,7 +561,6 @@ type m struct {
|
|||||||
printlock int8
|
printlock int8
|
||||||
incgo bool // m is executing a cgo call
|
incgo bool // m is executing a cgo call
|
||||||
isextra bool // m is an extra m
|
isextra bool // m is an extra m
|
||||||
isExtraInC bool // m is an extra m that is not executing Go code
|
|
||||||
freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
|
freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
|
||||||
fastrand uint64
|
fastrand uint64
|
||||||
needextram bool
|
needextram bool
|
||||||
|
@ -435,7 +435,7 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||||||
c := &sigctxt{info, ctx}
|
c := &sigctxt{info, ctx}
|
||||||
gp := sigFetchG(c)
|
gp := sigFetchG(c)
|
||||||
setg(gp)
|
setg(gp)
|
||||||
if gp == nil || (gp.m != nil && gp.m.isExtraInC) {
|
if gp == nil {
|
||||||
if sig == _SIGPROF {
|
if sig == _SIGPROF {
|
||||||
// Some platforms (Linux) have per-thread timers, which we use in
|
// Some platforms (Linux) have per-thread timers, which we use in
|
||||||
// combination with the process-wide timer. Avoid double-counting.
|
// combination with the process-wide timer. Avoid double-counting.
|
||||||
@ -458,18 +458,7 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.fixsigcode(sig)
|
c.fixsigcode(sig)
|
||||||
// Set g to nil here and badsignal will use g0 by needm.
|
|
||||||
// TODO: reuse the current m here by using the gsignal and adjustSignalStack,
|
|
||||||
// since the current g maybe a normal goroutine and actually running on the signal stack,
|
|
||||||
// it may hit stack split that is not expected here.
|
|
||||||
if gp != nil {
|
|
||||||
setg(nil)
|
|
||||||
}
|
|
||||||
badsignal(uintptr(sig), c)
|
badsignal(uintptr(sig), c)
|
||||||
// Restore g
|
|
||||||
if gp != nil {
|
|
||||||
setg(gp)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +574,7 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
|
|||||||
|
|
||||||
// sp is not within gsignal stack, g0 stack, or sigaltstack. Bad.
|
// sp is not within gsignal stack, g0 stack, or sigaltstack. Bad.
|
||||||
setg(nil)
|
setg(nil)
|
||||||
needm(true)
|
needm()
|
||||||
if st.ss_flags&_SS_DISABLE != 0 {
|
if st.ss_flags&_SS_DISABLE != 0 {
|
||||||
noSignalStack(sig)
|
noSignalStack(sig)
|
||||||
} else {
|
} else {
|
||||||
@ -1058,7 +1047,7 @@ func badsignal(sig uintptr, c *sigctxt) {
|
|||||||
exit(2)
|
exit(2)
|
||||||
*(*uintptr)(unsafe.Pointer(uintptr(123))) = 2
|
*(*uintptr)(unsafe.Pointer(uintptr(123))) = 2
|
||||||
}
|
}
|
||||||
needm(true)
|
needm()
|
||||||
if !sigsend(uint32(sig)) {
|
if !sigsend(uint32(sig)) {
|
||||||
// A foreign thread received the signal sig, and the
|
// A foreign thread received the signal sig, and the
|
||||||
// Go code does not want to handle it.
|
// Go code does not want to handle it.
|
||||||
@ -1126,9 +1115,8 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
|
|||||||
// (1) we weren't in VDSO page,
|
// (1) we weren't in VDSO page,
|
||||||
// (2) we were in a goroutine (i.e., m.curg != nil), and
|
// (2) we were in a goroutine (i.e., m.curg != nil), and
|
||||||
// (3) we weren't in CGO.
|
// (3) we weren't in CGO.
|
||||||
// (4) we weren't in dropped extra m.
|
|
||||||
gp := sigFetchG(c)
|
gp := sigFetchG(c)
|
||||||
if gp != nil && gp.m != nil && gp.m.curg != nil && !gp.m.isExtraInC && !gp.m.incgo {
|
if gp != nil && gp.m != nil && gp.m.curg != nil && !gp.m.incgo {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,9 +237,6 @@ func noEscapePtr[T any](p *T) *T {
|
|||||||
// cgocallback is not called from Go, only from crosscall2.
|
// cgocallback is not called from Go, only from crosscall2.
|
||||||
// This in turn calls cgocallbackg, which is where we'll find
|
// This in turn calls cgocallbackg, which is where we'll find
|
||||||
// pointer-declared arguments.
|
// pointer-declared arguments.
|
||||||
//
|
|
||||||
// When fn is nil (frame is saved g), call dropm instead,
|
|
||||||
// this is used when the C thread is exiting.
|
|
||||||
func cgocallback(fn, frame, ctxt uintptr)
|
func cgocallback(fn, frame, ctxt uintptr)
|
||||||
|
|
||||||
func gogo(buf *gobuf)
|
func gogo(buf *gobuf)
|
||||||
|
89
src/runtime/testdata/testprogcgo/bindm.go
vendored
89
src/runtime/testdata/testprogcgo/bindm.go
vendored
@ -1,89 +0,0 @@
|
|||||||
// Copyright 2023 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 !plan9 && !windows
|
|
||||||
|
|
||||||
// Test that callbacks from C to Go in the same C-thread always get the same m.
|
|
||||||
// Make sure the extra M bind to the C-thread.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
extern void GoCheckBindM();
|
|
||||||
|
|
||||||
#define CTHREADS 2
|
|
||||||
#define CHECKCALLS 100
|
|
||||||
|
|
||||||
static void* checkBindMThread(void* thread) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < CHECKCALLS; i++) {
|
|
||||||
GoCheckBindM((uintptr_t)thread);
|
|
||||||
usleep(1);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CheckBindM() {
|
|
||||||
int i;
|
|
||||||
pthread_t s[CTHREADS];
|
|
||||||
|
|
||||||
for (i = 0; i < CTHREADS; i++) {
|
|
||||||
pthread_create(&s[i], NULL, checkBindMThread, &s[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < CTHREADS; i++) {
|
|
||||||
pthread_join(s[i], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mutex = sync.Mutex{}
|
|
||||||
cThreadToM = map[uintptr]uintptr{}
|
|
||||||
started = atomic.Uint32{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// same as CTHREADS in C, make sure all the C threads are actually started.
|
|
||||||
const cThreadNum = 2
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
register("EnsureBindM", EnsureBindM)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export GoCheckBindM
|
|
||||||
func GoCheckBindM(thread uintptr) {
|
|
||||||
// Wait all threads start
|
|
||||||
if started.Load() != cThreadNum {
|
|
||||||
// Only once for each thread, since it will wait all threads start.
|
|
||||||
started.Add(1)
|
|
||||||
for started.Load() < cThreadNum {
|
|
||||||
runtime.Gosched()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m := runtime_getm_for_test()
|
|
||||||
mutex.Lock()
|
|
||||||
defer mutex.Unlock()
|
|
||||||
if savedM, ok := cThreadToM[thread]; ok && savedM != m {
|
|
||||||
fmt.Printf("m == %x want %x\n", m, savedM)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
cThreadToM[thread] = m
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnsureBindM() {
|
|
||||||
C.CheckBindM()
|
|
||||||
fmt.Println("OK")
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user