]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/cgo: retry pthread_create on EAGAIN for OpenBSD
authorIan Lance Taylor <iant@golang.org>
Mon, 5 Dec 2016 19:17:59 +0000 (11:17 -0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 5 Dec 2016 21:15:05 +0000 (21:15 +0000)
For reasons that I do not know, OpenBSD does not call pthread_create
directly, but instead looks it up in libpthread.so. That means that we
can't use the code used on other systems to retry pthread_create on
EAGAIN, since that code simply calls pthread_create.

This patch copies that code to an OpenBSD-specific version.

Also, check for an EAGAIN failure in the test, as that seems to be the
underlying cause of the test failure on several systems including OpenBSD.

Fixes #18146.

Change-Id: I3bceaa1e03a7eaebc2da19c9cc146b25b59243ef
Reviewed-on: https://go-review.googlesource.com/33905
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
misc/cgo/test/issue18146.go
src/runtime/cgo/gcc_libinit_openbsd.c
src/runtime/cgo/gcc_openbsd_386.c
src/runtime/cgo/gcc_openbsd_amd64.c
src/runtime/cgo/libcgo_unix.h

index ee62fc6aff449bdef8bc93085636e216bdbc6a0e..5ced6ecc22c2ba44923f7dfedd8bd56be0000967 100644 (file)
@@ -18,14 +18,10 @@ import (
        "runtime"
        "syscall"
        "testing"
+       "time"
 )
 
 func test18146(t *testing.T) {
-       switch runtime.GOOS {
-       case "darwin", "openbsd", "dragonfly":
-               t.Skip("skipping on %s; issue 18146", runtime.GOOS)
-       }
-
        attempts := 1000
        threads := 4
 
@@ -64,6 +60,18 @@ func test18146(t *testing.T) {
                cmd.Stdout = buf
                cmd.Stderr = buf
                if err := cmd.Start(); err != nil {
+                       // We are starting so many processes that on
+                       // some systems (problem seen on Darwin,
+                       // Dragonfly, OpenBSD) the fork call will fail
+                       // with EAGAIN.
+                       if pe, ok := err.(*os.PathError); ok {
+                               err = pe.Err
+                       }
+                       if se, ok := err.(syscall.Errno); ok && se == syscall.EAGAIN {
+                               time.Sleep(time.Millisecond)
+                               continue
+                       }
+
                        t.Error(err)
                        return
                }
index 626bf8adca104a96a742418821d7976ff6b2abd4..c8308e54c3491d76a40fa1ba4a38eaee3f0a2582 100644 (file)
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include "libcgo.h"
@@ -48,3 +51,24 @@ void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
 void (*(_cgo_get_context_function(void)))(struct context_arg*) {
        return cgo_context_function;
 }
+
+// _cgo_try_pthread_create retries sys_pthread_create if it fails with
+// EAGAIN.
+int
+_cgo_openbsd_try_pthread_create(int (*sys_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*),
+       pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
+       int tries;
+       int err;
+       struct timespec ts;
+
+       for (tries = 0; tries < 100; tries++) {
+               err = sys_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 1bc61ff7087bf972366c6589895790e77447eb2f..0cac047ad3045a3a13700bfe583783988797f087 100644 (file)
@@ -9,6 +9,7 @@
 #include <signal.h>
 #include <string.h>
 #include "libcgo.h"
+#include "libcgo_unix.h"
 
 static void* threadentry(void*);
 static void (*setg_gcc)(void*);
@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
        // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
        ts->g->stackhi = size;
-       err = sys_pthread_create(&p, &attr, threadentry, ts);
+       err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
 
        pthread_sigmask(SIG_SETMASK, &oset, nil);
 
index 4d4d14314c790b11e2aad461d08132b0ed2a7ad7..86a9185a37e6b9905572ba781b08e1bba4a414a7 100644 (file)
@@ -9,6 +9,7 @@
 #include <signal.h>
 #include <string.h>
 #include "libcgo.h"
+#include "libcgo_unix.h"
 
 static void* threadentry(void*);
 static void (*setg_gcc)(void*);
@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
        // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
        ts->g->stackhi = size;
-       err = sys_pthread_create(&p, &attr, threadentry, ts);
+       err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
 
        pthread_sigmask(SIG_SETMASK, &oset, nil);
 
index 13c84ce131a6b144ec30cc9255396d994fa5fc76..a56a366f23ccd97f44ab510559a4dc30ae5e26c6 100644 (file)
@@ -5,4 +5,11 @@
 /*
  * Call pthread_create, retrying on EAGAIN.
  */
-int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
+extern int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
+
+/*
+ * Same as _cgo_try_pthread_create, but passing on the pthread_create function.
+ * Only defined on OpenBSD.
+ */
+extern int _cgo_openbsd_try_pthread_create(int (*)(pthread_t*, const pthread_attr_t*, void *(*pfn)(void*), void*),
+       pthread_t*, const pthread_attr_t*, void* (*)(void*), void* arg);