Skip to content

Commit 7cba779

Browse files
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 8c31f40 commit 7cba779

24 files changed

+160
-21
lines changed

misc/cgo/test/cgo_unix_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ import "testing"
1010

1111
func TestSigaltstack(t *testing.T) { testSigaltstack(t) }
1212
func TestSigprocmask(t *testing.T) { testSigprocmask(t) }
13+
func Test18146(t *testing.T) { test18146(t) }

misc/cgo/test/issue18146.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build !windows
6+
7+
// Issue 18146: pthread_create failure during syscall.Exec.
8+
9+
package cgotest
10+
11+
import "C"
12+
13+
import (
14+
"bytes"
15+
"crypto/md5"
16+
"os"
17+
"os/exec"
18+
"runtime"
19+
"syscall"
20+
"testing"
21+
)
22+
23+
func test18146(t *testing.T) {
24+
switch runtime.GOOS {
25+
case "darwin", "openbsd":
26+
t.Skip("skipping on %s; issue 18146", runtime.GOOS)
27+
}
28+
29+
attempts := 1000
30+
threads := 4
31+
32+
if testing.Short() {
33+
attempts = 100
34+
}
35+
36+
if os.Getenv("test18146") == "exec" {
37+
runtime.GOMAXPROCS(1)
38+
for n := threads; n > 0; n-- {
39+
go func() {
40+
for {
41+
_ = md5.Sum([]byte("Hello, !"))
42+
}
43+
}()
44+
}
45+
runtime.GOMAXPROCS(threads)
46+
argv := append(os.Args, "-test.run=NoSuchTestExists")
47+
if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
48+
t.Fatal(err)
49+
}
50+
}
51+
52+
var cmds []*exec.Cmd
53+
defer func() {
54+
for _, cmd := range cmds {
55+
cmd.Process.Kill()
56+
}
57+
}()
58+
59+
args := append(append([]string(nil), os.Args[1:]...), "-test.run=Test18146")
60+
for n := attempts; n > 0; n-- {
61+
cmd := exec.Command(os.Args[0], args...)
62+
cmd.Env = append(os.Environ(), "test18146=exec")
63+
buf := bytes.NewBuffer(nil)
64+
cmd.Stdout = buf
65+
cmd.Stderr = buf
66+
if err := cmd.Start(); err != nil {
67+
t.Error(err)
68+
return
69+
}
70+
cmds = append(cmds, cmd)
71+
}
72+
73+
failures := 0
74+
for _, cmd := range cmds {
75+
err := cmd.Wait()
76+
if err == nil {
77+
continue
78+
}
79+
80+
t.Errorf("syscall.Exec failed: %v\n%s", err, cmd.Stdout)
81+
failures++
82+
}
83+
84+
if failures > 0 {
85+
t.Logf("Failed %v of %v attempts.", failures, len(cmds))
86+
}
87+
}

src/runtime/cgo/gcc_darwin_386.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <pthread.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void* threadentry(void*);
1112
static pthread_key_t k1;
@@ -123,7 +124,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
123124
pthread_attr_getstacksize(&attr, &size);
124125
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
125126
ts->g->stackhi = size;
126-
err = pthread_create(&p, &attr, threadentry, ts);
127+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
127128

128129
pthread_sigmask(SIG_SETMASK, &oset, nil);
129130

src/runtime/cgo/gcc_darwin_amd64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <pthread.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void* threadentry(void*);
1112
static pthread_key_t k1;
@@ -94,7 +95,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
9495
pthread_attr_getstacksize(&attr, &size);
9596
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
9697
ts->g->stackhi = size;
97-
err = pthread_create(&p, &attr, threadentry, ts);
98+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
9899

99100
pthread_sigmask(SIG_SETMASK, &oset, nil);
100101

src/runtime/cgo/gcc_darwin_arm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <unistd.h>
1111

1212
#include "libcgo.h"
13+
#include "libcgo_unix.h"
1314

1415
#include <CoreFoundation/CFBundle.h>
1516
#include <CoreFoundation/CFString.h>
@@ -65,7 +66,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
6566
pthread_attr_getstacksize(&attr, &size);
6667
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
6768
ts->g->stackhi = size;
68-
err = pthread_create(&p, &attr, threadentry, ts);
69+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
6970

7071
pthread_sigmask(SIG_SETMASK, &oset, nil);
7172

src/runtime/cgo/gcc_darwin_arm64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdlib.h>
1212

1313
#include "libcgo.h"
14+
#include "libcgo_unix.h"
1415

1516
#include <CoreFoundation/CFBundle.h>
1617
#include <CoreFoundation/CFString.h>
@@ -67,7 +68,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
6768
pthread_attr_getstacksize(&attr, &size);
6869
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
6970
ts->g->stackhi = size;
70-
err = pthread_create(&p, &attr, threadentry, ts);
71+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
7172

7273
pthread_sigmask(SIG_SETMASK, &oset, nil);
7374

src/runtime/cgo/gcc_dragonfly_amd64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <signal.h>
99
#include <string.h>
1010
#include "libcgo.h"
11+
#include "libcgo_unix.h"
1112

1213
static void* threadentry(void*);
1314
static void (*setg_gcc)(void*);
@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
4243

4344
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
4445
ts->g->stackhi = size;
45-
err = pthread_create(&p, &attr, threadentry, ts);
46+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4647

4748
pthread_sigmask(SIG_SETMASK, &oset, nil);
4849

src/runtime/cgo/gcc_freebsd_386.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <signal.h>
99
#include <string.h>
1010
#include "libcgo.h"
11+
#include "libcgo_unix.h"
1112

1213
static void* threadentry(void*);
1314
static void (*setg_gcc)(void*);
@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
4243
pthread_attr_getstacksize(&attr, &size);
4344
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
4445
ts->g->stackhi = size;
45-
err = pthread_create(&p, &attr, threadentry, ts);
46+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4647

4748
pthread_sigmask(SIG_SETMASK, &oset, nil);
4849

src/runtime/cgo/gcc_freebsd_amd64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <signal.h>
99
#include <string.h>
1010
#include "libcgo.h"
11+
#include "libcgo_unix.h"
1112

1213
static void* threadentry(void*);
1314
static void (*setg_gcc)(void*);
@@ -42,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
4243

4344
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
4445
ts->g->stackhi = size;
45-
err = pthread_create(&p, &attr, threadentry, ts);
46+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4647

4748
pthread_sigmask(SIG_SETMASK, &oset, nil);
4849

src/runtime/cgo/gcc_freebsd_arm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <signal.h>
1010
#include <string.h>
1111
#include "libcgo.h"
12+
#include "libcgo_unix.h"
1213

1314
#ifdef ARM_TP_ADDRESS
1415
// ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
@@ -58,7 +59,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
5859
pthread_attr_getstacksize(&attr, &size);
5960
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
6061
ts->g->stackhi = size;
61-
err = pthread_create(&p, &attr, threadentry, ts);
62+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
6263

6364
pthread_sigmask(SIG_SETMASK, &oset, nil);
6465

src/runtime/cgo/gcc_libinit.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
// +build darwin dragonfly freebsd linux netbsd solaris
77

88
#include <pthread.h>
9+
#include <errno.h>
910
#include <stdio.h>
1011
#include <stdlib.h>
1112
#include <string.h> // strerror
13+
#include <time.h>
1214
#include "libcgo.h"
15+
#include "libcgo_unix.h"
1316

1417
static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
1518
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
@@ -21,7 +24,7 @@ static void (*cgo_context_function)(struct context_arg*);
2124
void
2225
x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
2326
pthread_t p;
24-
int err = pthread_create(&p, NULL, func, arg);
27+
int err = _cgo_try_pthread_create(&p, NULL, func, arg);
2528
if (err != 0) {
2629
fprintf(stderr, "pthread_create failed: %s", strerror(err));
2730
abort();
@@ -84,3 +87,23 @@ void (*(_cgo_get_context_function(void)))(struct context_arg*) {
8487
pthread_mutex_unlock(&runtime_init_mu);
8588
return ret;
8689
}
90+
91+
// _cgo_try_pthread_create retries pthread_create if it fails with
92+
// EAGAIN.
93+
int
94+
_cgo_try_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
95+
int tries;
96+
int err;
97+
struct timespec ts;
98+
99+
for (tries = 0; tries < 20; tries++) {
100+
err = pthread_create(thread, attr, pfn, arg);
101+
if (err != EAGAIN) {
102+
return err;
103+
}
104+
ts.tv_sec = 0;
105+
ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
106+
nanosleep(&ts, nil);
107+
}
108+
return EAGAIN;
109+
}

src/runtime/cgo/gcc_linux_386.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void *threadentry(void*);
1112
static void (*setg_gcc)(void*);
@@ -53,7 +54,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
5354
pthread_attr_getstacksize(&attr, &size);
5455
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
5556
ts->g->stackhi = size;
56-
err = pthread_create(&p, &attr, threadentry, ts);
57+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
5758

5859
pthread_sigmask(SIG_SETMASK, &oset, nil);
5960

src/runtime/cgo/gcc_linux_amd64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <signal.h>
99
#include <stdlib.h>
1010
#include "libcgo.h"
11+
#include "libcgo_unix.h"
1112

1213
static void* threadentry(void*);
1314
static void (*setg_gcc)(void*);
@@ -70,7 +71,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
7071
pthread_attr_getstacksize(&attr, &size);
7172
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
7273
ts->g->stackhi = size;
73-
err = pthread_create(&p, &attr, threadentry, ts);
74+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
7475

7576
pthread_sigmask(SIG_SETMASK, &oset, nil);
7677

src/runtime/cgo/gcc_linux_arm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void *threadentry(void*);
1112

@@ -33,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
3334
pthread_attr_getstacksize(&attr, &size);
3435
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
3536
ts->g->stackhi = size;
36-
err = pthread_create(&p, &attr, threadentry, ts);
37+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
3738

3839
pthread_sigmask(SIG_SETMASK, &oset, nil);
3940

src/runtime/cgo/gcc_linux_arm64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void *threadentry(void*);
1112

@@ -33,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
3334
pthread_attr_getstacksize(&attr, &size);
3435
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
3536
ts->g->stackhi = size;
36-
err = pthread_create(&p, &attr, threadentry, ts);
37+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
3738

3839
pthread_sigmask(SIG_SETMASK, &oset, nil);
3940

src/runtime/cgo/gcc_linux_mips64x.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <string.h>
1111
#include <signal.h>
1212
#include "libcgo.h"
13+
#include "libcgo_unix.h"
1314

1415
static void *threadentry(void*);
1516

@@ -37,7 +38,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
3738
pthread_attr_getstacksize(&attr, &size);
3839
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
3940
ts->g->stackhi = size;
40-
err = pthread_create(&p, &attr, threadentry, ts);
41+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4142

4243
pthread_sigmask(SIG_SETMASK, &oset, nil);
4344

src/runtime/cgo/gcc_linux_ppc64x.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <string.h>
99
#include <signal.h>
1010
#include "libcgo.h"
11+
#include "libcgo_unix.h"
1112

1213
static void *threadentry(void*);
1314

@@ -43,7 +44,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
4344
pthread_attr_getstacksize(&attr, &size);
4445
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
4546
ts->g->stackhi = size;
46-
err = pthread_create(&p, &attr, threadentry, ts);
47+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4748

4849
pthread_sigmask(SIG_SETMASK, &oset, nil);
4950

src/runtime/cgo/gcc_linux_s390x.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string.h>
77
#include <signal.h>
88
#include "libcgo.h"
9+
#include "libcgo_unix.h"
910

1011
static void *threadentry(void*);
1112

@@ -41,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
4142
pthread_attr_getstacksize(&attr, &size);
4243
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
4344
ts->g->stackhi = size;
44-
err = pthread_create(&p, &attr, threadentry, ts);
45+
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
4546

4647
pthread_sigmask(SIG_SETMASK, &oset, nil);
4748

0 commit comments

Comments
 (0)