Commit 80acfe95 authored by Ian Lance Taylor's avatar Ian Lance Taylor

runtime/cgo: retry pthread_create on EAGAIN for OpenBSD

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: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent a303f05f
...@@ -18,14 +18,10 @@ import ( ...@@ -18,14 +18,10 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"testing" "testing"
"time"
) )
func test18146(t *testing.T) { func test18146(t *testing.T) {
switch runtime.GOOS {
case "darwin", "openbsd", "dragonfly":
t.Skip("skipping on %s; issue 18146", runtime.GOOS)
}
attempts := 1000 attempts := 1000
threads := 4 threads := 4
...@@ -64,6 +60,18 @@ func test18146(t *testing.T) { ...@@ -64,6 +60,18 @@ func test18146(t *testing.T) {
cmd.Stdout = buf cmd.Stdout = buf
cmd.Stderr = buf cmd.Stderr = buf
if err := cmd.Start(); err != nil { 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) t.Error(err)
return return
} }
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "libcgo.h" #include "libcgo.h"
...@@ -48,3 +51,24 @@ void x_cgo_set_context_function(void (*context)(struct context_arg*)) { ...@@ -48,3 +51,24 @@ void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
void (*(_cgo_get_context_function(void)))(struct context_arg*) { void (*(_cgo_get_context_function(void)))(struct context_arg*) {
return cgo_context_function; 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;
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include "libcgo.h" #include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*); static void* threadentry(void*);
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
...@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts) ...@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
// Leave stacklo=0 and set stackhi=size; mstack will do the rest. // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size; 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); pthread_sigmask(SIG_SETMASK, &oset, nil);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include "libcgo.h" #include "libcgo.h"
#include "libcgo_unix.h"
static void* threadentry(void*); static void* threadentry(void*);
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
...@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts) ...@@ -170,7 +171,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
// Leave stacklo=0 and set stackhi=size; mstack will do the rest. // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size; 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); pthread_sigmask(SIG_SETMASK, &oset, nil);
......
...@@ -5,4 +5,11 @@ ...@@ -5,4 +5,11 @@
/* /*
* Call pthread_create, retrying on EAGAIN. * 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);
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