1// Copyright 2013 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#include <sys/types.h>
6#include <pthread.h>
7#include <signal.h>
8#include <string.h>
9#include "libcgo.h"
10#include "libcgo_unix.h"
11
12static void *threadentry(void*);
13
14static void (*setg_gcc)(void*);
15
16void
17x_cgo_init(G *g, void (*setg)(void*))
18{
19	pthread_attr_t attr;
20	size_t size;
21
22	setg_gcc = setg;
23	pthread_attr_init(&attr);
24	pthread_attr_getstacksize(&attr, &size);
25	g->stacklo = (uintptr)&attr - size + 4096;
26	pthread_attr_destroy(&attr);
27}
28
29
30void
31_cgo_sys_thread_start(ThreadStart *ts)
32{
33	pthread_attr_t attr;
34	sigset_t ign, oset;
35	pthread_t p;
36	size_t size;
37	int err;
38
39	sigfillset(&ign);
40	pthread_sigmask(SIG_SETMASK, &ign, &oset);
41
42	pthread_attr_init(&attr);
43	pthread_attr_getstacksize(&attr, &size);
44	// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
45	ts->g->stackhi = size;
46	err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
47
48	pthread_sigmask(SIG_SETMASK, &oset, nil);
49
50	if (err != 0) {
51		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
52		abort();
53	}
54}
55
56extern void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
57static void*
58threadentry(void *v)
59{
60	ThreadStart ts;
61	stack_t ss;
62
63	ts = *(ThreadStart*)v;
64	free(v);
65
66	// On NetBSD, a new thread inherits the signal stack of the
67	// creating thread. That confuses minit, so we remove that
68	// signal stack here before calling the regular mstart. It's
69	// a bit baroque to remove a signal stack here only to add one
70	// in minit, but it's a simple change that keeps NetBSD
71	// working like other OS's. At this point all signals are
72	// blocked, so there is no race.
73	memset(&ss, 0, sizeof ss);
74	ss.ss_flags = SS_DISABLE;
75	sigaltstack(&ss, nil);
76
77	crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
78	return nil;
79}
80