| // Copyright 2015 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. | 
 |  | 
 | #include <pthread.h> | 
 | #include <string.h> | 
 | #include <signal.h> | 
 | #include <ucontext.h> | 
 | #include "libcgo.h" | 
 | #include "libcgo_unix.h" | 
 |  | 
 | static void* threadentry(void*); | 
 | static void (*setg_gcc)(void*); | 
 |  | 
 | void | 
 | x_cgo_init(G *g, void (*setg)(void*)) | 
 | { | 
 | 	ucontext_t ctx; | 
 |  | 
 | 	setg_gcc = setg; | 
 | 	if (getcontext(&ctx) != 0) | 
 | 		perror("runtime/cgo: getcontext failed"); | 
 | 	g->stacklo = (uintptr_t)ctx.uc_stack.ss_sp; | 
 |  | 
 | 	// Solaris processes report a tiny stack when run with "ulimit -s unlimited". | 
 | 	// Correct that as best we can: assume it's at least 1 MB. | 
 | 	// See golang.org/issue/12210. | 
 | 	if(ctx.uc_stack.ss_size < 1024*1024) | 
 | 		g->stacklo -= 1024*1024 - ctx.uc_stack.ss_size; | 
 | } | 
 |  | 
 | void | 
 | _cgo_sys_thread_start(ThreadStart *ts) | 
 | { | 
 | 	pthread_attr_t attr; | 
 | 	sigset_t ign, oset; | 
 | 	pthread_t p; | 
 | 	void *base; | 
 | 	size_t size; | 
 | 	int err; | 
 |  | 
 | 	sigfillset(&ign); | 
 | 	pthread_sigmask(SIG_SETMASK, &ign, &oset); | 
 |  | 
 | 	pthread_attr_init(&attr); | 
 |  | 
 | 	if (pthread_attr_getstack(&attr, &base, &size) != 0) | 
 | 		perror("runtime/cgo: pthread_attr_getstack failed"); | 
 | 	if (size == 0) { | 
 | 		ts->g->stackhi = 2 << 20; | 
 | 		if (pthread_attr_setstack(&attr, NULL, ts->g->stackhi) != 0) | 
 | 			perror("runtime/cgo: pthread_attr_setstack failed"); | 
 | 	} else { | 
 | 		ts->g->stackhi = size; | 
 | 	} | 
 | 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | 
 | 	err = _cgo_try_pthread_create(&p, &attr, threadentry, ts); | 
 |  | 
 | 	pthread_sigmask(SIG_SETMASK, &oset, nil); | 
 |  | 
 | 	if (err != 0) { | 
 | 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err)); | 
 | 		abort(); | 
 | 	} | 
 | } | 
 |  | 
 | static void* | 
 | threadentry(void *v) | 
 | { | 
 | 	ThreadStart ts; | 
 |  | 
 | 	ts = *(ThreadStart*)v; | 
 | 	free(v); | 
 |  | 
 | 	/* | 
 | 	 * Set specific keys. | 
 | 	 */ | 
 | 	setg_gcc((void*)ts.g); | 
 |  | 
 | 	crosscall_amd64(ts.fn); | 
 | 	return nil; | 
 | } |