]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/cgo: retry pthread_create on EAGAIN
authorIan Lance Taylor <iant@golang.org>
Fri, 2 Dec 2016 23:32:55 +0000 (15:32 -0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 5 Dec 2016 18:46:18 +0000 (18:46 +0000)
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>
24 files changed:
misc/cgo/test/cgo_unix_test.go
misc/cgo/test/issue18146.go [new file with mode: 0644]
src/runtime/cgo/gcc_darwin_386.c
src/runtime/cgo/gcc_darwin_amd64.c
src/runtime/cgo/gcc_darwin_arm.c
src/runtime/cgo/gcc_darwin_arm64.c
src/runtime/cgo/gcc_dragonfly_amd64.c
src/runtime/cgo/gcc_freebsd_386.c
src/runtime/cgo/gcc_freebsd_amd64.c
src/runtime/cgo/gcc_freebsd_arm.c
src/runtime/cgo/gcc_libinit.c
src/runtime/cgo/gcc_linux_386.c
src/runtime/cgo/gcc_linux_amd64.c
src/runtime/cgo/gcc_linux_arm.c
src/runtime/cgo/gcc_linux_arm64.c
src/runtime/cgo/gcc_linux_mips64x.c
src/runtime/cgo/gcc_linux_ppc64x.c
src/runtime/cgo/gcc_linux_s390x.c
src/runtime/cgo/gcc_netbsd_386.c
src/runtime/cgo/gcc_netbsd_amd64.c
src/runtime/cgo/gcc_netbsd_arm.c
src/runtime/cgo/gcc_signal_darwin_armx.c
src/runtime/cgo/gcc_solaris_amd64.c
src/runtime/cgo/libcgo_unix.h [new file with mode: 0644]

index b3633b73f34c8ad855c502591d90347bbc0da809..e3d591664983befc0ef8b6bfe3f251f352f491d5 100644 (file)
@@ -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) }
diff --git a/misc/cgo/test/issue18146.go b/misc/cgo/test/issue18146.go
new file mode 100644 (file)
index 0000000..6e551c9
--- /dev/null
@@ -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))
+       }
+}
index effbcdfd4b47d7453c37be8099d54370ba90765d..83092dbeacea953ead0df340272163f2fd154fe1 100644 (file)
@@ -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);
 
index 15396b0d258f7d8444b46fd13a10a6a84be105a8..93a6b8e3ed71f59dbbec2dba079b4be23227a614 100644 (file)
@@ -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);
 
index dbf88c34ac510d0b0ecd43c0aa78328bed035ddd..b3f80460111e0ece2644a1c91a0399dbd0a4d49b 100644 (file)
@@ -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);
 
index a9eb4f2cd2d2a31396a701adc5190239ee52a38f..039dcc02bd628f21daec3cc8e0a4a201c984fcc0 100644 (file)
@@ -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);
 
index e532ad69d6933a564d8bdddd2369c61b4ddc1efd..bdfbf6b5617f51824628cf1735729d8e8bc0ad52 100644 (file)
@@ -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);
 
index d288666a3dbca67085fb43c404105ccd3e364190..c6d4f258c077fcbe22241e8c5184b4c76f954c54 100644 (file)
@@ -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);
 
index e532ad69d6933a564d8bdddd2369c61b4ddc1efd..bdfbf6b5617f51824628cf1735729d8e8bc0ad52 100644 (file)
@@ -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);
 
index c4e7574326138f1231aadb2095ece543b4780a26..746ca893224e6868e971576b9725a4d6de8c0018 100644 (file)
@@ -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);
 
index 0bdf40a4ca77c956a91f46908070ef39dc7ff971..f6fbaa3f01efb5d7b76f2ef782a04d7785b51de3 100644 (file)
@@ -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;
+}
index 30fe92bfea9b4f38c52b65680483bbee3c571f8d..457a2c7e3ae7b52bee98b1d4823f3deb82aaf6da 100644 (file)
@@ -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);
 
index 0c34c66592aaf15c71775dafe1a8d2d67ec86652..5d8ff101401181d15e002346141f2c735f794618 100644 (file)
@@ -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);
 
index 945c3f19e498ec39c821c057b34af9e1a0a2950b..31ced5e03c86a84577f73293d66bd9958f896adc 100644 (file)
@@ -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);
 
index ca9ba0ba6e7090575de3835498c03c62d8fcf7d3..35b8e27967f02491d094d5bdfeac80ac2dec57d6 100644 (file)
@@ -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);
 
index 8a95629f56149ea1311963faa2c746fb2c2a6a29..e0ce08f4e5c1755cc14c6dd4ff658599ec9e82ea 100644 (file)
@@ -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);
 
index fb19805bdae7e9026213c9f43abb9a3749042efa..fcf77cfe4784dee2fa2dc9ce02651a6d23b7a5de 100644 (file)
@@ -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);
 
index 81e3b339b0ca6b8158bd8021515845f19b6a2830..cdc9c23f49b1ad0d27845fa4c22768b23dfb6b6a 100644 (file)
@@ -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);
 
index 99558ea1401562bbeeb1d79b41ca6ce065142abd..fb317c1c680cb198b96766fc1d2d9e8b55181fb4 100644 (file)
@@ -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);
 
index f5c8b1e74f0507a2e0b144c50c72862955bb7d53..77a553f5fa7ebabfe0d79f2bf07c35e9494decd5 100644 (file)
@@ -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);
 
index 97ce908485e02564ff46fe5de2935142a20a40e3..672f49c3d811519cf515d91a1b60b32df2c1f98c 100644 (file)
@@ -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);
 
index 02c54d80a232c618b11f389823d812e4153931a1..a2d520bce8f9d57677bf3dcfeaa85bd588c0da0d 100644 (file)
@@ -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);
 
index 98a1a8be532a3bf9cebee1f86adf14bdb64f9b72..079bd12898e25652bc791cafd5acef38b6e8fc5a 100644 (file)
@@ -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);
 
diff --git a/src/runtime/cgo/libcgo_unix.h b/src/runtime/cgo/libcgo_unix.h
new file mode 100644 (file)
index 0000000..13c84ce
--- /dev/null
@@ -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*);