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 (
"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
}
......
......@@ -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;
}
......@@ -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);
......
......@@ -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);
......
......@@ -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);
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