// Create a new m. It will start off with a call to runtime_mstart. M* runtime_newm(void) { M *m; pthread_attr_t attr; pthread_t tid; size_t stacksize; m = runtime_malloc(sizeof(M)); mcommoninit(m); m->g0 = runtime_malg(-1, nil, nil); 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"); stacksize = PTHREAD_STACK_MIN; // With glibc before version 2.16 the static TLS size is taken // out of the stack size, and we get an error or a crash if // there is not enough stack space left. Add it back in if we // can, in case the program uses a lot of TLS space. FIXME: // This can be disabled in glibc 2.16 and later, if the bug is // indeed fixed then. stacksize += tlssize; if(pthread_attr_setstacksize(&attr, stacksize) != 0) runtime_throw("pthread_attr_setstacksize"); if(pthread_create(&tid, &attr, runtime_mstart, m) != 0) runtime_throw("pthread_create"); return m; }
G* __go_go(void (*fn)(void*), void* arg) { byte *sp; size_t spsize; G * volatile newg; // volatile to avoid longjmp warning schedlock(); if((newg = gfget()) != nil){ #ifdef USING_SPLIT_STACK int dont_block_signals = 0; sp = __splitstack_resetcontext(&newg->stack_context[0], &spsize); __splitstack_block_signals_context(&newg->stack_context[0], &dont_block_signals, nil); #else sp = newg->gcinitial_sp; spsize = newg->gcstack_size; if(spsize == 0) runtime_throw("bad spsize in __go_go"); newg->gcnext_sp = sp; #endif } else { newg = runtime_malg(StackMin, &sp, &spsize); if(runtime_lastg == nil) runtime_allg = newg; else runtime_lastg->alllink = newg; runtime_lastg = newg; } newg->status = Gwaiting; newg->waitreason = "new goroutine"; newg->entry = (byte*)fn; newg->param = arg; newg->gopc = (uintptr)__builtin_return_address(0); runtime_sched.gcount++; runtime_sched.goidgen++; newg->goid = runtime_sched.goidgen; if(sp == nil) runtime_throw("nil g->stack0"); getcontext(&newg->context); newg->context.uc_stack.ss_sp = sp; #ifdef MAKECONTEXT_STACK_TOP newg->context.uc_stack.ss_sp += spsize; #endif newg->context.uc_stack.ss_size = spsize; makecontext(&newg->context, kickoff, 0); newprocreadylocked(newg); schedunlock(); return newg; //printf(" goid=%d\n", newg->goid); }
static M* startm(void) { M *m; pthread_attr_t attr; pthread_t tid; m = runtime_malloc(sizeof(M)); mcommoninit(m); m->g0 = runtime_malg(-1, nil, nil); 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"); #ifndef PTHREAD_STACK_MIN #define PTHREAD_STACK_MIN 8192 #endif if(pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) runtime_throw("pthread_attr_setstacksize"); if(pthread_create(&tid, &attr, runtime_mstart, m) != 0) runtime_throw("pthread_create"); return m; }
// Called to initialize a new m (including the bootstrap m). // Called on the parent thread (main thread in case of bootstrap), can allocate memory. void runtime_mpreinit(M *mp) { mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K }