diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c index 955b81da0b..dda9a1e2d8 100644 --- a/src/runtime/cgo/gcc_darwin_amd64.c +++ b/src/runtime/cgo/gcc_darwin_amd64.c @@ -14,12 +14,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - size_t size; - setg_gcc = setg; - - size = pthread_get_stacksize_np(pthread_self()); - g->stacklo = (uintptr)&size - size + 4096; + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c index 5b77a4294a..f1344de8e1 100644 --- a/src/runtime/cgo/gcc_darwin_arm64.c +++ b/src/runtime/cgo/gcc_darwin_arm64.c @@ -127,12 +127,9 @@ init_working_dir() void x_cgo_init(G *g, void (*setg)(void*)) { - size_t size; - //fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR setg_gcc = setg; - size = pthread_get_stacksize_np(pthread_self()); - g->stacklo = (uintptr)&size - size + 4096; + _cgo_set_stacklo(g, NULL); #if TARGET_OS_IPHONE darwin_arm_init_mach_exception_handler(); diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c index 0003414bf8..b5ae411d3d 100644 --- a/src/runtime/cgo/gcc_dragonfly_amd64.c +++ b/src/runtime/cgo/gcc_dragonfly_amd64.c @@ -16,14 +16,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_freebsd_386.c b/src/runtime/cgo/gcc_freebsd_386.c index 9097a2af90..e56fad6a5b 100644 --- a/src/runtime/cgo/gcc_freebsd_386.c +++ b/src/runtime/cgo/gcc_freebsd_386.c @@ -16,14 +16,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c index 6071ec3909..d3c133fc76 100644 --- a/src/runtime/cgo/gcc_freebsd_amd64.c +++ b/src/runtime/cgo/gcc_freebsd_amd64.c @@ -18,7 +18,6 @@ void x_cgo_init(G *g, void (*setg)(void*)) { pthread_attr_t *attr; - size_t size; // Deal with memory sanitizer/clang interaction. // See gcc_linux_amd64.c for details. @@ -27,10 +26,7 @@ x_cgo_init(G *g, void (*setg)(void*)) if (attr == NULL) { fatalf("malloc failed: %s", strerror(errno)); } - pthread_attr_init(attr); - pthread_attr_getstacksize(attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(attr); + _cgo_set_stacklo(g, attr); free(attr); } diff --git a/src/runtime/cgo/gcc_freebsd_arm.c b/src/runtime/cgo/gcc_freebsd_arm.c index 5f89978379..af398f8320 100644 --- a/src/runtime/cgo/gcc_freebsd_arm.c +++ b/src/runtime/cgo/gcc_freebsd_arm.c @@ -27,14 +27,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_freebsd_arm64.c b/src/runtime/cgo/gcc_freebsd_arm64.c index dd8f888290..01f6a31c32 100644 --- a/src/runtime/cgo/gcc_freebsd_arm64.c +++ b/src/runtime/cgo/gcc_freebsd_arm64.c @@ -17,14 +17,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_freebsd_riscv64.c b/src/runtime/cgo/gcc_freebsd_riscv64.c index 6ce5e656ab..7fe7972d2d 100644 --- a/src/runtime/cgo/gcc_freebsd_riscv64.c +++ b/src/runtime/cgo/gcc_freebsd_riscv64.c @@ -17,14 +17,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c index 0b2cc25277..f6c930209e 100644 --- a/src/runtime/cgo/gcc_libinit.c +++ b/src/runtime/cgo/gcc_libinit.c @@ -82,6 +82,34 @@ _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, pthread_attr_t *pattr) +{ + pthread_attr_t attr; + size_t size; + + // pattr can be passed in by the caller; see gcc_linux_amd64.c. + if (pattr == NULL) { + pattr = &attr; + } + + pthread_attr_init(pattr); + pthread_attr_getstacksize(pattr, &size); + + g->stacklo = (uintptr)(__builtin_frame_address(0)) - size + 4096; + + // 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(); + } + + pthread_attr_destroy(pattr); +} + // 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) { diff --git a/src/runtime/cgo/gcc_linux_386.c b/src/runtime/cgo/gcc_linux_386.c index 0ce9359616..13a5aa90de 100644 --- a/src/runtime/cgo/gcc_linux_386.c +++ b/src/runtime/cgo/gcc_linux_386.c @@ -17,14 +17,8 @@ void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common)); void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c index fb164c1a1d..34b70e77ca 100644 --- a/src/runtime/cgo/gcc_linux_amd64.c +++ b/src/runtime/cgo/gcc_linux_amd64.c @@ -20,7 +20,6 @@ void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { pthread_attr_t *attr; - size_t size; /* The memory sanitizer distributed with versions of clang before 3.8 has a bug: if you call mmap before malloc, mmap @@ -42,12 +41,7 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) if (attr == NULL) { fatalf("malloc failed: %s", strerror(errno)); } - pthread_attr_init(attr); - pthread_attr_getstacksize(attr, &size); - g->stacklo = (uintptr)__builtin_frame_address(0) - size + 4096; - if (g->stacklo >= g->stackhi) - fatalf("bad stack bounds: lo=%p hi=%p\n", g->stacklo, g->stackhi); - pthread_attr_destroy(attr); + _cgo_set_stacklo(g, attr); free(attr); if (x_cgo_inittls) { diff --git a/src/runtime/cgo/gcc_linux_arm.c b/src/runtime/cgo/gcc_linux_arm.c index 5e97a9ed31..6a7e3bea04 100644 --- a/src/runtime/cgo/gcc_linux_arm.c +++ b/src/runtime/cgo/gcc_linux_arm.c @@ -54,14 +54,8 @@ threadentry(void *v) void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c index dac45e418b..8b822fe8a3 100644 --- a/src/runtime/cgo/gcc_linux_arm64.c +++ b/src/runtime/cgo/gcc_linux_arm64.c @@ -57,7 +57,6 @@ void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { pthread_attr_t *attr; - size_t size; /* The memory sanitizer distributed with versions of clang before 3.8 has a bug: if you call mmap before malloc, mmap @@ -79,10 +78,7 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) if (attr == NULL) { fatalf("malloc failed: %s", strerror(errno)); } - pthread_attr_init(attr); - pthread_attr_getstacksize(attr, &size); - g->stacklo = (uintptr)&size - size + 4096; - pthread_attr_destroy(attr); + _cgo_set_stacklo(g, attr); free(attr); if (x_cgo_inittls) { diff --git a/src/runtime/cgo/gcc_linux_loong64.c b/src/runtime/cgo/gcc_linux_loong64.c index 96a06eb960..b7363ccd96 100644 --- a/src/runtime/cgo/gcc_linux_loong64.c +++ b/src/runtime/cgo/gcc_linux_loong64.c @@ -54,14 +54,8 @@ threadentry(void *v) void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_mips64x.c b/src/runtime/cgo/gcc_linux_mips64x.c index c059fd1255..6f4b52e2b0 100644 --- a/src/runtime/cgo/gcc_linux_mips64x.c +++ b/src/runtime/cgo/gcc_linux_mips64x.c @@ -56,14 +56,8 @@ threadentry(void *v) void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_mipsx.c b/src/runtime/cgo/gcc_linux_mipsx.c index 218b8fd6e1..f6470d66dc 100644 --- a/src/runtime/cgo/gcc_linux_mipsx.c +++ b/src/runtime/cgo/gcc_linux_mipsx.c @@ -56,15 +56,9 @@ threadentry(void *v) void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_riscv64.c b/src/runtime/cgo/gcc_linux_riscv64.c index 99c2866de4..ee4981104a 100644 --- a/src/runtime/cgo/gcc_linux_riscv64.c +++ b/src/runtime/cgo/gcc_linux_riscv64.c @@ -54,14 +54,8 @@ threadentry(void *v) void x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); if (x_cgo_inittls) { x_cgo_inittls(tlsg, tlsbase); diff --git a/src/runtime/cgo/gcc_linux_s390x.c b/src/runtime/cgo/gcc_linux_s390x.c index bb600482e1..4b9f76c39e 100644 --- a/src/runtime/cgo/gcc_linux_s390x.c +++ b/src/runtime/cgo/gcc_linux_s390x.c @@ -16,14 +16,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*), void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_netbsd_386.c b/src/runtime/cgo/gcc_netbsd_386.c index 5495f0fd72..b8cb5d0bc9 100644 --- a/src/runtime/cgo/gcc_netbsd_386.c +++ b/src/runtime/cgo/gcc_netbsd_386.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_netbsd_amd64.c b/src/runtime/cgo/gcc_netbsd_amd64.c index 9f4b031a08..94ff1f52bf 100644 --- a/src/runtime/cgo/gcc_netbsd_amd64.c +++ b/src/runtime/cgo/gcc_netbsd_amd64.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_netbsd_arm.c b/src/runtime/cgo/gcc_netbsd_arm.c index b0c80ea7c4..ca370f69c3 100644 --- a/src/runtime/cgo/gcc_netbsd_arm.c +++ b/src/runtime/cgo/gcc_netbsd_arm.c @@ -16,14 +16,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_netbsd_arm64.c b/src/runtime/cgo/gcc_netbsd_arm64.c index 694116ce70..c6961f5cbe 100644 --- a/src/runtime/cgo/gcc_netbsd_arm64.c +++ b/src/runtime/cgo/gcc_netbsd_arm64.c @@ -16,14 +16,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c index 127a1b683b..092da4a6d2 100644 --- a/src/runtime/cgo/gcc_openbsd_386.c +++ b/src/runtime/cgo/gcc_openbsd_386.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c index 09d2750f3a..3f0b771c74 100644 --- a/src/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/runtime/cgo/gcc_openbsd_amd64.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_openbsd_arm.c b/src/runtime/cgo/gcc_openbsd_arm.c index 9a5757f0ad..2aec207e36 100644 --- a/src/runtime/cgo/gcc_openbsd_arm.c +++ b/src/runtime/cgo/gcc_openbsd_arm.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_openbsd_arm64.c b/src/runtime/cgo/gcc_openbsd_arm64.c index abf9f6660c..a9af8a2d1f 100644 --- a/src/runtime/cgo/gcc_openbsd_arm64.c +++ b/src/runtime/cgo/gcc_openbsd_arm64.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_openbsd_mips64.c b/src/runtime/cgo/gcc_openbsd_mips64.c index 79f039a373..fbf7ceb0c5 100644 --- a/src/runtime/cgo/gcc_openbsd_mips64.c +++ b/src/runtime/cgo/gcc_openbsd_mips64.c @@ -15,14 +15,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*)) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_ppc64x.c b/src/runtime/cgo/gcc_ppc64x.c index bfdcf65014..98a654957b 100644 --- a/src/runtime/cgo/gcc_ppc64x.c +++ b/src/runtime/cgo/gcc_ppc64x.c @@ -18,14 +18,8 @@ static void (*setg_gcc)(void*); void x_cgo_init(G *g, void (*setg)(void*), void **tlsbase) { - pthread_attr_t attr; - size_t size; - setg_gcc = setg; - pthread_attr_init(&attr); - pthread_attr_getstacksize(&attr, &size); - g->stacklo = (uintptr)&attr - size + 4096; - pthread_attr_destroy(&attr); + _cgo_set_stacklo(g, NULL); } void diff --git a/src/runtime/cgo/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c index e89e844b1e..ebd945b2e3 100644 --- a/src/runtime/cgo/gcc_solaris_amd64.c +++ b/src/runtime/cgo/gcc_solaris_amd64.c @@ -27,6 +27,13 @@ x_cgo_init(G *g, void (*setg)(void*)) // See golang.org/issue/12210. if(ctx.uc_stack.ss_size < 1024*1024) g->stacklo -= 1024*1024 - ctx.uc_stack.ss_size; + + // 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(); + } } void diff --git a/src/runtime/cgo/libcgo_unix.h b/src/runtime/cgo/libcgo_unix.h index a56a366f23..6d30769542 100644 --- a/src/runtime/cgo/libcgo_unix.h +++ b/src/runtime/cgo/libcgo_unix.h @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +/* + * Initialize g->stacklo. + */ +extern void _cgo_set_stacklo(G *, pthread_attr_t*); + /* * Call pthread_create, retrying on EAGAIN. */