aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2025-09-30 14:54:16 +0200
committerQuim Muntal <quimmuntal@gmail.com>2026-02-13 08:07:09 -0800
commit65b9017c0e955ad57fb42c3bf82aa0ff51ddbff5 (patch)
tree5c746c95203f2485f02c48c1cd960e5eeaf0f94d /src/runtime
parentc9cbeb0a1b08a9830a3d2d4abe0c2108e52f7647 (diff)
downloadgo-65b9017c0e955ad57fb42c3bf82aa0ff51ddbff5.tar.xz
runtime/cgo: deduplicate pthreads-related functions
Almost all pthread-related functions are exactly the same for Unix OSes. Their implementation can be shared, taking into account the small differences using standard predefined macros. Cq-Include-Trybots: luci.golang.try:gotip-freebsd-amd64,gotip-darwin-amd64_14,gotip-darwin-arm64_15,gotip-netbsd-arm64,gotip-openbsd-amd64,gotip-openbsd-ppc64,gotip-solaris-amd64,gotip-linux-ppc64_power10 Change-Id: I8bee25f0619a5b315439cf12d94312c36c3e5a73 Reviewed-on: https://go-review.googlesource.com/c/go/+/707955 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/cgo/gcc_darwin_amd64.c33
-rw-r--r--src/runtime/cgo/gcc_darwin_arm64.c34
-rw-r--r--src/runtime/cgo/gcc_dragonfly_amd64.c34
-rw-r--r--src/runtime/cgo/gcc_fatalf.c2
-rw-r--r--src/runtime/cgo/gcc_freebsd.c33
-rw-r--r--src/runtime/cgo/gcc_freebsd_amd64.c33
-rw-r--r--src/runtime/cgo/gcc_libinit.c41
-rw-r--r--src/runtime/cgo/gcc_libinit_windows.c2
-rw-r--r--src/runtime/cgo/gcc_linux.c32
-rw-r--r--src/runtime/cgo/gcc_linux_amd64.c31
-rw-r--r--src/runtime/cgo/gcc_linux_arm64.c32
-rw-r--r--src/runtime/cgo/gcc_linux_s390x.c32
-rw-r--r--src/runtime/cgo/gcc_netbsd.c32
-rw-r--r--src/runtime/cgo/gcc_openbsd.c33
-rw-r--r--src/runtime/cgo/gcc_ppc64x.c32
-rw-r--r--src/runtime/cgo/gcc_solaris_amd64.c39
-rw-r--r--src/runtime/cgo/gcc_stack_darwin.c25
-rw-r--r--src/runtime/cgo/gcc_stack_unix.c48
-rw-r--r--src/runtime/cgo/gcc_stack_windows.c7
-rw-r--r--src/runtime/cgo/libcgo_unix.h4
-rw-r--r--src/runtime/cgo/pthread_unix.c138
21 files changed, 158 insertions, 539 deletions
diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c
index 1ffbbd75f2..0a9198e29f 100644
--- a/src/runtime/cgo/gcc_darwin_amd64.c
+++ b/src/runtime/cgo/gcc_darwin_amd64.c
@@ -3,12 +3,9 @@
// license that can be found in the LICENSE file.
#include <string.h> /* for strerror */
-#include <pthread.h>
-#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -19,36 +16,8 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- size = pthread_get_stacksize_np(pthread_self());
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, size);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
- abort();
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
index e800e9303c..e502851fc1 100644
--- a/src/runtime/cgo/gcc_darwin_arm64.c
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file.
#include <limits.h>
-#include <pthread.h>
-#include <signal.h>
#include <string.h> /* for strerror */
#include <sys/param.h>
#include <unistd.h>
@@ -20,40 +18,10 @@
#include <CoreFoundation/CFString.h>
#endif
-static void *threadentry(void*);
static void (*setg_gcc)(void*);
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- //fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- size = pthread_get_stacksize_np(pthread_self());
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, size);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
- abort();
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c
index 646e9e653a..4851b2a6a0 100644
--- a/src/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/runtime/cgo/gcc_dragonfly_amd64.c
@@ -2,15 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <sys/types.h>
-#include <sys/signalvar.h>
-#include <pthread.h>
-#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -20,35 +15,8 @@ x_cgo_init(G *g, void (*setg)(void*))
_cgo_set_stacklo(g, NULL);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- SIGFILLSET(ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
-
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_fatalf.c b/src/runtime/cgo/gcc_fatalf.c
index 822c0150bd..8d46e9187d 100644
--- a/src/runtime/cgo/gcc_fatalf.c
+++ b/src/runtime/cgo/gcc_fatalf.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build aix || (!android && linux) || dragonfly || freebsd || netbsd || openbsd || solaris
+//go:build unix && !android
#include <stdarg.h>
#include <stdio.h>
diff --git a/src/runtime/cgo/gcc_freebsd.c b/src/runtime/cgo/gcc_freebsd.c
index 1cc582a3bb..b5adecc5f1 100644
--- a/src/runtime/cgo/gcc_freebsd.c
+++ b/src/runtime/cgo/gcc_freebsd.c
@@ -4,11 +4,7 @@
//go:build freebsd && (386 || arm || arm64 || riscv64)
-#include <sys/types.h>
-#include <sys/signalvar.h>
#include <machine/sysarch.h>
-#include <pthread.h>
-#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
@@ -22,7 +18,6 @@
#endif
#endif
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -32,34 +27,8 @@ x_cgo_init(G *g, void (*setg)(void*))
_cgo_set_stacklo(g, NULL);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- SIGFILLSET(ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c
index ec23a00fee..0fa81495a3 100644
--- a/src/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/runtime/cgo/gcc_freebsd_amd64.c
@@ -2,16 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <sys/types.h>
#include <errno.h>
-#include <sys/signalvar.h>
-#include <pthread.h>
-#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -30,34 +25,8 @@ x_cgo_init(G *g, void (*setg)(void*))
free(pbounds);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- SIGFILLSET(ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 05998fadf8..4b163c2d19 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -12,11 +12,8 @@
#pragma GCC diagnostic ignored "-Watomic-alignment"
#include <pthread.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h> // strerror
-#include <time.h>
#include "libcgo.h"
#include "libcgo_unix.h"
@@ -41,21 +38,6 @@ static void (*cgo_context_function)(struct cgoContextArg*);
// The symbolizer function, used when symbolizing C frames.
static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
-void
-x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
- pthread_attr_t attr;
- pthread_t p;
- int err;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- err = _cgo_try_pthread_create(&p, &attr, func, arg);
- if (err != 0) {
- fprintf(stderr, "pthread_create failed: %s", strerror(err));
- abort();
- }
-}
-
uintptr_t
_cgo_wait_runtime_init_done(void) {
void (*pfn)(struct cgoContextArg*);
@@ -208,29 +190,6 @@ void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
_cgo_tsan_release();
}
-// _cgo_try_pthread_create retries pthread_create if it fails with
-// EAGAIN.
-int
-_cgo_try_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
- int tries;
- int err;
- struct timespec ts;
-
- for (tries = 0; tries < 20; tries++) {
- err = pthread_create(thread, attr, pfn, arg);
- if (err == 0) {
- return 0;
- }
- if (err != EAGAIN) {
- return err;
- }
- ts.tv_sec = 0;
- ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
- nanosleep(&ts, nil);
- }
- return EAGAIN;
-}
-
static void
pthread_key_destructor(void* g) {
if (x_crosscall2_ptr != NULL) {
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
index 7e7ff3e667..d2082e0916 100644
--- a/src/runtime/cgo/gcc_libinit_windows.c
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -212,3 +212,5 @@ void _cgo_beginthread(unsigned long (__stdcall *func)(void*), void* arg) {
fprintf(stderr, "runtime: failed to create new OS thread (%lu)\n", GetLastError());
abort();
}
+
+void x_cgo_getstackbound(uintptr bounds[2]) {} // no-op for now
diff --git a/src/runtime/cgo/gcc_linux.c b/src/runtime/cgo/gcc_linux.c
index fbdb5e652a..cdccbf3454 100644
--- a/src/runtime/cgo/gcc_linux.c
+++ b/src/runtime/cgo/gcc_linux.c
@@ -4,14 +4,10 @@
//go:build linux && (386 || arm || loong64 || mips || mipsle || mips64 || mips64le || riscv64)
-#include <pthread.h>
#include <string.h>
-#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void *threadentry(void*);
-
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*);
@@ -27,34 +23,8 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
}
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c
index c81fde2887..35c4f76457 100644
--- a/src/runtime/cgo/gcc_linux_amd64.c
+++ b/src/runtime/cgo/gcc_linux_amd64.c
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <pthread.h>
#include <errno.h>
#include <string.h> // strerror
-#include <signal.h>
#include <stdlib.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
// This will be set in gcc_android.c for android-specific customization.
@@ -50,34 +47,8 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
index ce46804ba2..bd4b36a553 100644
--- a/src/runtime/cgo/gcc_linux_arm64.c
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -2,47 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <pthread.h>
#include <errno.h>
#include <string.h>
-#include <signal.h>
#include <stdlib.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void *threadentry(void*);
-
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*);
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_linux_s390x.c b/src/runtime/cgo/gcc_linux_s390x.c
index 1fae4e7d44..8f055e3087 100644
--- a/src/runtime/cgo/gcc_linux_s390x.c
+++ b/src/runtime/cgo/gcc_linux_s390x.c
@@ -2,14 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <pthread.h>
#include <string.h>
-#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void *threadentry(void*);
-
void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
static void (*setg_gcc)(void*);
@@ -20,35 +16,9 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
_cgo_set_stacklo(g, NULL);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall_s390x(void (*fn)(void), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_netbsd.c b/src/runtime/cgo/gcc_netbsd.c
index 98b629e805..c8c0969108 100644
--- a/src/runtime/cgo/gcc_netbsd.c
+++ b/src/runtime/cgo/gcc_netbsd.c
@@ -4,14 +4,11 @@
//go:build netbsd && (386 || amd64 || arm || arm64)
-#include <sys/types.h>
-#include <pthread.h>
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -21,35 +18,8 @@ x_cgo_init(G *g, void (*setg)(void*))
_cgo_set_stacklo(g, NULL);
}
-
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_openbsd.c b/src/runtime/cgo/gcc_openbsd.c
index b31c312f59..166b9cd756 100644
--- a/src/runtime/cgo/gcc_openbsd.c
+++ b/src/runtime/cgo/gcc_openbsd.c
@@ -4,14 +4,10 @@
//go:build openbsd && (386 || arm || amd64 || arm64 || riscv64)
-#include <sys/types.h>
-#include <pthread.h>
-#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -21,35 +17,8 @@ x_cgo_init(G *g, void (*setg)(void*))
_cgo_set_stacklo(g, NULL);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
-
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_ppc64x.c b/src/runtime/cgo/gcc_ppc64x.c
index e1a5c14ff9..6f5a0bd9ad 100644
--- a/src/runtime/cgo/gcc_ppc64x.c
+++ b/src/runtime/cgo/gcc_ppc64x.c
@@ -4,14 +4,10 @@
//go:build ppc64 || ppc64le
-#include <pthread.h>
#include <string.h>
-#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void *threadentry(void*);
-
void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
static void (*setg_gcc)(void*);
@@ -22,35 +18,9 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
_cgo_set_stacklo(g, NULL);
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_getstacksize(&attr, &size);
- // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
- ts->g->stackhi = size;
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall_ppc64(void (*fn)(void), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c
index 9b106a63ea..492522bdfb 100644
--- a/src/runtime/cgo/gcc_solaris_amd64.c
+++ b/src/runtime/cgo/gcc_solaris_amd64.c
@@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <pthread.h>
#include <string.h>
-#include <signal.h>
#include <ucontext.h>
#include "libcgo.h"
#include "libcgo_unix.h"
-static void* threadentry(void*);
static void (*setg_gcc)(void*);
void
@@ -35,42 +32,8 @@ x_cgo_init(G *g, void (*setg)(void*))
}
}
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- sigset_t ign, oset;
- pthread_t p;
- void *base;
- size_t size;
- int err;
-
- sigfillset(&ign);
- pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
- pthread_attr_init(&attr);
-
- if (pthread_attr_getstack(&attr, &base, &size) != 0)
- perror("runtime/cgo: pthread_attr_getstack failed");
- if (size == 0) {
- ts->g->stackhi = 2 << 20;
- if (pthread_attr_setstack(&attr, NULL, ts->g->stackhi) != 0)
- perror("runtime/cgo: pthread_attr_setstack failed");
- } else {
- ts->g->stackhi = size;
- }
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
-
- pthread_sigmask(SIG_SETMASK, &oset, nil);
-
- if (err != 0) {
- fatalf("pthread_create failed: %s", strerror(err));
- }
-}
-
extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
-static void*
+void*
threadentry(void *v)
{
ThreadStart ts;
diff --git a/src/runtime/cgo/gcc_stack_darwin.c b/src/runtime/cgo/gcc_stack_darwin.c
deleted file mode 100644
index 28364c7420..0000000000
--- a/src/runtime/cgo/gcc_stack_darwin.c
+++ /dev/null
@@ -1,25 +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(uintptr bounds[2])
-{
- 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);
-
- // bounds points into the Go stack. TSAN can't see the synchronization
- // in Go around stack reuse.
- _cgo_tsan_acquire();
- bounds[0] = (uintptr)addr - size;
- bounds[1] = (uintptr)addr;
- _cgo_tsan_release();
-}
diff --git a/src/runtime/cgo/gcc_stack_unix.c b/src/runtime/cgo/gcc_stack_unix.c
deleted file mode 100644
index 9550cd7839..0000000000
--- a/src/runtime/cgo/gcc_stack_unix.c
+++ /dev/null
@@ -1,48 +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(uintptr bounds[2])
-{
- pthread_attr_t attr;
- void *addr;
- size_t size;
-
- // Needed before pthread_getattr_np, too, since before glibc 2.32
- // it did not call pthread_attr_init in all cases (see #65625).
- pthread_attr_init(&attr);
-#if defined(__GLIBC__) || defined(__BIONIC__) || (defined(__sun) && !defined(__illumos__))
- // pthread_getattr_np is a GNU extension supported in glibc.
- // Solaris is not glibc but does support pthread_getattr_np
- // (and the fallback doesn't work...). Illumos does not.
- pthread_getattr_np(pthread_self(), &attr); // GNU extension
- pthread_attr_getstack(&attr, &addr, &size); // low address
-#elif defined(__illumos__)
- pthread_attr_get_np(pthread_self(), &attr);
- pthread_attr_getstack(&attr, &addr, &size); // low address
-#else
- // We don't know how to get the current stacks, leave it as
- // 0 and the caller will use an estimate based on the current
- // SP.
- addr = 0;
- size = 0;
-#endif
- pthread_attr_destroy(&attr);
-
- // bounds points into the Go stack. TSAN can't see the synchronization
- // in Go around stack reuse.
- _cgo_tsan_acquire();
- bounds[0] = (uintptr)addr;
- bounds[1] = (uintptr)addr + size;
- _cgo_tsan_release();
-}
diff --git a/src/runtime/cgo/gcc_stack_windows.c b/src/runtime/cgo/gcc_stack_windows.c
deleted file mode 100644
index d798cc77d1..0000000000
--- a/src/runtime/cgo/gcc_stack_windows.c
+++ /dev/null
@@ -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(uintptr bounds[2]) {} // no-op for now
diff --git a/src/runtime/cgo/libcgo_unix.h b/src/runtime/cgo/libcgo_unix.h
index b8f8d30d30..5ce0224523 100644
--- a/src/runtime/cgo/libcgo_unix.h
+++ b/src/runtime/cgo/libcgo_unix.h
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <pthread.h>
+
/*
* Initialize g->stacklo.
*/
@@ -18,3 +20,5 @@ extern int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(
*/
extern int _cgo_openbsd_try_pthread_create(int (*)(pthread_t*, const pthread_attr_t*, void *(*pfn)(void*), void*),
pthread_t*, const pthread_attr_t*, void* (*)(void*), void* arg);
+
+extern void* threadentry(void*);
diff --git a/src/runtime/cgo/pthread_unix.c b/src/runtime/cgo/pthread_unix.c
new file mode 100644
index 0000000000..7b5248817a
--- /dev/null
+++ b/src/runtime/cgo/pthread_unix.c
@@ -0,0 +1,138 @@
+// Copyright 2025 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
+
+#ifndef _GNU_SOURCE // pthread_getattr_np
+#define _GNU_SOURCE
+#endif
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+#if defined(__APPLE__)
+ // Copy stack size from parent thread instead of using the
+ // non-main thread default stack size.
+ size = pthread_get_stacksize_np(pthread_self());
+ pthread_attr_setstacksize(&attr, size);
+#else
+ pthread_attr_getstacksize(&attr, &size);
+#endif
+
+#if defined(__sun)
+ // Solaris can report 0 stack size, fix it.
+ if (size == 0) {
+ size = 2 << 20;
+ if (pthread_attr_setstacksize(&attr, size) != 0) {
+ perror("runtime/cgo: pthread_attr_setstacksize failed");
+ }
+ }
+#endif
+
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+ pthread_attr_t attr;
+ pthread_t p;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ err = _cgo_try_pthread_create(&p, &attr, func, arg);
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+void
+x_cgo_getstackbound(uintptr bounds[2])
+{
+ pthread_attr_t attr;
+ void *addr;
+ size_t size;
+
+ // Needed before pthread_getattr_np, too, since before glibc 2.32
+ // it did not call pthread_attr_init in all cases (see #65625).
+ pthread_attr_init(&attr);
+#if defined(__APPLE__)
+ // On macOS/iOS, use the non-portable pthread_get_stackaddr_np
+ // and pthread_get_stacksize_np APIs (high address + size).
+ addr = pthread_get_stackaddr_np(pthread_self());
+ size = pthread_get_stacksize_np(pthread_self());
+ addr = (void*)((uintptr)addr - size); // convert to low address
+#elif defined(__GLIBC__) || defined(__BIONIC__) || (defined(__sun) && !defined(__illumos__))
+ // pthread_getattr_np is a GNU extension supported in glibc.
+ // Solaris is not glibc but does support pthread_getattr_np
+ // (and the fallback doesn't work...). Illumos does not.
+ pthread_getattr_np(pthread_self(), &attr); // GNU extension
+ pthread_attr_getstack(&attr, &addr, &size); // low address
+#elif defined(__illumos__)
+ pthread_attr_get_np(pthread_self(), &attr);
+ pthread_attr_getstack(&attr, &addr, &size); // low address
+#else
+ // We don't know how to get the current stacks, leave it as
+ // 0 and the caller will use an estimate based on the current
+ // SP.
+ addr = 0;
+ size = 0;
+#endif
+ pthread_attr_destroy(&attr);
+
+ // bounds points into the Go stack. TSAN can't see the synchronization
+ // in Go around stack reuse.
+ _cgo_tsan_acquire();
+ bounds[0] = (uintptr)addr;
+ bounds[1] = (uintptr)addr + size;
+ _cgo_tsan_release();
+}
+
+// _cgo_try_pthread_create retries pthread_create if it fails with EAGAIN.
+int
+_cgo_try_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
+ int tries;
+ int err;
+ struct timespec ts;
+
+ for (tries = 0; tries < 20; tries++) {
+ err = pthread_create(thread, attr, pfn, arg);
+ if (err == 0) {
+ return 0;
+ }
+ if (err != EAGAIN) {
+ return err;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
+ nanosleep(&ts, nil);
+ }
+ return EAGAIN;
+}