Commit 7cba779c authored by Ian Lance Taylor's avatar Ian Lance Taylor

runtime/cgo: retry pthread_create on EAGAIN

Update #18146.

Change-Id: Ib447aabae9f203a8b61fb8c984b57d8e2bfe69c2
Reviewed-on: https://go-review.googlesource.com/33894
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 8c31f40a
......@@ -10,3 +10,4 @@ import "testing"
func TestSigaltstack(t *testing.T) { testSigaltstack(t) }
func TestSigprocmask(t *testing.T) { testSigprocmask(t) }
func Test18146(t *testing.T) { test18146(t) }
// 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.
// +build !windows
// Issue 18146: pthread_create failure during syscall.Exec.
package cgotest
import "C"
import (
"bytes"
"crypto/md5"
"os"
"os/exec"
"runtime"
"syscall"
"testing"
)
func test18146(t *testing.T) {
switch runtime.GOOS {
case "darwin", "openbsd":
t.Skip("skipping on %s; issue 18146", runtime.GOOS)
}
attempts := 1000
threads := 4
if testing.Short() {
attempts = 100
}
if os.Getenv("test18146") == "exec" {
runtime.GOMAXPROCS(1)
for n := threads; n > 0; n-- {
go func() {
for {
_ = md5.Sum([]byte("Hello, !"))
}
}()
}
runtime.GOMAXPROCS(threads)
argv := append(os.Args, "-test.run=NoSuchTestExists")
if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
t.Fatal(err)
}
}
var cmds []*exec.Cmd
defer func() {
for _, cmd := range cmds {
cmd.Process.Kill()
}
}()
args := append(append([]string(nil), os.Args[1:]...), "-test.run=Test18146")
for n := attempts; n > 0; n-- {
cmd := exec.Command(os.Args[0], args...)
cmd.Env = append(os.Environ(), "test18146=exec")
buf := bytes.NewBuffer(nil)
cmd.Stdout = buf
cmd.Stderr = buf
if err := cmd.Start(); err != nil {
t.Error(err)
return
}
cmds = append(cmds, cmd)
}
failures := 0
for _, cmd := range cmds {
err := cmd.Wait()
if err == nil {
continue
}
t.Errorf("syscall.Exec failed: %v\n%s", err, cmd.Stdout)
failures++
}
if failures > 0 {
t.Logf("Failed %v of %v attempts.", failures, len(cmds))
}
}
......@@ -6,6 +6,7 @@
#include <pthread.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static pthread_key_t k1;
......@@ -123,7 +124,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -6,6 +6,7 @@
#include <pthread.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static pthread_key_t k1;
......@@ -94,7 +95,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -10,6 +10,7 @@
#include <unistd.h>
#include "libcgo.h"
#include "libcgo_unix.h"
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFString.h>
......@@ -65,7 +66,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -11,6 +11,7 @@
#include <stdlib.h>
#include "libcgo.h"
#include "libcgo_unix.h"
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFString.h>
......@@ -67,7 +68,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -8,6 +8,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -8,6 +8,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -8,6 +8,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -9,6 +9,7 @@
#include <signal.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
......@@ -58,7 +59,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -6,10 +6,13 @@
// +build darwin dragonfly freebsd linux netbsd solaris
#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"
static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
......@@ -21,7 +24,7 @@ static void (*cgo_context_function)(struct context_arg*);
void
x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
pthread_t p;
int err = pthread_create(&p, NULL, func, arg);
int err = _cgo_try_pthread_create(&p, NULL, func, arg);
if (err != 0) {
fprintf(stderr, "pthread_create failed: %s", strerror(err));
abort();
......@@ -84,3 +87,23 @@ void (*(_cgo_get_context_function(void)))(struct context_arg*) {
pthread_mutex_unlock(&runtime_init_mu);
return ret;
}
// _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 != EAGAIN) {
return err;
}
ts.tv_sec = 0;
ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
nanosleep(&ts, nil);
}
return EAGAIN;
}
......@@ -6,6 +6,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -53,7 +54,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -8,6 +8,7 @@
#include <signal.h>
#include <stdlib.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -70,7 +71,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -6,6 +6,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -33,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -6,6 +6,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -33,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -10,6 +10,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -37,7 +38,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -8,6 +8,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -43,7 +44,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -6,6 +6,7 @@
#include <string.h>
#include <signal.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -41,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -7,6 +7,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -41,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -7,6 +7,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -7,6 +7,7 @@
#include <signal.h>
#include <string.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void *threadentry(void*);
......@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -37,6 +37,7 @@
#include <mach/thread_status.h>
#include "libcgo.h"
#include "libcgo_unix.h"
uintptr_t x_cgo_panicmem;
......@@ -201,7 +202,7 @@ darwin_arm_init_mach_exception_handler()
uintptr_t port_set = (uintptr_t)mach_exception_handler_port_set;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)port_set);
ret = _cgo_try_pthread_create(&thr, &attr, mach_exception_handler, (void*)port_set);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
......@@ -7,6 +7,7 @@
#include <signal.h>
#include <ucontext.h>
#include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*);
static void (*setg_gcc)(void*);
......@@ -53,7 +54,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackhi = size;
}
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
err = pthread_create(&p, &attr, threadentry, ts);
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
......
// 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.
/*
* Call pthread_create, retrying on EAGAIN.
*/
int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment