mirror of
https://github.com/golang/go
synced 2024-09-23 21:30:18 -06:00
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: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
8c31f40a4c
commit
7cba779cea
@ -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) }
|
||||
|
87
misc/cgo/test/issue18146.go
Normal file
87
misc/cgo/test/issue18146.go
Normal file
@ -0,0 +1,87 @@
|
||||
// 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);
|
||||
|
||||
|
8
src/runtime/cgo/libcgo_unix.h
Normal file
8
src/runtime/cgo/libcgo_unix.h
Normal file
@ -0,0 +1,8 @@
|
||||
// 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*);
|
Loading…
Reference in New Issue
Block a user