| // Copyright 2009 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 <errno.h> | 
 | #include <limits.h> | 
 | #include <signal.h> | 
 | #include <stdlib.h> | 
 | #include <pthread.h> | 
 | #include <unistd.h> | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #ifdef HAVE_DL_ITERATE_PHDR | 
 | #include <link.h> | 
 | #endif | 
 |  | 
 | #include "runtime.h" | 
 | #include "arch.h" | 
 | #include "defs.h" | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 |  | 
 | /* FIXME: These are not declared anywhere.  */ | 
 |  | 
 | extern void __splitstack_getcontext(void *context[10]); | 
 |  | 
 | extern void __splitstack_setcontext(void *context[10]); | 
 |  | 
 | extern void *__splitstack_makecontext(size_t, void *context[10], size_t *); | 
 |  | 
 | extern void * __splitstack_resetcontext(void *context[10], size_t *); | 
 |  | 
 | extern void __splitstack_releasecontext(void *context[10]); | 
 |  | 
 | extern void *__splitstack_find(void *, void *, size_t *, void **, void **, | 
 | 			       void **); | 
 |  | 
 | extern void __splitstack_block_signals (int *, int *); | 
 |  | 
 | extern void __splitstack_block_signals_context (void *context[10], int *, | 
 | 						int *); | 
 |  | 
 | #endif | 
 |  | 
 | #ifndef PTHREAD_STACK_MIN | 
 | # define PTHREAD_STACK_MIN 8192 | 
 | #endif | 
 |  | 
 | #if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK) | 
 | # define StackMin PTHREAD_STACK_MIN | 
 | #else | 
 | # define StackMin ((sizeof(char *) < 8) ? 2 * 1024 * 1024 : 4 * 1024 * 1024) | 
 | #endif | 
 |  | 
 | uintptr runtime_stacks_sys; | 
 |  | 
 | void gtraceback(G*) | 
 |   __asm__(GOSYM_PREFIX "runtime.gtraceback"); | 
 |  | 
 | static void gscanstack(G*); | 
 |  | 
 | #ifdef __rtems__ | 
 | #define __thread | 
 | #endif | 
 |  | 
 | __thread G *g __asm__(GOSYM_PREFIX "runtime.g"); | 
 |  | 
 | #ifndef SETCONTEXT_CLOBBERS_TLS | 
 |  | 
 | static inline void | 
 | initcontext(void) | 
 | { | 
 | } | 
 |  | 
 | static inline void | 
 | fixcontext(__go_context_t *c __attribute__ ((unused))) | 
 | { | 
 | } | 
 |  | 
 | #else | 
 |  | 
 | # if defined(__x86_64__) && defined(__sun__) | 
 |  | 
 | // x86_64 Solaris 10 and 11 have a bug: setcontext switches the %fs | 
 | // register to that of the thread which called getcontext.  The effect | 
 | // is that the address of all __thread variables changes.  This bug | 
 | // also affects pthread_self() and pthread_getspecific.  We work | 
 | // around it by clobbering the context field directly to keep %fs the | 
 | // same. | 
 |  | 
 | static __thread greg_t fs; | 
 |  | 
 | static inline void | 
 | initcontext(void) | 
 | { | 
 | 	ucontext_t c; | 
 |  | 
 | 	getcontext(&c); | 
 | 	fs = c.uc_mcontext.gregs[REG_FSBASE]; | 
 | } | 
 |  | 
 | static inline void | 
 | fixcontext(ucontext_t* c) | 
 | { | 
 | 	c->uc_mcontext.gregs[REG_FSBASE] = fs; | 
 | } | 
 |  | 
 | # elif defined(__NetBSD__) | 
 |  | 
 | // NetBSD has a bug: setcontext clobbers tlsbase, we need to save | 
 | // and restore it ourselves. | 
 |  | 
 | static __thread __greg_t tlsbase; | 
 |  | 
 | static inline void | 
 | initcontext(void) | 
 | { | 
 | 	ucontext_t c; | 
 |  | 
 | 	getcontext(&c); | 
 | 	tlsbase = c.uc_mcontext._mc_tlsbase; | 
 | } | 
 |  | 
 | static inline void | 
 | fixcontext(ucontext_t* c) | 
 | { | 
 | 	c->uc_mcontext._mc_tlsbase = tlsbase; | 
 | } | 
 |  | 
 | # elif defined(__sparc__) | 
 |  | 
 | static inline void | 
 | initcontext(void) | 
 | { | 
 | } | 
 |  | 
 | static inline void | 
 | fixcontext(ucontext_t *c) | 
 | { | 
 | 	/* ??? Using  | 
 | 	     register unsigned long thread __asm__("%g7"); | 
 | 	     c->uc_mcontext.gregs[REG_G7] = thread; | 
 | 	   results in | 
 | 	     error: variable ‘thread’ might be clobbered by \ | 
 | 		‘longjmp’ or ‘vfork’ [-Werror=clobbered] | 
 | 	   which ought to be false, as %g7 is a fixed register.  */ | 
 |  | 
 | 	if (sizeof (c->uc_mcontext.gregs[REG_G7]) == 8) | 
 | 		asm ("stx %%g7, %0" : "=m"(c->uc_mcontext.gregs[REG_G7])); | 
 | 	else | 
 | 		asm ("st %%g7, %0" : "=m"(c->uc_mcontext.gregs[REG_G7])); | 
 | } | 
 |  | 
 | # elif defined(_AIX) | 
 |  | 
 | static inline void | 
 | initcontext(void) | 
 | { | 
 | } | 
 |  | 
 | static inline void | 
 | fixcontext(ucontext_t* c) | 
 | { | 
 | 	// Thread pointer is in r13, per 64-bit ABI. | 
 | 	if (sizeof (c->uc_mcontext.jmp_context.gpr[13]) == 8) | 
 | 		asm ("std 13, %0" : "=m"(c->uc_mcontext.jmp_context.gpr[13])); | 
 | } | 
 |  | 
 | # else | 
 |  | 
 | #  error unknown case for SETCONTEXT_CLOBBERS_TLS | 
 |  | 
 | # endif | 
 |  | 
 | #endif | 
 |  | 
 | // ucontext_arg returns a properly aligned ucontext_t value.  On some | 
 | // systems a ucontext_t value must be aligned to a 16-byte boundary. | 
 | // The g structure that has fields of type ucontext_t is defined in | 
 | // Go, and Go has no simple way to align a field to such a boundary. | 
 | // So we make the field larger in runtime2.go and pick an appropriate | 
 | // offset within the field here. | 
 | static __go_context_t* | 
 | ucontext_arg(uintptr_t* go_ucontext) | 
 | { | 
 | 	uintptr_t p = (uintptr_t)go_ucontext; | 
 | 	size_t align = __alignof__(__go_context_t); | 
 | 	if(align > 16) { | 
 | 		// We only ensured space for up to a 16 byte alignment | 
 | 		// in libgo/go/runtime/runtime2.go. | 
 | 		runtime_throw("required alignment of __go_context_t too large"); | 
 | 	} | 
 | 	p = (p + align - 1) &~ (uintptr_t)(align - 1); | 
 | 	return (__go_context_t*)p; | 
 | } | 
 |  | 
 | // We can not always refer to the TLS variables directly.  The | 
 | // compiler will call tls_get_addr to get the address of the variable, | 
 | // and it may hold it in a register across a call to schedule.  When | 
 | // we get back from the call we may be running in a different thread, | 
 | // in which case the register now points to the TLS variable for a | 
 | // different thread.  We use non-inlinable functions to avoid this | 
 | // when necessary. | 
 |  | 
 | G* runtime_g(void) __attribute__ ((noinline, no_split_stack)); | 
 |  | 
 | G* | 
 | runtime_g(void) | 
 | { | 
 | 	return g; | 
 | } | 
 |  | 
 | M* runtime_m(void) __attribute__ ((noinline, no_split_stack)); | 
 |  | 
 | M* | 
 | runtime_m(void) | 
 | { | 
 | 	if(g == nil) | 
 | 		return nil; | 
 | 	return g->m; | 
 | } | 
 |  | 
 | // Set g. | 
 |  | 
 | void runtime_setg(G*) __attribute__ ((no_split_stack)); | 
 |  | 
 | void | 
 | runtime_setg(G* gp) | 
 | { | 
 | 	g = gp; | 
 | } | 
 |  | 
 | void runtime_newosproc(M *) | 
 |   __asm__(GOSYM_PREFIX "runtime.newosproc"); | 
 |  | 
 | // Start a new thread. | 
 | void | 
 | runtime_newosproc(M *mp) | 
 | { | 
 | 	pthread_attr_t attr; | 
 | 	sigset_t clear, old; | 
 | 	pthread_t tid; | 
 | 	int tries; | 
 | 	int ret; | 
 |  | 
 | 	if(pthread_attr_init(&attr) != 0) | 
 | 		runtime_throw("pthread_attr_init"); | 
 | 	if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) | 
 | 		runtime_throw("pthread_attr_setdetachstate"); | 
 |  | 
 | 	// Block signals during pthread_create so that the new thread | 
 | 	// starts with signals disabled.  It will enable them in minit. | 
 | 	sigfillset(&clear); | 
 |  | 
 | #ifdef SIGTRAP | 
 | 	// Blocking SIGTRAP reportedly breaks gdb on Alpha GNU/Linux. | 
 | 	sigdelset(&clear, SIGTRAP); | 
 | #endif | 
 |  | 
 | 	sigemptyset(&old); | 
 | 	pthread_sigmask(SIG_BLOCK, &clear, &old); | 
 |  | 
 | 	for (tries = 0; tries < 20; tries++) { | 
 | 		ret = pthread_create(&tid, &attr, runtime_mstart, mp); | 
 | 		if (ret != EAGAIN) { | 
 | 			break; | 
 | 		} | 
 | 		runtime_usleep((tries + 1) * 1000); // Milliseconds. | 
 | 	} | 
 |  | 
 | 	pthread_sigmask(SIG_SETMASK, &old, nil); | 
 |  | 
 | 	if (ret != 0) { | 
 | 		runtime_printf("pthread_create failed: %d\n", ret); | 
 | 		runtime_throw("pthread_create"); | 
 | 	} | 
 |  | 
 | 	if(pthread_attr_destroy(&attr) != 0) | 
 | 		runtime_throw("pthread_attr_destroy"); | 
 | } | 
 |  | 
 | // Switch context to a different goroutine.  This is like longjmp. | 
 | void runtime_gogo(G*) __attribute__ ((noinline)); | 
 | void | 
 | runtime_gogo(G* newg) | 
 | { | 
 | #ifdef USING_SPLIT_STACK | 
 | 	__splitstack_setcontext((void*)(&newg->stackcontext[0])); | 
 | #endif | 
 | 	g = newg; | 
 | 	newg->fromgogo = true; | 
 | 	fixcontext(ucontext_arg(&newg->context[0])); | 
 | 	__go_setcontext(ucontext_arg(&newg->context[0])); | 
 | 	runtime_throw("gogo setcontext returned"); | 
 | } | 
 |  | 
 | // Save context and call fn passing g as a parameter.  This is like | 
 | // setjmp.  Because getcontext always returns 0, unlike setjmp, we use | 
 | // g->fromgogo as a code.  It will be true if we got here via | 
 | // setcontext.  g == nil the first time this is called in a new m. | 
 | void runtime_mcall(FuncVal *) __attribute__ ((noinline)); | 
 | void | 
 | runtime_mcall(FuncVal *fv) | 
 | { | 
 | 	M *mp; | 
 | 	G *gp; | 
 | #ifndef USING_SPLIT_STACK | 
 | 	void *afterregs; | 
 | #endif | 
 |  | 
 | 	// Ensure that all registers are on the stack for the garbage | 
 | 	// collector. | 
 | 	__builtin_unwind_init(); | 
 | 	flush_registers_to_secondary_stack(); | 
 |  | 
 | 	gp = g; | 
 | 	mp = gp->m; | 
 | 	if(gp == mp->g0) | 
 | 		runtime_throw("runtime: mcall called on m->g0 stack"); | 
 |  | 
 | 	if(gp != nil) { | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 | 		__splitstack_getcontext((void*)(&gp->stackcontext[0])); | 
 | #else | 
 | 		// We have to point to an address on the stack that is | 
 | 		// below the saved registers. | 
 | 		gp->gcnextsp = (uintptr)(&afterregs); | 
 | 		gp->gcnextsp2 = (uintptr)(secondary_stack_pointer()); | 
 | #endif | 
 | 		gp->fromgogo = false; | 
 | 		__go_getcontext(ucontext_arg(&gp->context[0])); | 
 |  | 
 | 		// When we return from getcontext, we may be running | 
 | 		// in a new thread.  That means that g may have | 
 | 		// changed.  It is a global variables so we will | 
 | 		// reload it, but the address of g may be cached in | 
 | 		// our local stack frame, and that address may be | 
 | 		// wrong.  Call the function to reload the value for | 
 | 		// this thread. | 
 | 		gp = runtime_g(); | 
 | 		mp = gp->m; | 
 |  | 
 | 		if(gp->traceback != 0) | 
 | 			gtraceback(gp); | 
 | 		if(gp->scang != 0) | 
 | 			gscanstack(gp); | 
 | 	} | 
 | 	if (gp == nil || !gp->fromgogo) { | 
 | #ifdef USING_SPLIT_STACK | 
 | 		__splitstack_setcontext((void*)(&mp->g0->stackcontext[0])); | 
 | #endif | 
 | 		mp->g0->entry = fv; | 
 | 		mp->g0->param = gp; | 
 |  | 
 | 		// It's OK to set g directly here because this case | 
 | 		// can not occur if we got here via a setcontext to | 
 | 		// the getcontext call just above. | 
 | 		g = mp->g0; | 
 |  | 
 | 		fixcontext(ucontext_arg(&mp->g0->context[0])); | 
 | 		__go_setcontext(ucontext_arg(&mp->g0->context[0])); | 
 | 		runtime_throw("runtime: mcall function returned"); | 
 | 	} | 
 | } | 
 |  | 
 | // Goroutine scheduler | 
 | // The scheduler's job is to distribute ready-to-run goroutines over worker threads. | 
 | // | 
 | // The main concepts are: | 
 | // G - goroutine. | 
 | // M - worker thread, or machine. | 
 | // P - processor, a resource that is required to execute Go code. | 
 | //     M must have an associated P to execute Go code, however it can be | 
 | //     blocked or in a syscall w/o an associated P. | 
 | // | 
 | // Design doc at http://golang.org/s/go11sched. | 
 |  | 
 | extern G* allocg(void) | 
 |   __asm__ (GOSYM_PREFIX "runtime.allocg"); | 
 |  | 
 | bool	runtime_isarchive; | 
 |  | 
 | extern void kickoff(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.kickoff"); | 
 | extern void minit(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.minit"); | 
 | extern void mstart1() | 
 |   __asm__(GOSYM_PREFIX "runtime.mstart1"); | 
 | extern void stopm(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.stopm"); | 
 | extern void mexit(bool) | 
 |   __asm__(GOSYM_PREFIX "runtime.mexit"); | 
 | extern void handoffp(P*) | 
 |   __asm__(GOSYM_PREFIX "runtime.handoffp"); | 
 | extern void wakep(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.wakep"); | 
 | extern void stoplockedm(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.stoplockedm"); | 
 | extern void schedule(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.schedule"); | 
 | extern void execute(G*, bool) | 
 |   __asm__(GOSYM_PREFIX "runtime.execute"); | 
 | extern void reentersyscall(uintptr, uintptr) | 
 |   __asm__(GOSYM_PREFIX "runtime.reentersyscall"); | 
 | extern void reentersyscallblock(uintptr, uintptr) | 
 |   __asm__(GOSYM_PREFIX "runtime.reentersyscallblock"); | 
 | extern G* gfget(P*) | 
 |   __asm__(GOSYM_PREFIX "runtime.gfget"); | 
 | extern void acquirep(P*) | 
 |   __asm__(GOSYM_PREFIX "runtime.acquirep"); | 
 | extern P* releasep(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.releasep"); | 
 | extern void incidlelocked(int32) | 
 |   __asm__(GOSYM_PREFIX "runtime.incidlelocked"); | 
 | extern void globrunqput(G*) | 
 |   __asm__(GOSYM_PREFIX "runtime.globrunqput"); | 
 | extern P* pidleget(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.pidleget"); | 
 | extern struct mstats* getMemstats(void) | 
 |   __asm__(GOSYM_PREFIX "runtime.getMemstats"); | 
 |  | 
 | bool runtime_isstarted; | 
 |  | 
 | // Used to determine the field alignment. | 
 |  | 
 | struct field_align | 
 | { | 
 |   char c; | 
 |   Hchan *p; | 
 | }; | 
 |  | 
 | void getTraceback(G*, G*) __asm__(GOSYM_PREFIX "runtime.getTraceback"); | 
 |  | 
 | // getTraceback stores a traceback of gp in the g's traceback field | 
 | // and then returns to me.  We expect that gp's traceback is not nil. | 
 | // It works by saving me's current context, and checking gp's traceback field. | 
 | // If gp's traceback field is not nil, it starts running gp. | 
 | // In places where we call getcontext, we check the traceback field. | 
 | // If it is not nil, we collect a traceback, and then return to the | 
 | // goroutine stored in the traceback field, which is me. | 
 | void getTraceback(G* me, G* gp) | 
 | { | 
 | 	M* holdm; | 
 |  | 
 | 	holdm = gp->m; | 
 | 	gp->m = me->m; | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 | 	__splitstack_getcontext((void*)(&me->stackcontext[0])); | 
 | #endif | 
 | 	__go_getcontext(ucontext_arg(&me->context[0])); | 
 |  | 
 | 	if (gp->traceback != 0) { | 
 | 		runtime_gogo(gp); | 
 | 	} | 
 |  | 
 | 	gp->m = holdm; | 
 | } | 
 |  | 
 | // Do a stack trace of gp, and then restore the context to | 
 | // gp->traceback->gp. | 
 |  | 
 | void | 
 | gtraceback(G* gp) | 
 | { | 
 | 	Traceback* traceback; | 
 |  | 
 | 	traceback = (Traceback*)gp->traceback; | 
 | 	gp->traceback = 0; | 
 | 	traceback->c = runtime_callers(1, traceback->locbuf, | 
 | 		sizeof traceback->locbuf / sizeof traceback->locbuf[0], false); | 
 | 	runtime_gogo(traceback->gp); | 
 | } | 
 |  | 
 | void doscanstackswitch(G*, G*) __asm__(GOSYM_PREFIX "runtime.doscanstackswitch"); | 
 |  | 
 | // Switch to gp and let it scan its stack. | 
 | // The first time gp->scang is set (to me). The second time here | 
 | // gp is done scanning, and has unset gp->scang, so we just return. | 
 | void | 
 | doscanstackswitch(G* me, G* gp) | 
 | { | 
 | 	M* holdm; | 
 |  | 
 | 	__go_assert(me->entry == nil); | 
 | 	me->fromgogo = false; | 
 |  | 
 | 	holdm = gp->m; | 
 | 	gp->m = me->m; | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 | 	__splitstack_getcontext((void*)(&me->stackcontext[0])); | 
 | #endif | 
 | 	__go_getcontext(ucontext_arg(&me->context[0])); | 
 |  | 
 | 	if(me->entry != nil) { | 
 | 		// Got here from mcall. | 
 | 		// The stack scanning code may call systemstack, which calls | 
 | 		// mcall, which calls setcontext. | 
 | 		// Run the function, which at the end will switch back to gp. | 
 | 		FuncVal *fv = me->entry; | 
 | 		void (*pfn)(G*) = (void (*)(G*))fv->fn; | 
 | 		G* gp1 = (G*)me->param; | 
 | 		__go_assert(gp1 == gp); | 
 | 		me->entry = nil; | 
 | 		me->param = nil; | 
 | 		__builtin_call_with_static_chain(pfn(gp1), fv); | 
 | 		abort(); | 
 | 	} | 
 |  | 
 | 	if (gp->scang != 0) | 
 | 		runtime_gogo(gp); | 
 |  | 
 | 	gp->m = holdm; | 
 | } | 
 |  | 
 | // Do a stack scan, then switch back to the g that triggers this scan. | 
 | // We come here from doscanstackswitch. | 
 | static void | 
 | gscanstack(G *gp) | 
 | { | 
 | 	G *oldg, *oldcurg; | 
 |  | 
 | 	oldg = (G*)gp->scang; | 
 | 	oldcurg = oldg->m->curg; | 
 | 	oldg->m->curg = gp; | 
 | 	gp->scang = 0; | 
 |  | 
 | 	doscanstack(gp, (void*)gp->scangcw); | 
 |  | 
 | 	gp->scangcw = 0; | 
 | 	oldg->m->curg = oldcurg; | 
 | 	runtime_gogo(oldg); | 
 | } | 
 |  | 
 | // Called by pthread_create to start an M. | 
 | void* | 
 | runtime_mstart(void *arg) | 
 | { | 
 | 	M* mp; | 
 | 	G* gp; | 
 |  | 
 | 	mp = (M*)(arg); | 
 | 	gp = mp->g0; | 
 | 	gp->m = mp; | 
 |  | 
 | 	g = gp; | 
 |  | 
 | 	gp->entry = nil; | 
 | 	gp->param = nil; | 
 |  | 
 | 	// We have to call minit before we call getcontext, | 
 | 	// because getcontext will copy the signal mask. | 
 | 	minit(); | 
 |  | 
 | 	initcontext(); | 
 |  | 
 | 	// Record top of stack for use by mcall. | 
 | 	// Once we call schedule we're never coming back, | 
 | 	// so other calls can reuse this stack space. | 
 | #ifdef USING_SPLIT_STACK | 
 | 	__splitstack_getcontext((void*)(&gp->stackcontext[0])); | 
 | #else | 
 | 	gp->gcinitialsp = &arg; | 
 | 	// Setting gcstacksize to 0 is a marker meaning that gcinitialsp | 
 | 	// is the top of the stack, not the bottom. | 
 | 	gp->gcstacksize = 0; | 
 | 	gp->gcnextsp = (uintptr)(&arg); | 
 | 	gp->gcinitialsp2 = secondary_stack_pointer(); | 
 | 	gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2); | 
 | #endif | 
 |  | 
 | 	// Save the currently active context.  This will return | 
 | 	// multiple times via the setcontext call in mcall. | 
 | 	__go_getcontext(ucontext_arg(&gp->context[0])); | 
 |  | 
 | 	if(gp->traceback != 0) { | 
 | 		// Got here from getTraceback. | 
 | 		// I'm not sure this ever actually happens--getTraceback | 
 | 		// may always go to the getcontext call in mcall. | 
 | 		gtraceback(gp); | 
 | 	} | 
 | 	if(gp->scang != 0) | 
 | 		// Got here from doscanswitch. Should not happen. | 
 | 		runtime_throw("mstart with scang"); | 
 |  | 
 | 	if(gp->entry != nil) { | 
 | 		// Got here from mcall. | 
 | 		FuncVal *fv = gp->entry; | 
 | 		void (*pfn)(G*) = (void (*)(G*))fv->fn; | 
 | 		G* gp1 = (G*)gp->param; | 
 | 		gp->entry = nil; | 
 | 		gp->param = nil; | 
 | 		__builtin_call_with_static_chain(pfn(gp1), fv); | 
 | 		abort(); | 
 | 	} | 
 |  | 
 | 	if(mp->exiting) { | 
 | 		mexit(true); | 
 | 		return nil; | 
 | 	} | 
 |  | 
 | 	// Initial call to getcontext--starting thread. | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 | 	{ | 
 | 		int dont_block_signals = 0; | 
 | 		__splitstack_block_signals(&dont_block_signals, nil); | 
 | 	} | 
 | #endif | 
 |  | 
 | 	mstart1(); | 
 |  | 
 | 	// mstart1 does not return, but we need a return statement | 
 | 	// here to avoid a compiler warning. | 
 | 	return nil; | 
 | } | 
 |  | 
 | typedef struct CgoThreadStart CgoThreadStart; | 
 | struct CgoThreadStart | 
 | { | 
 | 	M *m; | 
 | 	G *g; | 
 | 	uintptr *tls; | 
 | 	void (*fn)(void); | 
 | }; | 
 |  | 
 | void setGContext(void) __asm__ (GOSYM_PREFIX "runtime.setGContext"); | 
 |  | 
 | // setGContext sets up a new goroutine context for the current g. | 
 | void | 
 | setGContext(void) | 
 | { | 
 | 	int val; | 
 | 	G *gp; | 
 |  | 
 | 	initcontext(); | 
 | 	gp = g; | 
 | 	gp->entry = nil; | 
 | 	gp->param = nil; | 
 | #ifdef USING_SPLIT_STACK | 
 | 	__splitstack_getcontext((void*)(&gp->stackcontext[0])); | 
 | 	val = 0; | 
 | 	__splitstack_block_signals(&val, nil); | 
 | #else | 
 | 	gp->gcinitialsp = &val; | 
 | 	gp->gcstack = 0; | 
 | 	gp->gcstacksize = 0; | 
 | 	gp->gcnextsp = (uintptr)(&val); | 
 | 	gp->gcinitialsp2 = secondary_stack_pointer(); | 
 | 	gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2); | 
 | #endif | 
 | 	__go_getcontext(ucontext_arg(&gp->context[0])); | 
 |  | 
 | 	if(gp->entry != nil) { | 
 | 		// Got here from mcall. | 
 | 		FuncVal *fv = gp->entry; | 
 | 		void (*pfn)(G*) = (void (*)(G*))fv->fn; | 
 | 		G* gp1 = (G*)gp->param; | 
 | 		gp->entry = nil; | 
 | 		gp->param = nil; | 
 | 		__builtin_call_with_static_chain(pfn(gp1), fv); | 
 | 		abort(); | 
 | 	} | 
 | } | 
 |  | 
 | void makeGContext(G*, byte*, uintptr) | 
 | 	__asm__(GOSYM_PREFIX "runtime.makeGContext"); | 
 |  | 
 | // makeGContext makes a new context for a g. | 
 | void | 
 | makeGContext(G* gp, byte* sp, uintptr spsize) { | 
 | 	__go_context_t *uc; | 
 |  | 
 | 	uc = ucontext_arg(&gp->context[0]); | 
 | 	__go_getcontext(uc); | 
 | 	__go_makecontext(uc, kickoff, sp, (size_t)spsize); | 
 | } | 
 |  | 
 | // The goroutine g is about to enter a system call. | 
 | // Record that it's not using the cpu anymore. | 
 | // This is called only from the go syscall library and cgocall, | 
 | // not from the low-level system calls used by the runtime. | 
 | // | 
 | // Entersyscall cannot split the stack: the runtime_gosave must | 
 | // make g->sched refer to the caller's stack segment, because | 
 | // entersyscall is going to return immediately after. | 
 |  | 
 | void runtime_entersyscall() __attribute__ ((no_split_stack)); | 
 | static void doentersyscall(uintptr, uintptr) | 
 |   __attribute__ ((no_split_stack, noinline)); | 
 |  | 
 | void | 
 | runtime_entersyscall() | 
 | { | 
 | 	// Save the registers in the g structure so that any pointers | 
 | 	// held in registers will be seen by the garbage collector. | 
 | 	if (!runtime_usestackmaps) | 
 | 		__go_getcontext(ucontext_arg(&g->gcregs[0])); | 
 |  | 
 | 	// Note that if this function does save any registers itself, | 
 | 	// we might store the wrong value in the call to getcontext. | 
 | 	// FIXME: This assumes that we do not need to save any | 
 | 	// callee-saved registers to access the TLS variable g.  We | 
 | 	// don't want to put the ucontext_t on the stack because it is | 
 | 	// large and we can not split the stack here. | 
 | 	doentersyscall((uintptr)runtime_getcallerpc(), | 
 | 		       (uintptr)runtime_getcallersp()); | 
 | } | 
 |  | 
 | static void | 
 | doentersyscall(uintptr pc, uintptr sp) | 
 | { | 
 | 	// Leave SP around for GC and traceback. | 
 | #ifdef USING_SPLIT_STACK | 
 | 	{ | 
 | 	  size_t gcstacksize; | 
 | 	  g->gcstack = (uintptr)(__splitstack_find(nil, nil, &gcstacksize, | 
 | 						   (void**)(&g->gcnextsegment), | 
 | 						   (void**)(&g->gcnextsp), | 
 | 						   &g->gcinitialsp)); | 
 | 	  g->gcstacksize = (uintptr)gcstacksize; | 
 | 	} | 
 | #else | 
 | 	{ | 
 | 		void *v; | 
 |  | 
 | 		g->gcnextsp = (uintptr)(&v); | 
 | 		g->gcnextsp2 = (uintptr)(secondary_stack_pointer()); | 
 | 	} | 
 | #endif | 
 |  | 
 | 	reentersyscall(pc, sp); | 
 | } | 
 |  | 
 | static void doentersyscallblock(uintptr, uintptr) | 
 |   __attribute__ ((no_split_stack, noinline)); | 
 |  | 
 | // The same as runtime_entersyscall(), but with a hint that the syscall is blocking. | 
 | void | 
 | runtime_entersyscallblock() | 
 | { | 
 | 	// Save the registers in the g structure so that any pointers | 
 | 	// held in registers will be seen by the garbage collector. | 
 | 	if (!runtime_usestackmaps) | 
 | 		__go_getcontext(ucontext_arg(&g->gcregs[0])); | 
 |  | 
 | 	// See comment in runtime_entersyscall. | 
 | 	doentersyscallblock((uintptr)runtime_getcallerpc(), | 
 | 			    (uintptr)runtime_getcallersp()); | 
 | } | 
 |  | 
 | static void | 
 | doentersyscallblock(uintptr pc, uintptr sp) | 
 | { | 
 | 	// Leave SP around for GC and traceback. | 
 | #ifdef USING_SPLIT_STACK | 
 | 	{ | 
 | 	  size_t gcstacksize; | 
 | 	  g->gcstack = (uintptr)(__splitstack_find(nil, nil, &gcstacksize, | 
 | 						   (void**)(&g->gcnextsegment), | 
 | 						   (void**)(&g->gcnextsp), | 
 | 						   &g->gcinitialsp)); | 
 | 	  g->gcstacksize = (uintptr)gcstacksize; | 
 | 	} | 
 | #else | 
 | 	{ | 
 | 		void *v; | 
 |  | 
 | 		g->gcnextsp = (uintptr)(&v); | 
 | 		g->gcnextsp2 = (uintptr)(secondary_stack_pointer()); | 
 | 	} | 
 | #endif | 
 |  | 
 | 	reentersyscallblock(pc, sp); | 
 | } | 
 |  | 
 | // Allocate a new g, with a stack big enough for stacksize bytes. | 
 | G* | 
 | runtime_malg(bool allocatestack, bool signalstack, byte** ret_stack, uintptr* ret_stacksize) | 
 | { | 
 | 	uintptr stacksize; | 
 | 	G *newg; | 
 | 	byte* unused_stack; | 
 | 	uintptr unused_stacksize; | 
 | #ifdef USING_SPLIT_STACK | 
 | 	int dont_block_signals = 0; | 
 | 	size_t ss_stacksize; | 
 | #endif | 
 |  | 
 | 	if (ret_stack == nil) { | 
 | 		ret_stack = &unused_stack; | 
 | 	} | 
 | 	if (ret_stacksize == nil) { | 
 | 		ret_stacksize = &unused_stacksize; | 
 | 	} | 
 | 	newg = allocg(); | 
 | 	if(allocatestack) { | 
 | 		stacksize = StackMin; | 
 | 		if(signalstack) { | 
 | 			stacksize = 32 * 1024; // OS X wants >= 8K, GNU/Linux >= 2K | 
 | #ifdef SIGSTKSZ | 
 | 			if(stacksize < (uintptr)(SIGSTKSZ)) | 
 | 				stacksize = (uintptr)(SIGSTKSZ); | 
 | #endif | 
 | 		} | 
 |  | 
 | #ifdef USING_SPLIT_STACK | 
 | 		*ret_stack = __splitstack_makecontext(stacksize, | 
 | 						      (void*)(&newg->stackcontext[0]), | 
 | 						      &ss_stacksize); | 
 | 		*ret_stacksize = (uintptr)ss_stacksize; | 
 | 		__splitstack_block_signals_context((void*)(&newg->stackcontext[0]), | 
 | 						   &dont_block_signals, nil); | 
 | #else | 
 |                 // In 64-bit mode, the maximum Go allocation space is | 
 |                 // 128G.  Our stack size is 4M, which only permits 32K | 
 |                 // goroutines.  In order to not limit ourselves, | 
 |                 // allocate the stacks out of separate memory.  In | 
 |                 // 32-bit mode, the Go allocation space is all of | 
 |                 // memory anyhow. | 
 | 		if(sizeof(void*) == 8) { | 
 | 			void *p = runtime_sysAlloc(stacksize, &getMemstats()->stacks_sys); | 
 | 			if(p == nil) | 
 | 				runtime_throw("runtime: cannot allocate memory for goroutine stack"); | 
 | 			*ret_stack = (byte*)p; | 
 | 		} else { | 
 | 			*ret_stack = runtime_mallocgc(stacksize, nil, false); | 
 | 			runtime_xadd(&runtime_stacks_sys, stacksize); | 
 | 		} | 
 | 		*ret_stacksize = (uintptr)stacksize; | 
 | 		newg->gcinitialsp = *ret_stack; | 
 | 		newg->gcstacksize = (uintptr)stacksize; | 
 | 		newg->gcinitialsp2 = initial_secondary_stack_pointer(*ret_stack); | 
 | #endif | 
 | 	} | 
 | 	return newg; | 
 | } | 
 |  | 
 | void stackfree(G*) | 
 |   __asm__(GOSYM_PREFIX "runtime.stackfree"); | 
 |  | 
 | // stackfree frees the stack of a g. | 
 | void | 
 | stackfree(G* gp) | 
 | { | 
 | #ifdef USING_SPLIT_STACK | 
 |   __splitstack_releasecontext((void*)(&gp->stackcontext[0])); | 
 | #else | 
 |   // If gcstacksize is 0, the stack is allocated by libc and will be | 
 |   // released when the thread exits. Otherwise, in 64-bit mode it was | 
 |   // allocated using sysAlloc and in 32-bit mode it was allocated | 
 |   // using garbage collected memory. | 
 |   if (gp->gcstacksize != 0) { | 
 |     if (sizeof(void*) == 8) { | 
 |       runtime_sysFree(gp->gcinitialsp, gp->gcstacksize, &getMemstats()->stacks_sys); | 
 |     } | 
 |     gp->gcinitialsp = nil; | 
 |     gp->gcstacksize = 0; | 
 |   } | 
 | #endif | 
 | } | 
 |  | 
 | void resetNewG(G*, void **, uintptr*) | 
 |   __asm__(GOSYM_PREFIX "runtime.resetNewG"); | 
 |  | 
 | // Reset stack information for g pulled out of the cache to start a | 
 | // new goroutine. | 
 | void | 
 | resetNewG(G *newg, void **sp, uintptr *spsize) | 
 | { | 
 | #ifdef USING_SPLIT_STACK | 
 |   int dont_block_signals = 0; | 
 |   size_t ss_spsize; | 
 |  | 
 |   *sp = __splitstack_resetcontext((void*)(&newg->stackcontext[0]), &ss_spsize); | 
 |   *spsize = ss_spsize; | 
 |   __splitstack_block_signals_context((void*)(&newg->stackcontext[0]), | 
 | 				     &dont_block_signals, nil); | 
 | #else | 
 |   *sp = newg->gcinitialsp; | 
 |   *spsize = newg->gcstacksize; | 
 |   if(*spsize == 0) | 
 |     runtime_throw("bad spsize in resetNewG"); | 
 |   newg->gcnextsp = (uintptr)(*sp); | 
 |   newg->gcnextsp2 = (uintptr)(newg->gcinitialsp2); | 
 | #endif | 
 | } |