mirror of
https://github.com/golang/go.git
synced 2026-04-03 01:40:30 +09:00
runtime/cgo: deduplicate x_cgo_init and crosscall1
Most platforms share the same implementation for x_cgo_init and crosscall1. Solaris diverges too much and is left for a future CL. Cq-Include-Trybots: luci.golang.try:gotip-freebsd-amd64,gotip-darwin-amd64_14,gotip-darwin-arm64_15,gotip-netbsd-arm64,gotip-openbsd-ppc64,gotip-solaris-amd64,gotip-linux-ppc64_power10 Change-Id: Ib2eeb6456caa5c055e1ac1907c2fdf63db58dafc Reviewed-on: https://go-review.googlesource.com/c/go/+/708035 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Junyang Shao <shaojunyang@google.com>
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
// Copyright 2009 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 <string.h> /* for strerror */
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2009 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 <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,41 +1,16 @@
|
||||
// Copyright 2009 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 freebsd && (386 || arm || arm64 || riscv64)
|
||||
|
||||
#include <machine/sysarch.h>
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
#ifdef ARM_TP_ADDRESS
|
||||
// ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
|
||||
// and is known to runtime.read_tls_fallback. Verify it with
|
||||
// cpp.
|
||||
#if ARM_TP_ADDRESS != 0xffff1000
|
||||
#error Wrong ARM_TP_ADDRESS!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, ts.g);
|
||||
return nil;
|
||||
}
|
||||
// Copyright 2009 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 freebsd
|
||||
|
||||
#include <machine/sysarch.h>
|
||||
|
||||
#ifdef ARM_TP_ADDRESS
|
||||
// ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
|
||||
// and is known to runtime.read_tls_fallback. Verify it with
|
||||
// cpp.
|
||||
#if ARM_TP_ADDRESS != 0xffff1000
|
||||
#error Wrong ARM_TP_ADDRESS!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2009 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 <errno.h>
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
{
|
||||
uintptr *pbounds;
|
||||
|
||||
// Deal with memory sanitizer/clang interaction.
|
||||
// See gcc_linux_amd64.c for details.
|
||||
setg_gcc = setg;
|
||||
pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
|
||||
if (pbounds == NULL) {
|
||||
fatalf("malloc failed: %s", strerror(errno));
|
||||
}
|
||||
_cgo_set_stacklo(g, pbounds);
|
||||
free(pbounds);
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
_cgo_tsan_acquire();
|
||||
free(v);
|
||||
_cgo_tsan_release();
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
@@ -18,27 +17,16 @@
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#endif
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
static void
|
||||
threadentry_platform(void)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
darwin_arm_init_thread_exception_port();
|
||||
#endif
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
// init_working_dir sets the current working directory to the app root.
|
||||
// By default ios/arm64 processes start in "/".
|
||||
static void
|
||||
@@ -101,16 +89,15 @@ init_working_dir()
|
||||
|
||||
#endif // TARGET_OS_IPHONE
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
static void
|
||||
init_platform()
|
||||
{
|
||||
//fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
darwin_arm_init_mach_exception_handler();
|
||||
darwin_arm_init_thread_exception_port();
|
||||
init_working_dir();
|
||||
#endif
|
||||
}
|
||||
|
||||
void (*x_cgo_init_platform)(void) = init_platform;
|
||||
void (*x_cgo_threadentry_platform)(void) = threadentry_platform;
|
||||
@@ -83,30 +83,6 @@ _cgo_wait_runtime_init_done(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _cgo_set_stacklo sets g->stacklo based on the stack size.
|
||||
// This is common code called from x_cgo_init, which is itself
|
||||
// called by rt0_go in the runtime package.
|
||||
void _cgo_set_stacklo(G *g, uintptr *pbounds)
|
||||
{
|
||||
uintptr bounds[2];
|
||||
|
||||
// pbounds can be passed in by the caller; see gcc_linux_amd64.c.
|
||||
if (pbounds == NULL) {
|
||||
pbounds = &bounds[0];
|
||||
}
|
||||
|
||||
x_cgo_getstackbound(pbounds);
|
||||
|
||||
g->stacklo = *pbounds;
|
||||
|
||||
// Sanity check the results now, rather than getting a
|
||||
// morestack on g0 crash.
|
||||
if (g->stacklo >= g->stackhi) {
|
||||
fprintf(stderr, "runtime/cgo: bad stack bounds: lo=%p hi=%p\n", (void*)(g->stacklo), (void*)(g->stackhi));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2009 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 linux && (386 || arm || loong64 || mips || mipsle || mips64 || mips64le || riscv64)
|
||||
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
{
|
||||
setg_gcc = setg;
|
||||
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
|
||||
if (x_cgo_inittls) {
|
||||
x_cgo_inittls(tlsg, tlsbase);
|
||||
}
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2009 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 <errno.h>
|
||||
#include <string.h> // strerror
|
||||
#include <stdlib.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
// This will be set in gcc_android.c for android-specific customization.
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
{
|
||||
uintptr *pbounds;
|
||||
|
||||
/* The memory sanitizer distributed with versions of clang
|
||||
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||
may return an address that is later overwritten by the msan
|
||||
library. Avoid this problem by forcing a call to malloc
|
||||
here, before we ever call malloc.
|
||||
|
||||
This is only required for the memory sanitizer, so it's
|
||||
unfortunate that we always run it. It should be possible
|
||||
to remove this when we no longer care about versions of
|
||||
clang before 3.8. The test for this is
|
||||
misc/cgo/testsanitizers.
|
||||
|
||||
GCC works hard to eliminate a seemingly unnecessary call to
|
||||
malloc, so we actually use the memory we allocate. */
|
||||
|
||||
setg_gcc = setg;
|
||||
pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
|
||||
if (pbounds == NULL) {
|
||||
fatalf("malloc failed: %s", strerror(errno));
|
||||
}
|
||||
_cgo_set_stacklo(g, pbounds);
|
||||
free(pbounds);
|
||||
|
||||
if (x_cgo_inittls) {
|
||||
x_cgo_inittls(tlsg, tlsbase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
_cgo_tsan_acquire();
|
||||
free(v);
|
||||
_cgo_tsan_release();
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2015 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 <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
{
|
||||
uintptr *pbounds;
|
||||
|
||||
/* The memory sanitizer distributed with versions of clang
|
||||
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||
may return an address that is later overwritten by the msan
|
||||
library. Avoid this problem by forcing a call to malloc
|
||||
here, before we ever call malloc.
|
||||
|
||||
This is only required for the memory sanitizer, so it's
|
||||
unfortunate that we always run it. It should be possible
|
||||
to remove this when we no longer care about versions of
|
||||
clang before 3.8. The test for this is
|
||||
misc/cgo/testsanitizers.
|
||||
|
||||
GCC works hard to eliminate a seemingly unnecessary call to
|
||||
malloc, so we actually use the memory we allocate. */
|
||||
|
||||
setg_gcc = setg;
|
||||
pbounds = (uintptr*)malloc(2 * sizeof(uintptr));
|
||||
if (pbounds == NULL) {
|
||||
fatalf("malloc failed: %s", strerror(errno));
|
||||
}
|
||||
_cgo_set_stacklo(g, pbounds);
|
||||
free(pbounds);
|
||||
|
||||
if (x_cgo_inittls) {
|
||||
x_cgo_inittls(tlsg, tlsbase);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2016 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 <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall_s390x(void (*fn)(void), void *g);
|
||||
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
// Save g for this thread in C TLS
|
||||
setg_gcc((void*)ts.g);
|
||||
|
||||
crosscall_s390x(ts.fn, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,44 +1,26 @@
|
||||
// Copyright 2009 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 netbsd && (386 || amd64 || arm || arm64)
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
stack_t ss;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
// On NetBSD, a new thread inherits the signal stack of the
|
||||
// creating thread. That confuses minit, so we remove that
|
||||
// signal stack here before calling the regular mstart. It's
|
||||
// a bit baroque to remove a signal stack here only to add one
|
||||
// in minit, but it's a simple change that keeps NetBSD
|
||||
// working like other OS's. At this point all signals are
|
||||
// blocked, so there is no race.
|
||||
memset(&ss, 0, sizeof ss);
|
||||
ss.ss_flags = SS_DISABLE;
|
||||
sigaltstack(&ss, nil);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, ts.g);
|
||||
return nil;
|
||||
}
|
||||
// Copyright 2009 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 netbsd
|
||||
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static void
|
||||
threadentry_platform(void)
|
||||
{
|
||||
// On NetBSD, a new thread inherits the signal stack of the
|
||||
// creating thread. That confuses minit, so we remove that
|
||||
// signal stack here before calling the regular mstart. It's
|
||||
// a bit baroque to remove a signal stack here only to add one
|
||||
// in minit, but it's a simple change that keeps NetBSD
|
||||
// working like other OS's. At this point all signals are
|
||||
// blocked, so there is no race.
|
||||
stack_t ss;
|
||||
memset(&ss, 0, sizeof ss);
|
||||
ss.ss_flags = SS_DISABLE;
|
||||
sigaltstack(&ss, NULL);
|
||||
}
|
||||
|
||||
void (*x_cgo_threadentry_platform)(void) = threadentry_platform;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2009 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 openbsd && (386 || arm || amd64 || arm64 || riscv64)
|
||||
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*))
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
free(v);
|
||||
|
||||
crosscall1(ts.fn, setg_gcc, ts.g);
|
||||
return nil;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2014 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 ppc64 || ppc64le
|
||||
|
||||
#include <string.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
|
||||
{
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g, NULL);
|
||||
}
|
||||
|
||||
extern void crosscall_ppc64(void (*fn)(void), void *g);
|
||||
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
_cgo_tsan_acquire();
|
||||
free(v);
|
||||
_cgo_tsan_release();
|
||||
|
||||
// Save g for this thread in C TLS
|
||||
setg_gcc((void*)ts.g);
|
||||
|
||||
crosscall_ppc64(ts.fn, (void*)ts.g);
|
||||
return nil;
|
||||
}
|
||||
118
src/runtime/cgo/gcc_unix.c
Normal file
118
src/runtime/cgo/gcc_unix.c
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2009 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 && !solaris
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "libcgo.h"
|
||||
#include "libcgo_unix.h"
|
||||
|
||||
// Platform-specific hooks.
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((weak));
|
||||
void (*x_cgo_init_platform)(void) __attribute__((weak));
|
||||
void (*x_cgo_threadentry_platform)(void) __attribute__((weak));
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
// _cgo_set_stacklo sets g->stacklo based on the stack size.
|
||||
// This is common code called from x_cgo_init, which is itself
|
||||
// called by rt0_go in the runtime package.
|
||||
static void
|
||||
_cgo_set_stacklo(G *g)
|
||||
{
|
||||
uintptr bounds[2];
|
||||
|
||||
x_cgo_getstackbound(bounds);
|
||||
|
||||
g->stacklo = bounds[0];
|
||||
|
||||
// Sanity check the results now, rather than getting a
|
||||
// morestack on g0 crash.
|
||||
if (g->stacklo >= g->stackhi) {
|
||||
fprintf(stderr, "runtime/cgo: bad stack bounds: lo=%p hi=%p\n", (void*)(g->stacklo), (void*)(g->stackhi));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clang_init()
|
||||
{
|
||||
#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
|
||||
/* The memory sanitizer distributed with versions of clang
|
||||
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||
may return an address that is later overwritten by the msan
|
||||
library. Avoid this problem by forcing a call to malloc
|
||||
here, before we ever call malloc.
|
||||
|
||||
This is only required for the memory sanitizer, so it's
|
||||
unfortunate that we always run it. It should be possible
|
||||
to remove this when we no longer care about versions of
|
||||
clang before 3.8. The test for this is
|
||||
cmd/cgo/internal/testsanitizers . */
|
||||
uintptr *p;
|
||||
p = (uintptr*)malloc(sizeof(uintptr));
|
||||
if (p == NULL) {
|
||||
fatalf("malloc failed: %s", strerror(errno));
|
||||
}
|
||||
/* GCC works hard to eliminate a seemingly unnecessary call to
|
||||
malloc, so we actually touch the memory we allocate. */
|
||||
((volatile char *)p)[0] = 0;
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
{
|
||||
clang_init();
|
||||
setg_gcc = setg;
|
||||
_cgo_set_stacklo(g);
|
||||
|
||||
if (x_cgo_inittls) {
|
||||
x_cgo_inittls(tlsg, tlsbase);
|
||||
}
|
||||
if (x_cgo_init_platform) {
|
||||
x_cgo_init_platform();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: change crosscall_ppc64 and crosscall_s390x so that it matches crosscall1
|
||||
// signature and behavior.
|
||||
#if defined(__powerpc64__)
|
||||
extern void crosscall_ppc64(void (*fn)(void), void *g);
|
||||
#elif defined(__s390x__)
|
||||
extern void crosscall_s390x(void (*fn)(void), void *g);
|
||||
#else
|
||||
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
|
||||
#endif
|
||||
|
||||
void*
|
||||
threadentry(void *v)
|
||||
{
|
||||
ThreadStart ts;
|
||||
|
||||
ts = *(ThreadStart*)v;
|
||||
_cgo_tsan_acquire();
|
||||
free(v);
|
||||
_cgo_tsan_release();
|
||||
|
||||
if (x_cgo_threadentry_platform != NULL) {
|
||||
x_cgo_threadentry_platform();
|
||||
}
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
// Save g for this thread in C TLS
|
||||
setg_gcc((void*)ts.g);
|
||||
crosscall_ppc64(ts.fn, (void*)ts.g);
|
||||
#elif defined(__s390x__)
|
||||
// Save g for this thread in C TLS
|
||||
setg_gcc((void*)ts.g);
|
||||
crosscall_s390x(ts.fn, (void*)ts.g);
|
||||
#else
|
||||
crosscall1(ts.fn, setg_gcc, ts.g);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
* Initialize g->stacklo.
|
||||
*/
|
||||
extern void _cgo_set_stacklo(G *, uintptr *);
|
||||
|
||||
/*
|
||||
* Call pthread_create, retrying on EAGAIN.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user