2010-12-03 04:34:57 +00:00
// 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.
2011-11-28 05:45:49 +00:00
# include <limits.h>
2013-01-31 17:30:28 +00:00
# include <signal.h>
2011-11-28 05:45:49 +00:00
# include <stdlib.h>
# include <pthread.h>
# include <unistd.h>
# include "config.h"
2012-06-07 00:55:20 +00:00
# ifdef HAVE_DL_ITERATE_PHDR
# include <link.h>
# endif
2010-12-03 04:34:57 +00:00
# include "runtime.h"
2011-10-26 23:57:58 +00:00
# include "arch.h"
2011-11-28 05:45:49 +00:00
# include "defs.h"
# include "malloc.h"
2012-11-21 07:03:38 +00:00
# include "go-type.h"
2011-11-28 05:45:49 +00:00
# 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_find ( void * , void * , size_t * , void * * , void * * ,
void * * ) ;
2011-12-21 22:24:47 +00:00
extern void __splitstack_block_signals ( int * , int * ) ;
extern void __splitstack_block_signals_context ( void * context [ 10 ] , int * ,
int * ) ;
2011-11-28 05:45:49 +00:00
# endif
2012-06-07 00:55:20 +00:00
# ifndef PTHREAD_STACK_MIN
# define PTHREAD_STACK_MIN 8192
# endif
2011-11-28 05:45:49 +00:00
# if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK)
2012-06-07 00:55:20 +00:00
# define StackMin PTHREAD_STACK_MIN
2011-11-28 05:45:49 +00:00
# else
2015-01-05 16:13:06 +00:00
# define StackMin ((sizeof(char *) < 8) ? 2 * 1024 * 1024 : 4 * 1024 * 1024)
2011-11-28 05:45:49 +00:00
# endif
2012-04-20 04:58:26 +00:00
uintptr runtime_stacks_sys ;
2012-05-17 05:30:25 +00:00
static void gtraceback ( G * ) ;
2010-12-03 04:34:57 +00:00
# ifdef __rtems__
# define __thread
# endif
2011-11-28 05:45:49 +00:00
static __thread G * g ;
2012-02-08 05:30:12 +00:00
# ifndef SETCONTEXT_CLOBBERS_TLS
static inline void
initcontext ( void )
{
}
static inline void
fixcontext ( ucontext_t * c __attribute__ ( ( unused ) ) )
{
}
2012-11-05 17:41:07 +00:00
# else
2012-02-08 05:30:12 +00:00
# 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 ;
}
2012-11-05 17:41:07 +00:00
# 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 ;
}
2015-01-16 23:23:31 +00:00
# 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 ] ) ) ;
}
2012-02-08 05:30:12 +00:00
# else
# error unknown case for SETCONTEXT_CLOBBERS_TLS
# endif
# endif
2016-09-09 13:31:49 +00:00
// 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 ucontext_t *
ucontext_arg ( void * * go_ucontext )
{
uintptr_t p = ( uintptr_t ) go_ucontext ;
2016-09-09 16:39:44 +00:00
size_t align = __alignof__ ( ucontext_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 ucontext_t too large " ) ;
}
p = ( p + align - 1 ) & ~ ( uintptr_t ) ( align - 1 ) ;
2016-09-09 13:31:49 +00:00
return ( ucontext_t * ) p ;
}
2011-11-28 05:45:49 +00:00
// 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 )
{
2016-08-30 21:07:47 +00:00
if ( g = = nil )
return nil ;
return g - > m ;
2011-11-28 05:45:49 +00:00
}
2016-08-30 21:07:47 +00:00
// Set g.
2013-07-16 06:54:42 +00:00
void
2016-08-30 21:07:47 +00:00
runtime_setg ( G * gp )
2012-06-07 00:55:20 +00:00
{
2013-07-16 06:54:42 +00:00
g = gp ;
2012-06-07 00:55:20 +00:00
}
2013-07-16 06:54:42 +00:00
// Start a new thread.
2012-06-07 00:55:20 +00:00
static void
2013-07-16 06:54:42 +00:00
runtime_newosproc ( M * mp )
2012-06-07 00:55:20 +00:00
{
2013-07-16 06:54:42 +00:00
pthread_attr_t attr ;
sigset_t clear , old ;
pthread_t tid ;
int ret ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
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 " ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// Block signals during pthread_create so that the new thread
// starts with signals disabled. It will enable them in minit.
sigfillset ( & clear ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
# ifdef SIGTRAP
// Blocking SIGTRAP reportedly breaks gdb on Alpha GNU/Linux.
sigdelset ( & clear , SIGTRAP ) ;
# endif
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
sigemptyset ( & old ) ;
2013-12-04 01:35:53 +00:00
pthread_sigmask ( SIG_BLOCK , & clear , & old ) ;
2013-07-16 06:54:42 +00:00
ret = pthread_create ( & tid , & attr , runtime_mstart , mp ) ;
2013-12-04 01:35:53 +00:00
pthread_sigmask ( SIG_SETMASK , & old , nil ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
if ( ret ! = 0 )
runtime_throw ( " pthread_create " ) ;
2011-11-28 05:45:49 +00:00
}
// First function run by a new goroutine. This replaces gogocall.
static void
kickoff ( void )
{
void ( * fn ) ( void * ) ;
2016-10-12 15:38:56 +00:00
void * param ;
2011-11-28 05:45:49 +00:00
2012-10-23 04:31:11 +00:00
if ( g - > traceback ! = nil )
gtraceback ( g ) ;
2011-11-28 05:45:49 +00:00
fn = ( void ( * ) ( void * ) ) ( g - > entry ) ;
2016-10-12 15:38:56 +00:00
param = g - > param ;
g - > param = nil ;
fn ( param ) ;
2011-11-28 05:45:49 +00:00
runtime_goexit ( ) ;
}
// Switch context to a different goroutine. This is like longjmp.
2013-11-06 19:49:01 +00:00
void runtime_gogo ( G * ) __attribute__ ( ( noinline ) ) ;
void
2011-11-28 05:45:49 +00:00
runtime_gogo ( G * newg )
{
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_setcontext ( & newg - > stackcontext [ 0 ] ) ;
2011-11-28 05:45:49 +00:00
# endif
g = newg ;
newg - > fromgogo = true ;
2016-09-09 13:31:49 +00:00
fixcontext ( ucontext_arg ( & newg - > context [ 0 ] ) ) ;
setcontext ( ucontext_arg ( & newg - > context [ 0 ] ) ) ;
2012-02-08 05:30:12 +00:00
runtime_throw ( " gogo setcontext returned " ) ;
2011-11-28 05:45:49 +00:00
}
// 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.
2013-11-06 19:49:01 +00:00
void runtime_mcall ( void ( * ) ( G * ) ) __attribute__ ( ( noinline ) ) ;
void
2011-11-28 05:45:49 +00:00
runtime_mcall ( void ( * pfn ) ( G * ) )
{
2012-02-14 00:38:07 +00:00
M * mp ;
G * gp ;
runtime: scan caller-saved registers for non-split-stack
While testing a patch on Solaris, which does not support split-stack, I
ran across a bug in the handling of caller-saved registers for the
garbage collector. For non-split-stack systems, runtime_mcall is
responsible for saving all caller-saved registers on the stack so that
the GC stack scan will see them. It does this by calling
__builtin_unwind_init and setting the g's gcnextsp field to point to the
current stack. The garbage collector then scans the stack from gcnextsp
to the top of stack.
Unfortunately, the code was setting gcnextsp to point to runtime_mcall's
argument, which meant that even though runtime_mcall was careful to
store all caller-saved registers on the stack, the GC never saw them.
This is, of course, only a problem if a value lives only in a
caller-saved register, and not anywhere else on the stack or heap. And
it is only a problem if that caller-saved register manages to make it
all the way down to runtime_mcall without being saved by any function on
the way. This is moderately unlikely but it turns out that the recent
changes to keep values on the stack when compiling the runtime package
caused it to happen for the local variable `s` in `notifyListWait` in
runtime/sema.go. That function calls goparkunlock which is simple
enough to not require all registers, and itself calls runtime_mcall. So
it was possible for `s` to be released by the GC before the goroutine
returned from goparkunlock, which eventually caused a dangling pointer
to be passed to releaseSudog.
This is not a problem on split-stack systems, which use
__splitstack_get_context, which saves a stack pointer low enough on the
stack to scan the registers saved by runtime_mcall.
Reviewed-on: https://go-review.googlesource.com/31323
From-SVN: r241304
2016-10-18 13:29:37 +00:00
# ifndef USING_SPLIT_STACK
void * afterregs ;
# endif
2011-11-28 05:45:49 +00:00
// Ensure that all registers are on the stack for the garbage
// collector.
__builtin_unwind_init ( ) ;
2012-02-14 00:38:07 +00:00
gp = g ;
2016-08-30 21:07:47 +00:00
mp = gp - > m ;
2012-02-14 00:38:07 +00:00
if ( gp = = mp - > g0 )
2011-11-28 05:45:49 +00:00
runtime_throw ( " runtime: mcall called on m->g0 stack " ) ;
2012-02-14 00:38:07 +00:00
if ( gp ! = nil ) {
2011-11-28 05:45:49 +00:00
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_getcontext ( & g - > stackcontext [ 0 ] ) ;
2011-11-28 05:45:49 +00:00
# else
runtime: scan caller-saved registers for non-split-stack
While testing a patch on Solaris, which does not support split-stack, I
ran across a bug in the handling of caller-saved registers for the
garbage collector. For non-split-stack systems, runtime_mcall is
responsible for saving all caller-saved registers on the stack so that
the GC stack scan will see them. It does this by calling
__builtin_unwind_init and setting the g's gcnextsp field to point to the
current stack. The garbage collector then scans the stack from gcnextsp
to the top of stack.
Unfortunately, the code was setting gcnextsp to point to runtime_mcall's
argument, which meant that even though runtime_mcall was careful to
store all caller-saved registers on the stack, the GC never saw them.
This is, of course, only a problem if a value lives only in a
caller-saved register, and not anywhere else on the stack or heap. And
it is only a problem if that caller-saved register manages to make it
all the way down to runtime_mcall without being saved by any function on
the way. This is moderately unlikely but it turns out that the recent
changes to keep values on the stack when compiling the runtime package
caused it to happen for the local variable `s` in `notifyListWait` in
runtime/sema.go. That function calls goparkunlock which is simple
enough to not require all registers, and itself calls runtime_mcall. So
it was possible for `s` to be released by the GC before the goroutine
returned from goparkunlock, which eventually caused a dangling pointer
to be passed to releaseSudog.
This is not a problem on split-stack systems, which use
__splitstack_get_context, which saves a stack pointer low enough on the
stack to scan the registers saved by runtime_mcall.
Reviewed-on: https://go-review.googlesource.com/31323
From-SVN: r241304
2016-10-18 13:29:37 +00:00
// We have to point to an address on the stack that is
// below the saved registers.
gp - > gcnextsp = & afterregs ;
2011-11-28 05:45:49 +00:00
# endif
2012-02-14 00:38:07 +00:00
gp - > fromgogo = false ;
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & gp - > context [ 0 ] ) ) ;
2012-02-14 00:38:07 +00:00
// When we return from getcontext, we may be running
2016-08-30 21:07:47 +00:00
// 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.
2012-02-14 00:38:07 +00:00
gp = runtime_g ( ) ;
2016-08-30 21:07:47 +00:00
mp = gp - > m ;
2012-05-17 05:30:25 +00:00
2012-05-24 21:07:18 +00:00
if ( gp - > traceback ! = nil )
2012-05-17 05:30:25 +00:00
gtraceback ( gp ) ;
2011-11-28 05:45:49 +00:00
}
2012-02-14 00:38:07 +00:00
if ( gp = = nil | | ! gp - > fromgogo ) {
2011-11-28 05:45:49 +00:00
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_setcontext ( & mp - > g0 - > stackcontext [ 0 ] ) ;
2011-11-28 05:45:49 +00:00
# endif
2012-02-14 00:38:07 +00:00
mp - > g0 - > entry = ( byte * ) pfn ;
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 ;
2016-09-09 13:31:49 +00:00
fixcontext ( ucontext_arg ( & mp - > g0 - > context [ 0 ] ) ) ;
setcontext ( ucontext_arg ( & mp - > g0 - > context [ 0 ] ) ) ;
2011-11-28 05:45:49 +00:00
runtime_throw ( " runtime: mcall function returned " ) ;
}
}
2013-07-16 06:54:42 +00:00
// 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.
2016-11-18 17:48:29 +00:00
typedef struct schedt Sched ;
2013-07-16 06:54:42 +00:00
2014-06-06 22:37:27 +00:00
enum
{
2016-11-18 17:48:29 +00:00
// Number of goroutine ids to grab from runtime_sched->goidgen to local per-P cache at once.
2014-06-06 22:37:27 +00:00
// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
GoidCacheBatch = 16 ,
} ;
2013-07-16 06:54:42 +00:00
2016-11-18 17:48:29 +00:00
extern Sched * runtime_getsched ( ) __asm__ ( GOSYM_PREFIX " runtime.getsched " ) ;
static Sched * runtime_sched ;
2013-07-16 06:54:42 +00:00
int32 runtime_gomaxprocs ;
2013-07-23 20:26:09 +00:00
uint32 runtime_needextram = 1 ;
2013-07-16 06:54:42 +00:00
M runtime_m0 ;
2014-06-06 22:37:27 +00:00
G runtime_g0 ; // idle goroutine for m0
2013-07-16 06:54:42 +00:00
G * runtime_lastg ;
M * runtime_allm ;
P * * runtime_allp ;
M * runtime_extram ;
int8 * runtime_goos ;
int32 runtime_ncpu ;
2013-11-06 19:49:01 +00:00
bool runtime_precisestack ;
2013-07-16 06:54:42 +00:00
static int32 newprocs ;
2014-06-06 22:37:27 +00:00
static Lock allglock ; // the following vars are protected by this lock or by stoptheworld
G * * runtime_allg ;
uintptr runtime_allglen ;
static uintptr allgcap ;
2015-04-29 21:31:53 +00:00
bool runtime_isarchive ;
2013-07-16 06:54:42 +00:00
void * runtime_mstart ( void * ) ;
static void runqput ( P * , G * ) ;
static G * runqget ( P * ) ;
2014-06-06 22:37:27 +00:00
static bool runqputslow ( P * , G * , uint32 , uint32 ) ;
2013-07-16 06:54:42 +00:00
static G * runqsteal ( P * , P * ) ;
static void mput ( M * ) ;
static M * mget ( void ) ;
static void mcommoninit ( M * ) ;
static void schedule ( void ) ;
static void procresize ( int32 ) ;
static void acquirep ( P * ) ;
static P * releasep ( void ) ;
static void newm ( void ( * ) ( void ) , P * ) ;
static void stopm ( void ) ;
static void startm ( P * , bool ) ;
static void handoffp ( P * ) ;
static void wakep ( void ) ;
static void stoplockedm ( void ) ;
static void startlockedm ( G * ) ;
static void sysmon ( void ) ;
2013-11-06 19:49:01 +00:00
static uint32 retake ( int64 ) ;
static void incidlelocked ( int32 ) ;
2013-07-16 06:54:42 +00:00
static void checkdead ( void ) ;
static void exitsyscall0 ( G * ) ;
static void park0 ( G * ) ;
static void goexit0 ( G * ) ;
static void gfput ( P * , G * ) ;
static G * gfget ( P * ) ;
static void gfpurge ( P * ) ;
static void globrunqput ( G * ) ;
2014-06-06 22:37:27 +00:00
static void globrunqputbatch ( G * , G * , int32 ) ;
2013-11-06 19:49:01 +00:00
static G * globrunqget ( P * , int32 ) ;
2013-07-16 06:54:42 +00:00
static P * pidleget ( void ) ;
static void pidleput ( P * ) ;
static void injectglist ( G * ) ;
2013-11-06 19:49:01 +00:00
static bool preemptall ( void ) ;
static bool exitsyscallfast ( void ) ;
2014-06-06 22:37:27 +00:00
static void allgadd ( G * ) ;
2012-03-02 20:01:37 +00:00
2015-04-29 21:31:53 +00:00
bool runtime_isstarted ;
2011-11-28 05:45:49 +00:00
// The bootstrap sequence is:
//
// call osinit
// call schedinit
// make & queue new G
// call runtime_mstart
//
2011-12-02 19:34:41 +00:00
// The new G calls runtime_main.
2011-11-28 05:45:49 +00:00
void
runtime_schedinit ( void )
{
2016-08-30 21:07:47 +00:00
M * m ;
2013-07-16 06:54:42 +00:00
int32 n , procs ;
2015-10-31 00:59:47 +00:00
String s ;
2011-11-28 05:45:49 +00:00
const byte * p ;
2013-11-06 19:49:01 +00:00
Eface i ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
runtime_sched = runtime_getsched ( ) ;
2011-11-28 05:45:49 +00:00
m = & runtime_m0 ;
g = & runtime_g0 ;
m - > g0 = g ;
m - > curg = g ;
g - > m = m ;
2012-02-08 05:30:12 +00:00
initcontext ( ) ;
2016-11-18 17:48:29 +00:00
runtime_sched - > maxmcount = 10000 ;
2013-11-06 19:49:01 +00:00
runtime_precisestack = 0 ;
2014-07-19 08:53:52 +00:00
// runtime_symtabinit();
2011-11-28 05:45:49 +00:00
runtime_mallocinit ( ) ;
mcommoninit ( m ) ;
2013-11-06 19:49:01 +00:00
// Initialize the itable value for newErrorCString,
// so that the next time it gets called, possibly
// in a fault during a garbage collection, it will not
// need to allocated memory.
runtime_newErrorCString ( 0 , & i ) ;
2014-07-19 08:53:52 +00:00
// Initialize the cached gotraceback value, since
// gotraceback calls getenv, which mallocs on Plan 9.
runtime_gotraceback ( nil ) ;
2011-11-28 05:45:49 +00:00
runtime_goargs ( ) ;
runtime_goenvs ( ) ;
2013-11-06 19:49:01 +00:00
runtime_parsedebugvars ( ) ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
runtime_sched - > lastpoll = runtime_nanotime ( ) ;
2013-07-16 06:54:42 +00:00
procs = 1 ;
2015-10-31 00:59:47 +00:00
s = runtime_getenv ( " GOMAXPROCS " ) ;
p = s . str ;
if ( p ! = nil & & ( n = runtime_atoi ( p , s . len ) ) > 0 ) {
2016-08-30 21:07:47 +00:00
if ( n > _MaxGomaxprocs )
n = _MaxGomaxprocs ;
2013-07-16 06:54:42 +00:00
procs = n ;
2011-11-28 05:45:49 +00:00
}
2016-08-30 21:07:47 +00:00
runtime_allp = runtime_malloc ( ( _MaxGomaxprocs + 1 ) * sizeof ( runtime_allp [ 0 ] ) ) ;
2013-07-16 06:54:42 +00:00
procresize ( procs ) ;
2011-11-28 05:45:49 +00:00
// Can not enable GC until all roots are registered.
2016-10-13 15:24:50 +00:00
// mstats()->enablegc = 1;
2011-11-28 05:45:49 +00:00
}
2013-01-24 19:44:23 +00:00
extern void main_init ( void ) __asm__ ( GOSYM_PREFIX " __go_init_main " ) ;
extern void main_main ( void ) __asm__ ( GOSYM_PREFIX " main.main " ) ;
2011-12-02 19:34:41 +00:00
2015-04-29 21:31:53 +00:00
// Used to determine the field alignment.
struct field_align
{
char c ;
Hchan * p ;
} ;
// main_init_done is a signal used by cgocallbackg that initialization
// has been completed. It is made before _cgo_notify_runtime_init_done,
// so all cgo calls can rely on it existing. When main_init is
// complete, it is closed, meaning cgocallbackg can reliably receive
// from it.
Hchan * runtime_main_init_done ;
// The chan bool type, for runtime_main_init_done.
extern const struct __go_type_descriptor bool_type_descriptor
__asm__ ( GOSYM_PREFIX " __go_tdn_bool " ) ;
static struct __go_channel_type chan_bool_type_descriptor =
{
/* __common */
{
/* __code */
GO_CHAN ,
/* __align */
__alignof ( Hchan * ) ,
/* __field_align */
offsetof ( struct field_align , p ) - 1 ,
/* __size */
sizeof ( Hchan * ) ,
/* __hash */
0 , /* This value doesn't matter. */
/* __hashfn */
compiler, runtime: replace hashmap code with Go 1.7 hashmap
This change removes the gccgo-specific hashmap code and replaces it with
the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is
more efficient, does a better job on details like when to update a key,
and provides some support against denial-of-service attacks.
The compiler is changed to call the new hashmap functions instead of the
old ones.
The compiler now tracks which types are reflexive and which require
updating when used as a map key, and records the information in map type
descriptors.
Map_index_expression is simplified. The special case for a map index on
the right hand side of a tuple expression has been unnecessary for some
time, and is removed. The support for specially marking a map index as
an lvalue is removed, in favor of lowering an assignment to a map index
into a function call. The long-obsolete support for a map index of a
pointer to a map is removed.
The __go_new_map_big function (known to the compiler as
Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap
function takes an int64 hint argument.
The old map descriptor type and supporting expression is removed.
The compiler was still supporting the long-obsolete syntax `m[k] = 0,
false` to delete a value from a map. That is now removed, requiring a
change to one of the gccgo-specific tests.
The builtin len function applied to a map or channel p is now compiled
as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to
the compiler as Runtime::CHAN_LEN) is removed.
Support for a shared zero value for maps to large value types is
introduced, along the lines of the gc compiler. The zero value is
handled as a common variable.
The hash function is changed to take a seed argument, changing the
runtime hash functions and the compiler-generated hash functions.
Unlike the gc compiler, both the hash and equal functions continue to
take the type length.
Types that can not be compared now store nil for the hash and equal
functions, rather than pointing to functions that throw. Interface hash
and comparison functions now check explicitly for nil. This matches the
gc compiler and permits a simple implementation for ismapkey.
The compiler is changed to permit marking struct and array types as
incomparable, meaning that they have no hash or equal function. We use
this for thunk types, removing the existing special code to avoid
generating hash/equal functions for them.
The C runtime code adds memclr, memequal, and memmove functions.
The hashmap code uses go:linkname comments to make the functions
visible, as otherwise the compiler would discard them.
The hashmap code comments out the unused reference to the address of the
first parameter in the race code, as otherwise the compiler thinks that
the parameter escapes and copies it onto the heap. This is probably not
needed when we enable escape analysis.
Several runtime map tests that ere previously skipped for gccgo are now
run.
The Go runtime picks up type kind information and stubs. The type kind
information causes the generated runtime header file to define some
constants, including `empty`, and the C code is adjusted accordingly.
A Go-callable version of runtime.throw, that takes a Go string, is
added to be called from the hashmap code.
Reviewed-on: https://go-review.googlesource.com/29447
* go.go-torture/execute/map-1.go: Replace old map deletion syntax
with call to builtin delete function.
From-SVN: r240334
2016-09-21 20:58:51 +00:00
NULL ,
2015-04-29 21:31:53 +00:00
/* __equalfn */
compiler, runtime: replace hashmap code with Go 1.7 hashmap
This change removes the gccgo-specific hashmap code and replaces it with
the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is
more efficient, does a better job on details like when to update a key,
and provides some support against denial-of-service attacks.
The compiler is changed to call the new hashmap functions instead of the
old ones.
The compiler now tracks which types are reflexive and which require
updating when used as a map key, and records the information in map type
descriptors.
Map_index_expression is simplified. The special case for a map index on
the right hand side of a tuple expression has been unnecessary for some
time, and is removed. The support for specially marking a map index as
an lvalue is removed, in favor of lowering an assignment to a map index
into a function call. The long-obsolete support for a map index of a
pointer to a map is removed.
The __go_new_map_big function (known to the compiler as
Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap
function takes an int64 hint argument.
The old map descriptor type and supporting expression is removed.
The compiler was still supporting the long-obsolete syntax `m[k] = 0,
false` to delete a value from a map. That is now removed, requiring a
change to one of the gccgo-specific tests.
The builtin len function applied to a map or channel p is now compiled
as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to
the compiler as Runtime::CHAN_LEN) is removed.
Support for a shared zero value for maps to large value types is
introduced, along the lines of the gc compiler. The zero value is
handled as a common variable.
The hash function is changed to take a seed argument, changing the
runtime hash functions and the compiler-generated hash functions.
Unlike the gc compiler, both the hash and equal functions continue to
take the type length.
Types that can not be compared now store nil for the hash and equal
functions, rather than pointing to functions that throw. Interface hash
and comparison functions now check explicitly for nil. This matches the
gc compiler and permits a simple implementation for ismapkey.
The compiler is changed to permit marking struct and array types as
incomparable, meaning that they have no hash or equal function. We use
this for thunk types, removing the existing special code to avoid
generating hash/equal functions for them.
The C runtime code adds memclr, memequal, and memmove functions.
The hashmap code uses go:linkname comments to make the functions
visible, as otherwise the compiler would discard them.
The hashmap code comments out the unused reference to the address of the
first parameter in the race code, as otherwise the compiler thinks that
the parameter escapes and copies it onto the heap. This is probably not
needed when we enable escape analysis.
Several runtime map tests that ere previously skipped for gccgo are now
run.
The Go runtime picks up type kind information and stubs. The type kind
information causes the generated runtime header file to define some
constants, including `empty`, and the C code is adjusted accordingly.
A Go-callable version of runtime.throw, that takes a Go string, is
added to be called from the hashmap code.
Reviewed-on: https://go-review.googlesource.com/29447
* go.go-torture/execute/map-1.go: Replace old map deletion syntax
with call to builtin delete function.
From-SVN: r240334
2016-09-21 20:58:51 +00:00
NULL ,
2015-04-29 21:31:53 +00:00
/* __gc */
NULL , /* This value doesn't matter */
/* __reflection */
NULL , /* This value doesn't matter */
/* __uncommon */
NULL ,
/* __pointer_to_this */
2015-10-29 18:14:50 +00:00
NULL
2015-04-29 21:31:53 +00:00
} ,
/* __element_type */
& bool_type_descriptor ,
/* __dir */
CHANNEL_BOTH_DIR
} ;
2016-10-10 16:52:09 +00:00
extern Hchan * makechan ( ChanType * , int64 )
__asm__ ( GOSYM_PREFIX " runtime.makechan " ) ;
2015-04-29 21:31:53 +00:00
extern void closechan ( Hchan * ) __asm__ ( GOSYM_PREFIX " runtime.closechan " ) ;
2013-11-06 19:49:01 +00:00
static void
initDone ( void * arg __attribute__ ( ( unused ) ) ) {
runtime_unlockOSThread ( ) ;
} ;
2011-12-02 19:34:41 +00:00
// The main goroutine.
2014-07-19 08:53:52 +00:00
// Note: C frames in general are not copyable during stack growth, for two reasons:
// 1) We don't know where in a frame to find pointers to other stack locations.
// 2) There's no guarantee that globals or heap values do not point into the frame.
//
// The C frame for runtime.main is copyable, because:
// 1) There are no pointers to other stack locations in the frame
// (d.fn points at a global, d.link is nil, d.argp is -1).
// 2) The only pointer into this frame is from the defer chain,
// which is explicitly handled during stack copying.
2011-12-02 19:34:41 +00:00
void
2013-07-16 06:54:42 +00:00
runtime_main ( void * dummy __attribute__ ( ( unused ) ) )
2011-12-02 19:34:41 +00:00
{
2013-11-06 19:49:01 +00:00
Defer d ;
_Bool frame ;
2013-07-16 06:54:42 +00:00
newm ( sysmon , nil ) ;
2011-12-02 19:34:41 +00:00
// Lock the main goroutine onto this, the main OS thread,
// during initialization. Most programs won't care, but a few
// do require certain calls to be made by the main thread.
// Those can arrange for main.main to run in the main thread
// by calling runtime.LockOSThread during initialization
// to preserve the lock.
2013-07-16 06:54:42 +00:00
runtime_lockOSThread ( ) ;
2013-11-06 19:49:01 +00:00
// Defer unlock so that runtime.Goexit during init does the unlock too.
2016-08-30 21:07:47 +00:00
d . pfn = ( uintptr ) ( void * ) initDone ;
d . next = g - > _defer ;
d . arg = ( void * ) - 1 ;
d . _panic = g - > _panic ;
d . retaddr = 0 ;
d . makefunccanrecover = 0 ;
d . frame = & frame ;
d . special = true ;
g - > _defer = & d ;
if ( g - > m ! = & runtime_m0 )
2013-07-16 06:54:42 +00:00
runtime_throw ( " runtime_main not on m0 " ) ;
__go_go ( runtime_MHeap_Scavenger , nil ) ;
2015-04-29 21:31:53 +00:00
2016-10-10 16:52:09 +00:00
runtime_main_init_done = makechan ( & chan_bool_type_descriptor , 0 ) ;
2015-04-29 21:31:53 +00:00
_cgo_notify_runtime_init_done ( ) ;
2011-12-02 19:34:41 +00:00
main_init ( ) ;
2013-11-06 19:49:01 +00:00
2015-04-29 21:31:53 +00:00
closechan ( runtime_main_init_done ) ;
2016-08-30 21:07:47 +00:00
if ( g - > _defer ! = & d | | ( void * ) d . pfn ! = initDone )
2013-11-06 19:49:01 +00:00
runtime_throw ( " runtime: bad defer entry after init " ) ;
2016-08-30 21:07:47 +00:00
g - > _defer = d . next ;
2013-07-16 06:54:42 +00:00
runtime_unlockOSThread ( ) ;
2011-12-02 19:34:41 +00:00
// For gccgo we have to wait until after main is initialized
// to enable GC, because initializing main registers the GC
// roots.
2016-10-13 15:24:50 +00:00
mstats ( ) - > enablegc = 1 ;
2011-12-02 19:34:41 +00:00
2015-04-29 21:31:53 +00:00
if ( runtime_isarchive ) {
// This is not a complete program, but is instead a
// library built using -buildmode=c-archive or
// c-shared. Now that we are initialized, there is
// nothing further to do.
return ;
}
2011-12-02 19:34:41 +00:00
main_main ( ) ;
2013-07-16 06:54:42 +00:00
// Make racy client program work: if panicking on
// another goroutine at the same time as main returns,
// let the other goroutine finish printing the panic trace.
// Once it does, it will exit. See issue 3934.
if ( runtime_panicking )
runtime_park ( nil , nil , " panicwait " ) ;
2011-12-02 19:34:41 +00:00
runtime_exit ( 0 ) ;
for ( ; ; )
* ( int32 * ) 0 = 0 ;
}
2012-05-17 05:30:25 +00:00
void
runtime_tracebackothers ( G * volatile me )
{
2012-10-23 04:31:11 +00:00
G * volatile gp ;
2013-01-30 01:37:13 +00:00
Traceback tb ;
int32 traceback ;
2016-10-14 22:51:46 +00:00
Slice slice ;
2014-06-06 22:37:27 +00:00
volatile uintptr i ;
2011-11-28 05:45:49 +00:00
2013-01-30 01:37:13 +00:00
tb . gp = me ;
2013-07-16 06:54:42 +00:00
traceback = runtime_gotraceback ( nil ) ;
2013-11-06 19:49:01 +00:00
// Show the current goroutine first, if we haven't already.
2016-08-30 21:07:47 +00:00
if ( ( gp = g - > m - > curg ) ! = nil & & gp ! = me ) {
2013-11-06 19:49:01 +00:00
runtime_printf ( " \n " ) ;
runtime_goroutineheader ( gp ) ;
gp - > traceback = & tb ;
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_getcontext ( & me - > stackcontext [ 0 ] ) ;
2013-11-06 19:49:01 +00:00
# endif
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & me - > context [ 0 ] ) ) ;
2013-11-06 19:49:01 +00:00
if ( gp - > traceback ! = nil ) {
runtime_gogo ( gp ) ;
}
2016-10-14 22:51:46 +00:00
slice . __values = & tb . locbuf [ 0 ] ;
slice . __count = tb . c ;
slice . __capacity = tb . c ;
runtime_printtrace ( slice , nil ) ;
2013-11-06 19:49:01 +00:00
runtime_printcreatedby ( gp ) ;
}
2014-06-06 22:37:27 +00:00
runtime_lock ( & allglock ) ;
for ( i = 0 ; i < runtime_allglen ; i + + ) {
gp = runtime_allg [ i ] ;
2016-08-30 21:07:47 +00:00
if ( gp = = me | | gp = = g - > m - > curg | | gp - > atomicstatus = = _Gdead )
2011-11-28 05:45:49 +00:00
continue ;
2013-01-30 01:37:13 +00:00
if ( gp - > issystem & & traceback < 2 )
continue ;
2011-11-28 05:45:49 +00:00
runtime_printf ( " \n " ) ;
2012-10-23 04:31:11 +00:00
runtime_goroutineheader ( gp ) ;
2012-05-17 05:30:25 +00:00
// Our only mechanism for doing a stack trace is
// _Unwind_Backtrace. And that only works for the
// current thread, not for other random goroutines.
// So we need to switch context to the goroutine, get
// the backtrace, and then switch back.
// This means that if g is running or in a syscall, we
// can't reliably print a stack trace. FIXME.
2016-08-30 21:07:47 +00:00
if ( gp - > atomicstatus = = _Grunning ) {
2013-11-06 19:49:01 +00:00
runtime_printf ( " \t goroutine running on other thread; stack unavailable \n " ) ;
runtime_printcreatedby ( gp ) ;
2016-08-30 21:07:47 +00:00
} else if ( gp - > atomicstatus = = _Gsyscall ) {
2013-11-06 19:49:01 +00:00
runtime_printf ( " \t goroutine in C code; stack unavailable \n " ) ;
runtime_printcreatedby ( gp ) ;
} else {
gp - > traceback = & tb ;
2012-05-17 05:30:25 +00:00
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_getcontext ( & me - > stackcontext [ 0 ] ) ;
2012-05-17 05:30:25 +00:00
# endif
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & me - > context [ 0 ] ) ) ;
2012-05-17 05:30:25 +00:00
2013-11-06 19:49:01 +00:00
if ( gp - > traceback ! = nil ) {
runtime_gogo ( gp ) ;
}
2016-10-14 22:51:46 +00:00
slice . __values = & tb . locbuf [ 0 ] ;
slice . __count = tb . c ;
slice . __capacity = tb . c ;
runtime_printtrace ( slice , nil ) ;
2013-11-06 19:49:01 +00:00
runtime_printcreatedby ( gp ) ;
2012-05-17 05:30:25 +00:00
}
2013-11-06 19:49:01 +00:00
}
2014-06-06 22:37:27 +00:00
runtime_unlock ( & allglock ) ;
2013-11-06 19:49:01 +00:00
}
2012-05-24 21:07:18 +00:00
2013-11-06 19:49:01 +00:00
static void
checkmcount ( void )
{
// sched lock is held
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > mcount > runtime_sched - > maxmcount ) {
runtime_printf ( " runtime: program exceeds %d-thread limit \n " , runtime_sched - > maxmcount ) ;
2013-11-06 19:49:01 +00:00
runtime_throw ( " thread exhaustion " ) ;
2011-11-28 05:45:49 +00:00
}
}
2012-05-17 05:30:25 +00:00
// Do a stack trace of gp, and then restore the context to
// gp->dotraceback.
static void
gtraceback ( G * gp )
{
2012-05-24 21:07:18 +00:00
Traceback * traceback ;
2012-05-17 05:30:25 +00:00
2012-05-24 21:07:18 +00:00
traceback = gp - > traceback ;
gp - > traceback = nil ;
2016-08-30 21:07:47 +00:00
if ( gp - > m ! = nil )
runtime_throw ( " gtraceback: m is not nil " ) ;
gp - > m = traceback - > gp - > m ;
2013-01-30 22:24:40 +00:00
traceback - > c = runtime_callers ( 1 , traceback - > locbuf ,
2014-07-19 21:36:26 +00:00
sizeof traceback - > locbuf / sizeof traceback - > locbuf [ 0 ] , false ) ;
2016-08-30 21:07:47 +00:00
gp - > m = nil ;
2012-05-24 21:07:18 +00:00
runtime_gogo ( traceback - > gp ) ;
2012-05-17 05:30:25 +00:00
}
2011-11-28 05:45:49 +00:00
static void
2012-10-23 04:31:11 +00:00
mcommoninit ( M * mp )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
// If there is no mcache runtime_callers() will crash,
// and we are most likely in sysmon thread so the stack is senseless anyway.
2016-08-30 21:07:47 +00:00
if ( g - > m - > mcache )
2014-07-19 21:36:26 +00:00
runtime_callers ( 1 , mp - > createstack , nelem ( mp - > createstack ) , false ) ;
2013-07-16 06:54:42 +00:00
2012-10-23 04:31:11 +00:00
mp - > fastrand = 0x49f6428aUL + mp - > id + runtime_cputicks ( ) ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
mp - > id = runtime_sched - > mcount + + ;
2013-11-06 19:49:01 +00:00
checkmcount ( ) ;
2013-07-16 06:54:42 +00:00
runtime_mpreinit ( mp ) ;
2012-03-06 17:57:23 +00:00
2012-03-02 16:38:43 +00:00
// Add to runtime_allm so garbage collector doesn't free m
// when it is just in a register or thread-local storage.
2012-10-23 04:31:11 +00:00
mp - > alllink = runtime_allm ;
2012-03-02 20:01:37 +00:00
// runtime_NumCgoCall() iterates over allm w/o schedlock,
2012-03-02 16:38:43 +00:00
// so we need to publish it safely.
2012-10-23 04:31:11 +00:00
runtime_atomicstorep ( & runtime_allm , mp ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
// Mark gp ready to run.
void
runtime_ready ( G * gp )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
// Mark runnable.
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ; // disable preemption because it can be holding p in a local var
if ( gp - > atomicstatus ! = _Gwaiting ) {
runtime_printf ( " goroutine %D has status %d \n " , gp - > goid , gp - > atomicstatus ) ;
runtime_throw ( " bad g->atomicstatus in ready " ) ;
2011-11-28 05:45:49 +00:00
}
2016-08-30 21:07:47 +00:00
gp - > atomicstatus = _Grunnable ;
runqput ( ( P * ) g - > m - > p , gp ) ;
2016-11-18 17:48:29 +00:00
if ( runtime_atomicload ( & runtime_sched - > npidle ) ! = 0 & & runtime_atomicload ( & runtime_sched - > nmspinning ) = = 0 ) // TODO: fast atomic
2013-07-16 06:54:42 +00:00
wakep ( ) ;
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
}
2016-10-10 16:52:09 +00:00
void goready ( G * , int ) __asm__ ( GOSYM_PREFIX " runtime.goready " ) ;
void
goready ( G * gp , int traceskip __attribute__ ( ( unused ) ) )
{
runtime_ready ( gp ) ;
}
2013-07-16 06:54:42 +00:00
int32
runtime_gcprocs ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
int32 n ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// Figure out how many CPUs to use during GC.
// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
n = runtime_gomaxprocs ;
if ( n > runtime_ncpu )
n = runtime_ncpu > 0 ? runtime_ncpu : 1 ;
if ( n > MaxGcproc )
n = MaxGcproc ;
2016-11-18 17:48:29 +00:00
if ( n > runtime_sched - > nmidle + 1 ) // one M is currently running
n = runtime_sched - > nmidle + 1 ;
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
return n ;
2011-11-28 05:45:49 +00:00
}
static bool
2013-07-16 06:54:42 +00:00
needaddgcproc ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
int32 n ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
n = runtime_gomaxprocs ;
if ( n > runtime_ncpu )
n = runtime_ncpu ;
if ( n > MaxGcproc )
n = MaxGcproc ;
2016-11-18 17:48:29 +00:00
n - = runtime_sched - > nmidle + 1 ; // one M is currently running
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
return n > 0 ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
void
runtime_helpgc ( int32 nproc )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
M * mp ;
int32 n , pos ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
pos = 0 ;
for ( n = 1 ; n < nproc ; n + + ) { // one M is currently running
2016-08-30 21:07:47 +00:00
if ( runtime_allp [ pos ] - > mcache = = g - > m - > mcache )
2013-07-16 06:54:42 +00:00
pos + + ;
mp = mget ( ) ;
if ( mp = = nil )
runtime_throw ( " runtime_gcprocs inconsistency " ) ;
mp - > helpgc = n ;
mp - > mcache = runtime_allp [ pos ] - > mcache ;
pos + + ;
runtime_notewakeup ( & mp - > park ) ;
2011-11-28 05:45:49 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
}
2013-11-06 19:49:01 +00:00
// Similar to stoptheworld but best-effort and can be called several times.
// There is no reverse operation, used during crashing.
// This function must not lock any mutexes.
void
runtime_freezetheworld ( void )
{
int32 i ;
if ( runtime_gomaxprocs = = 1 )
return ;
// stopwait and preemption requests can be lost
// due to races with concurrently executing threads,
// so try several times
for ( i = 0 ; i < 5 ; i + + ) {
// this should tell the scheduler to not start any new goroutines
2016-11-18 17:48:29 +00:00
runtime_sched - > stopwait = 0x7fffffff ;
runtime_atomicstore ( ( uint32 * ) & runtime_sched - > gcwaiting , 1 ) ;
2013-11-06 19:49:01 +00:00
// this should stop running goroutines
if ( ! preemptall ( ) )
break ; // no running goroutines
runtime_usleep ( 1000 ) ;
}
// to be sure
runtime_usleep ( 1000 ) ;
preemptall ( ) ;
runtime_usleep ( 1000 ) ;
}
2013-07-16 06:54:42 +00:00
void
2016-10-13 15:24:50 +00:00
runtime_stopTheWorldWithSema ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
int32 i ;
uint32 s ;
P * p ;
bool wait ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
runtime_sched - > stopwait = runtime_gomaxprocs ;
runtime_atomicstore ( ( uint32 * ) & runtime_sched - > gcwaiting , 1 ) ;
2013-11-06 19:49:01 +00:00
preemptall ( ) ;
2013-07-16 06:54:42 +00:00
// stop current P
2016-08-30 21:07:47 +00:00
( ( P * ) g - > m - > p ) - > status = _Pgcstop ;
2016-11-18 17:48:29 +00:00
runtime_sched - > stopwait - - ;
2016-08-30 21:07:47 +00:00
// try to retake all P's in _Psyscall status
2013-07-16 06:54:42 +00:00
for ( i = 0 ; i < runtime_gomaxprocs ; i + + ) {
p = runtime_allp [ i ] ;
s = p - > status ;
2016-08-30 21:07:47 +00:00
if ( s = = _Psyscall & & runtime_cas ( & p - > status , s , _Pgcstop ) )
2016-11-18 17:48:29 +00:00
runtime_sched - > stopwait - - ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
// stop idle P's
while ( ( p = pidleget ( ) ) ! = nil ) {
2016-08-30 21:07:47 +00:00
p - > status = _Pgcstop ;
2016-11-18 17:48:29 +00:00
runtime_sched - > stopwait - - ;
2011-11-28 05:45:49 +00:00
}
2016-11-18 17:48:29 +00:00
wait = runtime_sched - > stopwait > 0 ;
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
2013-11-06 19:49:01 +00:00
// wait for remaining P's to stop voluntarily
2013-07-16 06:54:42 +00:00
if ( wait ) {
2016-11-18 17:48:29 +00:00
runtime_notesleep ( & runtime_sched - > stopnote ) ;
runtime_noteclear ( & runtime_sched - > stopnote ) ;
2013-07-16 06:54:42 +00:00
}
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > stopwait )
2013-07-16 06:54:42 +00:00
runtime_throw ( " stoptheworld: not stopped " ) ;
for ( i = 0 ; i < runtime_gomaxprocs ; i + + ) {
p = runtime_allp [ i ] ;
2016-08-30 21:07:47 +00:00
if ( p - > status ! = _Pgcstop )
2013-07-16 06:54:42 +00:00
runtime_throw ( " stoptheworld: not stopped " ) ;
2011-11-28 05:45:49 +00:00
}
}
static void
2013-07-16 06:54:42 +00:00
mhelpgc ( void )
2011-11-28 05:45:49 +00:00
{
2016-08-30 21:07:47 +00:00
g - > m - > helpgc = - 1 ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
void
2016-10-13 15:24:50 +00:00
runtime_startTheWorldWithSema ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
P * p , * p1 ;
M * mp ;
2011-11-28 05:45:49 +00:00
G * gp ;
2013-07-16 06:54:42 +00:00
bool add ;
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ; // disable preemption because it can be holding p in a local var
2013-07-16 06:54:42 +00:00
gp = runtime_netpoll ( false ) ; // non-blocking
injectglist ( gp ) ;
add = needaddgcproc ( ) ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( newprocs ) {
procresize ( newprocs ) ;
newprocs = 0 ;
} else
procresize ( runtime_gomaxprocs ) ;
2016-11-18 17:48:29 +00:00
runtime_sched - > gcwaiting = 0 ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
p1 = nil ;
while ( ( p = pidleget ( ) ) ! = nil ) {
// procresize() puts p's with work at the beginning of the list.
// Once we reach a p without a run queue, the rest don't have one either.
if ( p - > runqhead = = p - > runqtail ) {
pidleput ( p ) ;
break ;
2011-11-28 05:45:49 +00:00
}
2016-08-30 21:07:47 +00:00
p - > m = ( uintptr ) mget ( ) ;
p - > link = ( uintptr ) p1 ;
2013-11-06 19:49:01 +00:00
p1 = p ;
2011-11-28 05:45:49 +00:00
}
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > sysmonwait ) {
runtime_sched - > sysmonwait = false ;
runtime_notewakeup ( & runtime_sched - > sysmonnote ) ;
2011-11-28 05:45:49 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
while ( p1 ) {
p = p1 ;
2016-08-30 21:07:47 +00:00
p1 = ( P * ) p1 - > link ;
2013-11-06 19:49:01 +00:00
if ( p - > m ) {
2016-08-30 21:07:47 +00:00
mp = ( M * ) p - > m ;
p - > m = 0 ;
2013-11-06 19:49:01 +00:00
if ( mp - > nextp )
2016-10-13 15:24:50 +00:00
runtime_throw ( " startTheWorldWithSema: inconsistent mp->nextp " ) ;
2016-08-30 21:07:47 +00:00
mp - > nextp = ( uintptr ) p ;
2013-11-06 19:49:01 +00:00
runtime_notewakeup ( & mp - > park ) ;
} else {
// Start M to run P. Do not start another M below.
newm ( nil , p ) ;
add = false ;
}
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
if ( add ) {
2012-10-23 04:31:11 +00:00
// If GC could have used another helper proc, start one now,
// in the hope that it will be available next time.
// It would have been even better to start it before the collection,
// but doing so requires allocating memory, so it's tricky to
// coordinate. This lazy approach works out in practice:
// we don't mind if the first couple gc rounds don't have quite
// the maximum number of procs.
2013-07-16 06:54:42 +00:00
newm ( mhelpgc , nil ) ;
2011-11-28 05:45:49 +00:00
}
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
}
// Called to start an M.
void *
runtime_mstart ( void * mp )
{
2016-08-30 21:07:47 +00:00
M * m ;
2011-11-28 05:45:49 +00:00
m = ( M * ) mp ;
g = m - > g0 ;
2016-08-30 21:07:47 +00:00
g - > m = m ;
2011-11-28 05:45:49 +00:00
2012-02-08 05:30:12 +00:00
initcontext ( ) ;
2011-11-28 05:45:49 +00:00
g - > entry = nil ;
g - > param = nil ;
// 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
2016-08-30 21:07:47 +00:00
__splitstack_getcontext ( & g - > stackcontext [ 0 ] ) ;
2011-11-28 05:45:49 +00:00
# else
2016-08-30 21:07:47 +00:00
g - > gcinitialsp = & mp ;
// Setting gcstacksize to 0 is a marker meaning that gcinitialsp
2012-02-10 15:55:37 +00:00
// is the top of the stack, not the bottom.
2016-08-30 21:07:47 +00:00
g - > gcstacksize = 0 ;
g - > gcnextsp = & mp ;
2011-11-28 05:45:49 +00:00
# endif
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & g - > context [ 0 ] ) ) ;
2011-11-28 05:45:49 +00:00
if ( g - > entry ! = nil ) {
// Got here from mcall.
void ( * pfn ) ( G * ) = ( void ( * ) ( G * ) ) g - > entry ;
G * gp = ( G * ) g - > param ;
pfn ( gp ) ;
* ( int * ) 0x21 = 0x21 ;
}
runtime_minit ( ) ;
2011-12-21 22:24:47 +00:00
# ifdef USING_SPLIT_STACK
{
2013-07-23 20:26:09 +00:00
int dont_block_signals = 0 ;
__splitstack_block_signals ( & dont_block_signals , nil ) ;
2011-12-21 22:24:47 +00:00
}
# endif
2012-03-30 22:09:55 +00:00
// Install signal handlers; after minit so that minit can
// prepare the thread to be able to handle the signals.
2015-04-29 21:31:53 +00:00
if ( m = = & runtime_m0 ) {
if ( runtime_iscgo & & ! runtime_cgoHasExtraM ) {
runtime_cgoHasExtraM = true ;
runtime_newextram ( ) ;
runtime_needextram = 0 ;
}
2016-02-12 22:10:09 +00:00
runtime_initsig ( false ) ;
2015-04-29 21:31:53 +00:00
}
2013-07-16 06:54:42 +00:00
if ( m - > mstartfn )
2016-08-30 21:07:47 +00:00
( ( void ( * ) ( void ) ) m - > mstartfn ) ( ) ;
2012-03-30 22:09:55 +00:00
2013-07-16 06:54:42 +00:00
if ( m - > helpgc ) {
m - > helpgc = 0 ;
stopm ( ) ;
} else if ( m ! = & runtime_m0 ) {
2016-08-30 21:07:47 +00:00
acquirep ( ( P * ) m - > nextp ) ;
m - > nextp = 0 ;
2013-07-16 06:54:42 +00:00
}
schedule ( ) ;
2012-10-23 04:31:11 +00:00
// TODO(brainman): This point is never reached, because scheduler
// does not release os threads at the moment. But once this path
// is enabled, we must remove our seh here.
2011-11-28 05:45:49 +00:00
return nil ;
}
typedef struct CgoThreadStart CgoThreadStart ;
struct CgoThreadStart
{
M * m ;
G * g ;
2014-06-06 22:37:27 +00:00
uintptr * tls ;
2011-11-28 05:45:49 +00:00
void ( * fn ) ( void ) ;
} ;
2013-07-16 06:54:42 +00:00
// Allocate a new m unassociated with any thread.
// Can use p for allocation context if needed.
2011-12-12 23:40:51 +00:00
M *
2016-08-30 21:07:47 +00:00
runtime_allocm ( P * p , int32 stacksize , byte * * ret_g0_stack , uintptr * ret_g0_stacksize )
2011-11-28 05:45:49 +00:00
{
2012-10-23 04:31:11 +00:00
M * mp ;
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ; // disable GC because it can be called from sysmon
if ( g - > m - > p = = 0 )
2013-07-16 06:54:42 +00:00
acquirep ( p ) ; // temporarily borrow p for mallocs in this function
2012-11-21 07:03:38 +00:00
#if 0
if ( mtype = = nil ) {
Eface e ;
runtime_gc_m_ptr ( & e ) ;
mtype = ( ( const PtrType * ) e . __type_descriptor ) - > __element_type ;
}
# endif
mp = runtime_mal ( sizeof * mp ) ;
2012-10-23 04:31:11 +00:00
mcommoninit ( mp ) ;
2013-07-23 20:26:09 +00:00
mp - > g0 = runtime_malg ( stacksize , ret_g0_stack , ret_g0_stacksize ) ;
2016-08-30 21:07:47 +00:00
mp - > g0 - > m = mp ;
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
if ( p = = ( P * ) g - > m - > p )
2013-07-16 06:54:42 +00:00
releasep ( ) ;
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
return mp ;
}
2012-06-05 06:19:19 +00:00
2014-07-19 08:53:52 +00:00
static G *
allocg ( void )
{
G * gp ;
// static Type *gtype;
// if(gtype == nil) {
// Eface e;
// runtime_gc_g_ptr(&e);
// gtype = ((PtrType*)e.__type_descriptor)->__element_type;
// }
// gp = runtime_cnew(gtype);
gp = runtime_malloc ( sizeof ( G ) ) ;
return gp ;
}
2013-07-16 06:54:42 +00:00
static M * lockextra ( bool nilokay ) ;
static void unlockextra ( M * ) ;
2012-06-05 06:19:19 +00:00
2013-07-16 06:54:42 +00:00
// needm is called when a cgo callback happens on a
// thread without an m (a thread not created by Go).
// In this case, needm is expected to find an m to use
// and return with m, g initialized correctly.
// Since m and g are not set now (likely nil, but see below)
// needm is limited in what routines it can call. In particular
// it can only call nosplit functions (textflag 7) and cannot
// do any scheduling that requires an m.
//
// In order to avoid needing heavy lifting here, we adopt
// the following strategy: there is a stack of available m's
// that can be stolen. Using compare-and-swap
// to pop from the stack has ABA races, so we simulate
// a lock by doing an exchange (via casp) to steal the stack
// head and replace the top pointer with MLOCKED (1).
// This serves as a simple spin lock that we can use even
// without an m. The thread that locks the stack in this way
// unlocks the stack by storing a valid stack head pointer.
//
// In order to make sure that there is always an m structure
// available to be stolen, we maintain the invariant that there
// is always one more than needed. At the beginning of the
// program (if cgo is in use) the list is seeded with a single m.
// If needm finds that it has taken the last m off the list, its job
// is - once it has installed its own m so that it can do things like
// allocate memory - to create a spare m and put it on the list.
//
// Each of these extra m's also has a g0 and a curg that are
// pressed into service as the scheduling stack and current
// goroutine for the duration of the cgo callback.
//
// When the callback is done with the m, it calls dropm to
// put the m back on the list.
2013-07-23 20:26:09 +00:00
//
// Unlike the gc toolchain, we start running on curg, since we are
// just going to return and let the caller continue.
2013-07-16 06:54:42 +00:00
void
runtime_needm ( void )
{
M * mp ;
2011-11-28 05:45:49 +00:00
2013-11-06 19:49:01 +00:00
if ( runtime_needextram ) {
// Can happen if C/C++ code calls Go from a global ctor.
// Can not throw, because scheduler is not initialized yet.
2014-05-27 22:01:21 +00:00
int rv __attribute__ ( ( unused ) ) ;
rv = runtime_write ( 2 , " fatal error: cgo callback before cgo call \n " ,
2013-11-06 19:49:01 +00:00
sizeof ( " fatal error: cgo callback before cgo call \n " ) - 1 ) ;
runtime_exit ( 1 ) ;
}
2013-07-16 06:54:42 +00:00
// Lock extra list, take head, unlock popped list.
// nilokay=false is safe here because of the invariant above,
// that the extra list always contains or will soon contain
// at least one m.
mp = lockextra ( false ) ;
// Set needextram when we've just emptied the list,
// so that the eventual call into cgocallbackg will
// allocate a new m for the extra list. We delay the
// allocation until then so that it can be done
// after exitsyscall makes sure it is okay to be
// running at all (that is, there's no garbage collection
// running right now).
2016-08-30 21:07:47 +00:00
mp - > needextram = mp - > schedlink = = 0 ;
unlockextra ( ( M * ) mp - > schedlink ) ;
2013-07-16 06:54:42 +00:00
2016-08-30 21:07:47 +00:00
// Install g (= m->curg).
runtime_setg ( mp - > curg ) ;
2013-07-16 06:54:42 +00:00
2013-07-23 20:26:09 +00:00
// Initialize g's context as in mstart.
initcontext ( ) ;
2016-08-30 21:07:47 +00:00
g - > atomicstatus = _Gsyscall ;
2013-07-23 20:26:09 +00:00
g - > entry = nil ;
g - > param = nil ;
# ifdef USING_SPLIT_STACK
2016-08-30 21:07:47 +00:00
__splitstack_getcontext ( & g - > stackcontext [ 0 ] ) ;
2013-07-23 20:26:09 +00:00
# else
2016-08-30 21:07:47 +00:00
g - > gcinitialsp = & mp ;
runtime: Clear stack pointers for extra G's.
Fix an unusual C to Go callback case. Newly created C threads
call into Go code, forcing the Go code to allocate new M and G
structures. While executing Go code, the stack is split. The
Go code then returns. Returning from a Go callback is treated
as entering a system call, so the G gcstack field is set to
point to the Go stack. In this case, though, we were called
from a newly created C thread, so we drop the extra M and G
structures. The C thread then exits.
Then a new C thread calls into Go code, reusing the previously
created M and G. The Go code requires a larger stack frame,
causing the old stack segment to be unmapped and a new stack
segment allocated. At this point the gcstack field is
pointing to the old stack segment.
Then a garbage collection occurs. The garbage collector sees
that the gcstack field is not nil, so it scans it as the first
stack segment. Unfortunately it points to memory that was
unmapped. So the program crashes.
The fix is simple: when handling extra G structures created
for callbacks from new C threads, clear the gcstack field.
From-SVN: r218699
2014-12-13 00:52:20 +00:00
g - > gcstack = nil ;
2016-08-30 21:07:47 +00:00
g - > gcstacksize = 0 ;
g - > gcnextsp = & mp ;
2013-07-23 20:26:09 +00:00
# endif
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & g - > context [ 0 ] ) ) ;
2013-07-23 20:26:09 +00:00
if ( g - > entry ! = nil ) {
// Got here from mcall.
void ( * pfn ) ( G * ) = ( void ( * ) ( G * ) ) g - > entry ;
G * gp = ( G * ) g - > param ;
pfn ( gp ) ;
* ( int * ) 0x22 = 0x22 ;
}
2013-07-16 06:54:42 +00:00
// Initialize this thread to use the m.
runtime_minit ( ) ;
2013-07-23 20:26:09 +00:00
# ifdef USING_SPLIT_STACK
{
int dont_block_signals = 0 ;
__splitstack_block_signals ( & dont_block_signals , nil ) ;
}
# endif
2013-07-16 06:54:42 +00:00
}
2013-02-28 21:56:14 +00:00
2013-07-16 06:54:42 +00:00
// newextram allocates an m and puts it on the extra list.
// It is called with a working local m, so that it can do things
// like call schedlock and allocate.
void
runtime_newextram ( void )
{
M * mp , * mnext ;
G * gp ;
2013-07-23 20:26:09 +00:00
byte * g0_sp , * sp ;
2016-08-30 21:07:47 +00:00
uintptr g0_spsize , spsize ;
2016-09-09 13:31:49 +00:00
ucontext_t * uc ;
2013-02-28 21:56:14 +00:00
2013-07-16 06:54:42 +00:00
// Create extra goroutine locked to extra m.
// The goroutine is the context in which the cgo callback will run.
// The sched.pc will never be returned to, but setting it to
// runtime.goexit makes clear to the traceback routines where
// the goroutine stack ends.
2013-07-23 20:26:09 +00:00
mp = runtime_allocm ( nil , StackMin , & g0_sp , & g0_spsize ) ;
gp = runtime_malg ( StackMin , & sp , & spsize ) ;
2016-08-30 21:07:47 +00:00
gp - > atomicstatus = _Gdead ;
gp - > m = mp ;
2013-07-16 06:54:42 +00:00
mp - > curg = gp ;
2016-08-30 21:07:47 +00:00
mp - > locked = _LockInternal ;
2013-07-16 06:54:42 +00:00
mp - > lockedg = gp ;
gp - > lockedm = mp ;
2016-11-18 17:48:29 +00:00
gp - > goid = runtime_xadd64 ( & runtime_sched - > goidgen , 1 ) ;
2013-07-16 06:54:42 +00:00
// put on allg for garbage collector
2014-06-06 22:37:27 +00:00
allgadd ( gp ) ;
2013-01-31 17:30:28 +00:00
2013-07-23 20:26:09 +00:00
// The context for gp will be set up in runtime_needm. But
// here we need to set up the context for g0.
2016-09-09 13:31:49 +00:00
uc = ucontext_arg ( & mp - > g0 - > context [ 0 ] ) ;
getcontext ( uc ) ;
uc - > uc_stack . ss_sp = g0_sp ;
uc - > uc_stack . ss_size = ( size_t ) g0_spsize ;
makecontext ( uc , kickoff , 0 ) ;
2013-07-23 20:26:09 +00:00
2013-07-16 06:54:42 +00:00
// Add m to the extra list.
mnext = lockextra ( true ) ;
2016-08-30 21:07:47 +00:00
mp - > schedlink = ( uintptr ) mnext ;
2013-07-16 06:54:42 +00:00
unlockextra ( mp ) ;
}
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// dropm is called when a cgo callback has called needm but is now
// done with the callback and returning back into the non-Go thread.
// It puts the current m back onto the extra list.
//
// The main expense here is the call to signalstack to release the
// m's signal stack, and then the call to needm on the next callback
// from this thread. It is tempting to try to save the m for next time,
// which would eliminate both these costs, but there might not be
// a next time: the current thread (which Go does not control) might exit.
// If we saved the m for that thread, there would be an m leak each time
// such a thread exited. Instead, we acquire and release an m on each
// call. These should typically not be scheduling operations, just a few
// atomics, so the cost should be small.
//
// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
// variable using pthread_key_create. Unlike the pthread keys we already use
// on OS X, this dummy key would never be read by Go code. It would exist
// only so that we could register at thread-exit-time destructor.
// That destructor would put the m back onto the extra list.
// This is purely a performance optimization. The current version,
// in which dropm happens on each cgo call, is still correct too.
// We may have to keep the current version on systems with cgo
// but without pthreads, like Windows.
void
runtime_dropm ( void )
{
M * mp , * mnext ;
// Undo whatever initialization minit did during needm.
runtime_unminit ( ) ;
// Clear m and g, and return m to the extra list.
2016-08-30 21:07:47 +00:00
// After the call to setg we can only call nosplit functions.
mp = g - > m ;
runtime_setg ( nil ) ;
2013-07-16 06:54:42 +00:00
2016-08-30 21:07:47 +00:00
mp - > curg - > atomicstatus = _Gdead ;
runtime: Clear stack pointers for extra G's.
Fix an unusual C to Go callback case. Newly created C threads
call into Go code, forcing the Go code to allocate new M and G
structures. While executing Go code, the stack is split. The
Go code then returns. Returning from a Go callback is treated
as entering a system call, so the G gcstack field is set to
point to the Go stack. In this case, though, we were called
from a newly created C thread, so we drop the extra M and G
structures. The C thread then exits.
Then a new C thread calls into Go code, reusing the previously
created M and G. The Go code requires a larger stack frame,
causing the old stack segment to be unmapped and a new stack
segment allocated. At this point the gcstack field is
pointing to the old stack segment.
Then a garbage collection occurs. The garbage collector sees
that the gcstack field is not nil, so it scans it as the first
stack segment. Unfortunately it points to memory that was
unmapped. So the program crashes.
The fix is simple: when handling extra G structures created
for callbacks from new C threads, clear the gcstack field.
From-SVN: r218699
2014-12-13 00:52:20 +00:00
mp - > curg - > gcstack = nil ;
2016-08-30 21:07:47 +00:00
mp - > curg - > gcnextsp = nil ;
2013-07-23 20:26:09 +00:00
2013-07-16 06:54:42 +00:00
mnext = lockextra ( true ) ;
2016-08-30 21:07:47 +00:00
mp - > schedlink = ( uintptr ) mnext ;
2013-07-16 06:54:42 +00:00
unlockextra ( mp ) ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
# define MLOCKED ((M*)1)
// lockextra locks the extra list and returns the list head.
// The caller must unlock the list by storing a new list head
// to runtime.extram. If nilokay is true, then lockextra will
// return a nil list head if that's what it finds. If nilokay is false,
// lockextra will keep waiting until the list head is no longer nil.
static M *
lockextra ( bool nilokay )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
M * mp ;
void ( * yield ) ( void ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
for ( ; ; ) {
mp = runtime_atomicloadp ( & runtime_extram ) ;
if ( mp = = MLOCKED ) {
yield = runtime_osyield ;
yield ( ) ;
continue ;
}
if ( mp = = nil & & ! nilokay ) {
runtime_usleep ( 1 ) ;
continue ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
if ( ! runtime_casp ( & runtime_extram , mp , MLOCKED ) ) {
yield = runtime_osyield ;
yield ( ) ;
continue ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
break ;
}
return mp ;
}
static void
unlockextra ( M * mp )
{
runtime_atomicstorep ( & runtime_extram , mp ) ;
}
2013-07-23 20:26:09 +00:00
static int32
countextra ( )
{
M * mp , * mc ;
int32 c ;
for ( ; ; ) {
mp = runtime_atomicloadp ( & runtime_extram ) ;
if ( mp = = MLOCKED ) {
runtime_osyield ( ) ;
continue ;
}
if ( ! runtime_casp ( & runtime_extram , mp , MLOCKED ) ) {
runtime_osyield ( ) ;
continue ;
}
c = 0 ;
2016-08-30 21:07:47 +00:00
for ( mc = mp ; mc ! = nil ; mc = ( M * ) mc - > schedlink )
2013-07-23 20:26:09 +00:00
c + + ;
runtime_atomicstorep ( & runtime_extram , mp ) ;
return c ;
}
}
2013-07-16 06:54:42 +00:00
// Create a new m. It will start off with a call to fn, or else the scheduler.
static void
newm ( void ( * fn ) ( void ) , P * p )
{
M * mp ;
2013-07-23 20:26:09 +00:00
mp = runtime_allocm ( p , - 1 , nil , nil ) ;
2016-08-30 21:07:47 +00:00
mp - > nextp = ( uintptr ) p ;
mp - > mstartfn = ( uintptr ) ( void * ) fn ;
2013-07-16 06:54:42 +00:00
runtime_newosproc ( mp ) ;
}
// Stops execution of the current m until new work is available.
// Returns with acquired P.
static void
stopm ( void )
{
2016-08-30 21:07:47 +00:00
M * m ;
m = g - > m ;
2013-07-16 06:54:42 +00:00
if ( m - > locks )
runtime_throw ( " stopm holding locks " ) ;
if ( m - > p )
runtime_throw ( " stopm holding p " ) ;
if ( m - > spinning ) {
m - > spinning = false ;
2016-11-18 17:48:29 +00:00
runtime_xadd ( & runtime_sched - > nmspinning , - 1 ) ;
2013-07-16 06:54:42 +00:00
}
retry :
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
mput ( m ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
runtime_notesleep ( & m - > park ) ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
2013-07-16 06:54:42 +00:00
runtime_noteclear ( & m - > park ) ;
if ( m - > helpgc ) {
runtime_gchelper ( ) ;
2011-11-28 05:45:49 +00:00
m - > helpgc = 0 ;
2013-07-16 06:54:42 +00:00
m - > mcache = nil ;
goto retry ;
}
2016-08-30 21:07:47 +00:00
acquirep ( ( P * ) m - > nextp ) ;
m - > nextp = 0 ;
2013-07-16 06:54:42 +00:00
}
static void
mspinning ( void )
{
2016-08-30 21:07:47 +00:00
g - > m - > spinning = true ;
2013-07-16 06:54:42 +00:00
}
// Schedules some M to run the p (creates an M if necessary).
2014-06-06 22:37:27 +00:00
// If p==nil, tries to get an idle P, if no idle P's does nothing.
2013-07-16 06:54:42 +00:00
static void
startm ( P * p , bool spinning )
{
M * mp ;
void ( * fn ) ( void ) ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( p = = nil ) {
p = pidleget ( ) ;
if ( p = = nil ) {
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( spinning )
2016-11-18 17:48:29 +00:00
runtime_xadd ( & runtime_sched - > nmspinning , - 1 ) ;
2013-07-16 06:54:42 +00:00
return ;
}
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
mp = mget ( ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( mp = = nil ) {
fn = nil ;
if ( spinning )
fn = mspinning ;
newm ( fn , p ) ;
return ;
}
if ( mp - > spinning )
runtime_throw ( " startm: m is spinning " ) ;
if ( mp - > nextp )
runtime_throw ( " startm: m has p " ) ;
mp - > spinning = spinning ;
2016-08-30 21:07:47 +00:00
mp - > nextp = ( uintptr ) p ;
2013-07-16 06:54:42 +00:00
runtime_notewakeup ( & mp - > park ) ;
}
// Hands off P from syscall or locked M.
static void
handoffp ( P * p )
{
// if it has local work, start it straight away
2016-11-18 17:48:29 +00:00
if ( p - > runqhead ! = p - > runqtail | | runtime_sched - > runqsize ) {
2013-07-16 06:54:42 +00:00
startm ( p , false ) ;
return ;
}
// no local work, check that there are no spinning/idle M's,
// otherwise our help is not required
2016-11-18 17:48:29 +00:00
if ( runtime_atomicload ( & runtime_sched - > nmspinning ) + runtime_atomicload ( & runtime_sched - > npidle ) = = 0 & & // TODO: fast atomic
runtime_cas ( & runtime_sched - > nmspinning , 0 , 1 ) ) {
2013-07-16 06:54:42 +00:00
startm ( p , true ) ;
return ;
}
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
if ( runtime_sched - > gcwaiting ) {
2016-08-30 21:07:47 +00:00
p - > status = _Pgcstop ;
2016-11-18 17:48:29 +00:00
if ( - - runtime_sched - > stopwait = = 0 )
runtime_notewakeup ( & runtime_sched - > stopnote ) ;
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
return ;
}
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqsize ) {
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
startm ( p , false ) ;
return ;
}
// If this is the last running P and nobody is polling network,
// need to wakeup another M to poll network.
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > npidle = = ( uint32 ) runtime_gomaxprocs - 1 & & runtime_atomicload64 ( & runtime_sched - > lastpoll ) ! = 0 ) {
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
startm ( p , false ) ;
return ;
}
pidleput ( p ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
}
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// Tries to add one more P to execute G's.
// Called when a G is made runnable (newproc, ready).
static void
wakep ( void )
{
// be conservative about spinning threads
2016-11-18 17:48:29 +00:00
if ( ! runtime_cas ( & runtime_sched - > nmspinning , 0 , 1 ) )
2013-07-16 06:54:42 +00:00
return ;
startm ( nil , true ) ;
}
// Stops execution of the current m that is locked to a g until the g is runnable again.
// Returns with acquired P.
static void
stoplockedm ( void )
{
2016-08-30 21:07:47 +00:00
M * m ;
2013-07-16 06:54:42 +00:00
P * p ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
2013-07-16 06:54:42 +00:00
if ( m - > lockedg = = nil | | m - > lockedg - > lockedm ! = m )
runtime_throw ( " stoplockedm: inconsistent locking " ) ;
if ( m - > p ) {
// Schedule another M to run this p.
p = releasep ( ) ;
handoffp ( p ) ;
}
2013-11-06 19:49:01 +00:00
incidlelocked ( 1 ) ;
2013-07-16 06:54:42 +00:00
// Wait until another thread schedules lockedg again.
runtime_notesleep ( & m - > park ) ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
2013-07-16 06:54:42 +00:00
runtime_noteclear ( & m - > park ) ;
2016-08-30 21:07:47 +00:00
if ( m - > lockedg - > atomicstatus ! = _Grunnable )
2013-07-16 06:54:42 +00:00
runtime_throw ( " stoplockedm: not runnable " ) ;
2016-08-30 21:07:47 +00:00
acquirep ( ( P * ) m - > nextp ) ;
m - > nextp = 0 ;
2013-07-16 06:54:42 +00:00
}
// Schedules the locked m to run the locked gp.
static void
startlockedm ( G * gp )
{
M * mp ;
P * p ;
mp = gp - > lockedm ;
2016-08-30 21:07:47 +00:00
if ( mp = = g - > m )
2013-07-16 06:54:42 +00:00
runtime_throw ( " startlockedm: locked to me " ) ;
if ( mp - > nextp )
runtime_throw ( " startlockedm: m has p " ) ;
// directly handoff current P to the locked m
2013-11-06 19:49:01 +00:00
incidlelocked ( - 1 ) ;
2013-07-16 06:54:42 +00:00
p = releasep ( ) ;
2016-08-30 21:07:47 +00:00
mp - > nextp = ( uintptr ) p ;
2013-07-16 06:54:42 +00:00
runtime_notewakeup ( & mp - > park ) ;
stopm ( ) ;
}
// Stops the current m for stoptheworld.
// Returns when the world is restarted.
static void
gcstopm ( void )
{
P * p ;
2016-11-18 17:48:29 +00:00
if ( ! runtime_sched - > gcwaiting )
2013-07-16 06:54:42 +00:00
runtime_throw ( " gcstopm: not waiting for gc " ) ;
2016-08-30 21:07:47 +00:00
if ( g - > m - > spinning ) {
g - > m - > spinning = false ;
2016-11-18 17:48:29 +00:00
runtime_xadd ( & runtime_sched - > nmspinning , - 1 ) ;
2013-07-16 06:54:42 +00:00
}
p = releasep ( ) ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2016-08-30 21:07:47 +00:00
p - > status = _Pgcstop ;
2016-11-18 17:48:29 +00:00
if ( - - runtime_sched - > stopwait = = 0 )
runtime_notewakeup ( & runtime_sched - > stopnote ) ;
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
stopm ( ) ;
}
// Schedules gp to run on the current M.
// Never returns.
static void
execute ( G * gp )
{
int32 hz ;
2016-08-30 21:07:47 +00:00
if ( gp - > atomicstatus ! = _Grunnable ) {
runtime_printf ( " execute: bad g status %d \n " , gp - > atomicstatus ) ;
2013-07-16 06:54:42 +00:00
runtime_throw ( " execute: bad g status " ) ;
}
2016-08-30 21:07:47 +00:00
gp - > atomicstatus = _Grunning ;
2014-06-06 22:37:27 +00:00
gp - > waitsince = 0 ;
2016-08-30 21:07:47 +00:00
( ( P * ) g - > m - > p ) - > schedtick + + ;
g - > m - > curg = gp ;
gp - > m = g - > m ;
2011-11-28 05:45:49 +00:00
// Check whether the profiler needs to be turned on or off.
2016-11-18 17:48:29 +00:00
hz = runtime_sched - > profilehz ;
2016-08-30 21:07:47 +00:00
if ( g - > m - > profilehz ! = hz )
2011-11-28 05:45:49 +00:00
runtime_resetcpuprofiler ( hz ) ;
runtime_gogo ( gp ) ;
}
2013-07-16 06:54:42 +00:00
// Finds a runnable goroutine to execute.
// Tries to steal from other P's, get g from global queue, poll network.
static G *
findrunnable ( void )
{
G * gp ;
P * p ;
int32 i ;
top :
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > gcwaiting ) {
2013-07-16 06:54:42 +00:00
gcstopm ( ) ;
goto top ;
}
2014-07-19 08:53:52 +00:00
if ( runtime_fingwait & & runtime_fingwake & & ( gp = runtime_wakefing ( ) ) ! = nil )
runtime_ready ( gp ) ;
2013-07-16 06:54:42 +00:00
// local runq
2016-08-30 21:07:47 +00:00
gp = runqget ( ( P * ) g - > m - > p ) ;
2013-07-16 06:54:42 +00:00
if ( gp )
return gp ;
// global runq
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqsize ) {
runtime_lock ( & runtime_sched - > lock ) ;
2016-08-30 21:07:47 +00:00
gp = globrunqget ( ( P * ) g - > m - > p , 0 ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( gp )
return gp ;
}
// poll network
gp = runtime_netpoll ( false ) ; // non-blocking
if ( gp ) {
2016-08-30 21:07:47 +00:00
injectglist ( ( G * ) gp - > schedlink ) ;
gp - > atomicstatus = _Grunnable ;
2013-07-16 06:54:42 +00:00
return gp ;
}
// If number of spinning M's >= number of busy P's, block.
// This is necessary to prevent excessive CPU consumption
// when GOMAXPROCS>>1 but the program parallelism is low.
2016-11-18 17:48:29 +00:00
if ( ! g - > m - > spinning & & 2 * runtime_atomicload ( & runtime_sched - > nmspinning ) > = runtime_gomaxprocs - runtime_atomicload ( & runtime_sched - > npidle ) ) // TODO: fast atomic
2013-07-16 06:54:42 +00:00
goto stop ;
2016-08-30 21:07:47 +00:00
if ( ! g - > m - > spinning ) {
g - > m - > spinning = true ;
2016-11-18 17:48:29 +00:00
runtime_xadd ( & runtime_sched - > nmspinning , 1 ) ;
2013-07-16 06:54:42 +00:00
}
// random steal from other P's
for ( i = 0 ; i < 2 * runtime_gomaxprocs ; i + + ) {
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > gcwaiting )
2013-07-16 06:54:42 +00:00
goto top ;
p = runtime_allp [ runtime_fastrand1 ( ) % runtime_gomaxprocs ] ;
2016-08-30 21:07:47 +00:00
if ( p = = ( P * ) g - > m - > p )
2013-07-16 06:54:42 +00:00
gp = runqget ( p ) ;
else
2016-08-30 21:07:47 +00:00
gp = runqsteal ( ( P * ) g - > m - > p , p ) ;
2013-07-16 06:54:42 +00:00
if ( gp )
return gp ;
}
stop :
// return P and block
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
if ( runtime_sched - > gcwaiting ) {
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
goto top ;
}
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqsize ) {
2016-08-30 21:07:47 +00:00
gp = globrunqget ( ( P * ) g - > m - > p , 0 ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
return gp ;
}
p = releasep ( ) ;
pidleput ( p ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2016-08-30 21:07:47 +00:00
if ( g - > m - > spinning ) {
g - > m - > spinning = false ;
2016-11-18 17:48:29 +00:00
runtime_xadd ( & runtime_sched - > nmspinning , - 1 ) ;
2013-07-16 06:54:42 +00:00
}
// check all runqueues once again
for ( i = 0 ; i < runtime_gomaxprocs ; i + + ) {
p = runtime_allp [ i ] ;
if ( p & & p - > runqhead ! = p - > runqtail ) {
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
p = pidleget ( ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( p ) {
acquirep ( p ) ;
goto top ;
}
break ;
}
}
// poll network
2016-11-18 17:48:29 +00:00
if ( runtime_xchg64 ( & runtime_sched - > lastpoll , 0 ) ! = 0 ) {
2016-08-30 21:07:47 +00:00
if ( g - > m - > p )
2013-07-16 06:54:42 +00:00
runtime_throw ( " findrunnable: netpoll with p " ) ;
2016-08-30 21:07:47 +00:00
if ( g - > m - > spinning )
2013-07-16 06:54:42 +00:00
runtime_throw ( " findrunnable: netpoll with spinning " ) ;
gp = runtime_netpoll ( true ) ; // block until new work is available
2016-11-18 17:48:29 +00:00
runtime_atomicstore64 ( & runtime_sched - > lastpoll , runtime_nanotime ( ) ) ;
2013-07-16 06:54:42 +00:00
if ( gp ) {
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
p = pidleget ( ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( p ) {
acquirep ( p ) ;
2016-08-30 21:07:47 +00:00
injectglist ( ( G * ) gp - > schedlink ) ;
gp - > atomicstatus = _Grunnable ;
2013-07-16 06:54:42 +00:00
return gp ;
}
injectglist ( gp ) ;
}
}
stopm ( ) ;
goto top ;
}
2013-11-06 19:49:01 +00:00
static void
resetspinning ( void )
{
int32 nmspinning ;
2016-08-30 21:07:47 +00:00
if ( g - > m - > spinning ) {
g - > m - > spinning = false ;
2016-11-18 17:48:29 +00:00
nmspinning = runtime_xadd ( & runtime_sched - > nmspinning , - 1 ) ;
2013-11-06 19:49:01 +00:00
if ( nmspinning < 0 )
runtime_throw ( " findrunnable: negative nmspinning " ) ;
} else
2016-11-18 17:48:29 +00:00
nmspinning = runtime_atomicload ( & runtime_sched - > nmspinning ) ;
2013-11-06 19:49:01 +00:00
// M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
// so see if we need to wakeup another P here.
2016-11-18 17:48:29 +00:00
if ( nmspinning = = 0 & & runtime_atomicload ( & runtime_sched - > npidle ) > 0 )
2013-11-06 19:49:01 +00:00
wakep ( ) ;
}
2013-07-16 06:54:42 +00:00
// Injects the list of runnable G's into the scheduler.
// Can run concurrently with GC.
static void
injectglist ( G * glist )
{
int32 n ;
G * gp ;
if ( glist = = nil )
return ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
for ( n = 0 ; glist ; n + + ) {
gp = glist ;
2016-08-30 21:07:47 +00:00
glist = ( G * ) gp - > schedlink ;
gp - > atomicstatus = _Grunnable ;
2013-07-16 06:54:42 +00:00
globrunqput ( gp ) ;
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
2016-11-18 17:48:29 +00:00
for ( ; n & & runtime_sched - > npidle ; n - - )
2013-07-16 06:54:42 +00:00
startm ( nil , false ) ;
}
// One round of scheduler: find a runnable goroutine and execute it.
// Never returns.
static void
schedule ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
G * gp ;
2013-11-06 19:49:01 +00:00
uint32 tick ;
2013-07-16 06:54:42 +00:00
2016-08-30 21:07:47 +00:00
if ( g - > m - > locks )
2013-07-16 06:54:42 +00:00
runtime_throw ( " schedule: holding locks " ) ;
top :
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > gcwaiting ) {
2013-07-16 06:54:42 +00:00
gcstopm ( ) ;
goto top ;
}
2013-11-06 19:49:01 +00:00
gp = nil ;
// Check the global runnable queue once in a while to ensure fairness.
// Otherwise two goroutines can completely occupy the local runqueue
// by constantly respawning each other.
2016-08-30 21:07:47 +00:00
tick = ( ( P * ) g - > m - > p ) - > schedtick ;
2013-11-06 19:49:01 +00:00
// This is a fancy way to say tick%61==0,
// it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors.
2016-11-18 17:48:29 +00:00
if ( tick - ( ( ( uint64 ) tick * 0x4325c53fu ) > > 36 ) * 61 = = 0 & & runtime_sched - > runqsize > 0 ) {
runtime_lock ( & runtime_sched - > lock ) ;
2016-08-30 21:07:47 +00:00
gp = globrunqget ( ( P * ) g - > m - > p , 1 ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
if ( gp )
resetspinning ( ) ;
}
if ( gp = = nil ) {
2016-08-30 21:07:47 +00:00
gp = runqget ( ( P * ) g - > m - > p ) ;
if ( gp & & g - > m - > spinning )
2013-11-06 19:49:01 +00:00
runtime_throw ( " schedule: spinning with local work " ) ;
}
if ( gp = = nil ) {
gp = findrunnable ( ) ; // blocks until work is available
resetspinning ( ) ;
2013-07-16 06:54:42 +00:00
}
if ( gp - > lockedm ) {
2013-11-06 19:49:01 +00:00
// Hands off own p to the locked m,
// then blocks waiting for a new p.
2013-07-16 06:54:42 +00:00
startlockedm ( gp ) ;
goto top ;
}
execute ( gp ) ;
2011-11-28 05:45:49 +00:00
}
2014-06-06 22:37:27 +00:00
// Puts the current goroutine into a waiting state and calls unlockf.
// If unlockf returns false, the goroutine is resumed.
2012-10-23 04:31:11 +00:00
void
2014-06-06 22:37:27 +00:00
runtime_park ( bool ( * unlockf ) ( G * , void * ) , void * lock , const char * reason )
2012-10-23 04:31:11 +00:00
{
2016-08-30 21:07:47 +00:00
if ( g - > atomicstatus ! = _Grunning )
2014-07-19 08:53:52 +00:00
runtime_throw ( " bad g status " ) ;
2016-08-30 21:07:47 +00:00
g - > m - > waitlock = lock ;
g - > m - > waitunlockf = unlockf ;
g - > waitreason = runtime_gostringnocopy ( ( const byte * ) reason ) ;
2013-07-16 06:54:42 +00:00
runtime_mcall ( park0 ) ;
2012-10-23 04:31:11 +00:00
}
2016-10-10 16:52:09 +00:00
void gopark ( FuncVal * , void * , String , byte , int )
__asm__ ( " runtime.gopark " ) ;
void
gopark ( FuncVal * unlockf , void * lock , String reason ,
byte traceEv __attribute__ ( ( unused ) ) ,
int traceskip __attribute__ ( ( unused ) ) )
{
if ( g - > atomicstatus ! = _Grunning )
runtime_throw ( " bad g status " ) ;
g - > m - > waitlock = lock ;
g - > m - > waitunlockf = unlockf = = nil ? nil : ( void * ) unlockf - > fn ;
g - > waitreason = reason ;
runtime_mcall ( park0 ) ;
}
2014-06-06 22:37:27 +00:00
static bool
parkunlock ( G * gp , void * lock )
{
USED ( gp ) ;
runtime_unlock ( lock ) ;
return true ;
}
// Puts the current goroutine into a waiting state and unlocks the lock.
// The goroutine can be made runnable again by calling runtime_ready(gp).
void
runtime_parkunlock ( Lock * lock , const char * reason )
{
runtime_park ( parkunlock , lock , reason ) ;
}
2016-10-10 16:52:09 +00:00
void goparkunlock ( Lock * , String , byte , int )
__asm__ ( GOSYM_PREFIX " runtime.goparkunlock " ) ;
void
goparkunlock ( Lock * lock , String reason , byte traceEv __attribute__ ( ( unused ) ) ,
int traceskip __attribute__ ( ( unused ) ) )
{
if ( g - > atomicstatus ! = _Grunning )
runtime_throw ( " bad g status " ) ;
g - > m - > waitlock = lock ;
g - > m - > waitunlockf = parkunlock ;
g - > waitreason = reason ;
runtime_mcall ( park0 ) ;
}
2013-07-16 06:54:42 +00:00
// runtime_park continuation on g0.
static void
park0 ( G * gp )
{
2016-08-30 21:07:47 +00:00
M * m ;
2014-06-06 22:37:27 +00:00
bool ok ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
gp - > atomicstatus = _Gwaiting ;
2013-07-16 06:54:42 +00:00
gp - > m = nil ;
m - > curg = nil ;
if ( m - > waitunlockf ) {
2016-08-30 21:07:47 +00:00
ok = ( ( bool ( * ) ( G * , void * ) ) m - > waitunlockf ) ( gp , m - > waitlock ) ;
2013-07-16 06:54:42 +00:00
m - > waitunlockf = nil ;
m - > waitlock = nil ;
2014-06-06 22:37:27 +00:00
if ( ! ok ) {
2016-08-30 21:07:47 +00:00
gp - > atomicstatus = _Grunnable ;
2014-06-06 22:37:27 +00:00
execute ( gp ) ; // Schedule it back, never returns.
}
2013-07-16 06:54:42 +00:00
}
if ( m - > lockedg ) {
stoplockedm ( ) ;
execute ( gp ) ; // Never returns.
}
schedule ( ) ;
}
// Scheduler yield.
void
runtime_gosched ( void )
{
2016-08-30 21:07:47 +00:00
if ( g - > atomicstatus ! = _Grunning )
2014-07-19 08:53:52 +00:00
runtime_throw ( " bad g status " ) ;
2013-11-06 19:49:01 +00:00
runtime_mcall ( runtime_gosched0 ) ;
2013-07-16 06:54:42 +00:00
}
// runtime_gosched continuation on g0.
2013-11-06 19:49:01 +00:00
void
runtime_gosched0 ( G * gp )
2013-07-16 06:54:42 +00:00
{
2016-08-30 21:07:47 +00:00
M * m ;
m = g - > m ;
gp - > atomicstatus = _Grunnable ;
2013-07-16 06:54:42 +00:00
gp - > m = nil ;
m - > curg = nil ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
globrunqput ( gp ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( m - > lockedg ) {
stoplockedm ( ) ;
execute ( gp ) ; // Never returns.
}
schedule ( ) ;
}
// Finishes execution of the current goroutine.
2013-11-06 19:49:01 +00:00
// Need to mark it as nosplit, because it runs with sp > stackbase (as runtime_lessstack).
// Since it does not return it does not matter. But if it is preempted
// at the split stack check, GC will complain about inconsistent sp.
2014-09-22 21:14:43 +00:00
void runtime_goexit ( void ) __attribute__ ( ( noinline ) ) ;
2013-07-16 06:54:42 +00:00
void
runtime_goexit ( void )
{
2016-08-30 21:07:47 +00:00
if ( g - > atomicstatus ! = _Grunning )
2014-07-19 08:53:52 +00:00
runtime_throw ( " bad g status " ) ;
2013-07-16 06:54:42 +00:00
runtime_mcall ( goexit0 ) ;
}
// runtime_goexit continuation on g0.
static void
goexit0 ( G * gp )
{
2016-08-30 21:07:47 +00:00
M * m ;
m = g - > m ;
gp - > atomicstatus = _Gdead ;
2013-07-16 06:54:42 +00:00
gp - > entry = nil ;
gp - > m = nil ;
gp - > lockedm = nil ;
2014-07-19 08:53:52 +00:00
gp - > paniconfault = 0 ;
2016-08-30 21:07:47 +00:00
gp - > _defer = nil ; // should be true already but just in case.
gp - > _panic = nil ; // non-nil for Goexit during panic. points at stack-allocated data.
2016-10-10 23:13:39 +00:00
gp - > writebuf . __values = nil ;
gp - > writebuf . __count = 0 ;
gp - > writebuf . __capacity = 0 ;
2016-08-30 21:07:47 +00:00
gp - > waitreason = runtime_gostringnocopy ( nil ) ;
2014-07-19 08:53:52 +00:00
gp - > param = nil ;
2013-07-16 06:54:42 +00:00
m - > curg = nil ;
m - > lockedg = nil ;
2016-08-30 21:07:47 +00:00
if ( m - > locked & ~ _LockExternal ) {
2013-11-06 19:49:01 +00:00
runtime_printf ( " invalid m->locked = %d \n " , m - > locked ) ;
2013-07-16 06:54:42 +00:00
runtime_throw ( " internal lockOSThread error " ) ;
}
m - > locked = 0 ;
2016-08-30 21:07:47 +00:00
gfput ( ( P * ) m - > p , gp ) ;
2013-07-16 06:54:42 +00:00
schedule ( ) ;
}
// 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.
2016-09-30 13:45:08 +00:00
void runtime_entersyscall ( int32 ) __attribute__ ( ( no_split_stack ) ) ;
2016-11-10 22:53:23 +00:00
static void doentersyscall ( uintptr , uintptr )
__attribute__ ( ( no_split_stack , noinline ) ) ;
2013-07-16 06:54:42 +00:00
void
2016-09-30 13:45:08 +00:00
runtime_entersyscall ( int32 dummy __attribute__ ( ( unused ) ) )
runtime: Fix GC bug caused by Entersyscall modifying reg.
This patch fixes a rare but serious bug. The Go garbage
collector only examines Go stacks. When Go code calls a
function that is not written in Go, it first calls
syscall.Entersyscall. Entersyscall records the position of
the Go stack pointer and saves a copy of all the registers.
If the garbage collector runs while the thread is executing
the non-Go code, the garbage collector fetches the stack
pointer and registers from the saved location.
Entersyscall saves the registers using the getcontext
function. Unfortunately I didn't consider the possibility
that Entersyscall might itself change a register before
calling getcontext. This only matters for callee-saved
registers, as caller-saved registers would be visible on the
saved stack. And it only matters if Entersyscall is compiled
to save and modify a callee-saved register before it calls
getcontext. And it only matters if a garbage collection
occurs while the non-Go code is executing. And it only
matters if the only copy of a valid Go pointer happens to be
in the callee-saved register when Entersyscall is called.
When all those conditions are true, the Go pointer might get
collected incorrectly, leading to memory corruption.
This patch tries to avoid the problem by splitting
Entersyscall into two functions. The first is a simple
function that just calls getcontext and then calls the rest of
Entersyscall. This should fix the problem, provided the
simple Entersyscall function does not itself modify any
callee-saved registers before calling getcontext. That seems
to be true on the systems I checked. But since the argument
to getcontext is an offset from a TLS variable, it won't be
true on a system which needs to save callee-saved registers in
order to get the address of a TLS variable. I don't know why
any system would work that way, but I don't know how to rule
it out. I think that on any such system this will have to be
implemented in assembler. I can't put the ucontext_t
structure on the stack, because this function can not split
stacks, and the ucontext_t structure is large enough that it
could cause a stack overflow.
From-SVN: r208390
2014-03-07 05:04:37 +00:00
{
// Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector.
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & g - > gcregs [ 0 ] ) ) ;
runtime: Fix GC bug caused by Entersyscall modifying reg.
This patch fixes a rare but serious bug. The Go garbage
collector only examines Go stacks. When Go code calls a
function that is not written in Go, it first calls
syscall.Entersyscall. Entersyscall records the position of
the Go stack pointer and saves a copy of all the registers.
If the garbage collector runs while the thread is executing
the non-Go code, the garbage collector fetches the stack
pointer and registers from the saved location.
Entersyscall saves the registers using the getcontext
function. Unfortunately I didn't consider the possibility
that Entersyscall might itself change a register before
calling getcontext. This only matters for callee-saved
registers, as caller-saved registers would be visible on the
saved stack. And it only matters if Entersyscall is compiled
to save and modify a callee-saved register before it calls
getcontext. And it only matters if a garbage collection
occurs while the non-Go code is executing. And it only
matters if the only copy of a valid Go pointer happens to be
in the callee-saved register when Entersyscall is called.
When all those conditions are true, the Go pointer might get
collected incorrectly, leading to memory corruption.
This patch tries to avoid the problem by splitting
Entersyscall into two functions. The first is a simple
function that just calls getcontext and then calls the rest of
Entersyscall. This should fix the problem, provided the
simple Entersyscall function does not itself modify any
callee-saved registers before calling getcontext. That seems
to be true on the systems I checked. But since the argument
to getcontext is an offset from a TLS variable, it won't be
true on a system which needs to save callee-saved registers in
order to get the address of a TLS variable. I don't know why
any system would work that way, but I don't know how to rule
it out. I think that on any such system this will have to be
implemented in assembler. I can't put the ucontext_t
structure on the stack, because this function can not split
stacks, and the ucontext_t structure is large enough that it
could cause a stack overflow.
From-SVN: r208390
2014-03-07 05:04:37 +00:00
// Do the work in a separate function, so that this function
// doesn't save any registers on its own stack. If this
// function does save any registers, 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.
2016-11-10 22:53:23 +00:00
doentersyscall ( ( uintptr ) runtime_getcallerpc ( & dummy ) ,
( uintptr ) runtime_getcallersp ( & dummy ) ) ;
runtime: Fix GC bug caused by Entersyscall modifying reg.
This patch fixes a rare but serious bug. The Go garbage
collector only examines Go stacks. When Go code calls a
function that is not written in Go, it first calls
syscall.Entersyscall. Entersyscall records the position of
the Go stack pointer and saves a copy of all the registers.
If the garbage collector runs while the thread is executing
the non-Go code, the garbage collector fetches the stack
pointer and registers from the saved location.
Entersyscall saves the registers using the getcontext
function. Unfortunately I didn't consider the possibility
that Entersyscall might itself change a register before
calling getcontext. This only matters for callee-saved
registers, as caller-saved registers would be visible on the
saved stack. And it only matters if Entersyscall is compiled
to save and modify a callee-saved register before it calls
getcontext. And it only matters if a garbage collection
occurs while the non-Go code is executing. And it only
matters if the only copy of a valid Go pointer happens to be
in the callee-saved register when Entersyscall is called.
When all those conditions are true, the Go pointer might get
collected incorrectly, leading to memory corruption.
This patch tries to avoid the problem by splitting
Entersyscall into two functions. The first is a simple
function that just calls getcontext and then calls the rest of
Entersyscall. This should fix the problem, provided the
simple Entersyscall function does not itself modify any
callee-saved registers before calling getcontext. That seems
to be true on the systems I checked. But since the argument
to getcontext is an offset from a TLS variable, it won't be
true on a system which needs to save callee-saved registers in
order to get the address of a TLS variable. I don't know why
any system would work that way, but I don't know how to rule
it out. I think that on any such system this will have to be
implemented in assembler. I can't put the ucontext_t
structure on the stack, because this function can not split
stacks, and the ucontext_t structure is large enough that it
could cause a stack overflow.
From-SVN: r208390
2014-03-07 05:04:37 +00:00
}
static void
2016-11-10 22:53:23 +00:00
doentersyscall ( uintptr pc , uintptr sp )
2013-07-16 06:54:42 +00:00
{
2016-08-30 21:07:47 +00:00
// Disable preemption because during this function g is in _Gsyscall status,
2013-11-06 19:49:01 +00:00
// but can have inconsistent g->sched, do not let GC observe it.
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ;
2013-07-16 06:54:42 +00:00
2013-11-06 19:49:01 +00:00
// Leave SP around for GC and traceback.
2013-07-16 06:54:42 +00:00
# ifdef USING_SPLIT_STACK
2016-09-20 16:48:19 +00:00
{
size_t gcstacksize ;
g - > gcstack = __splitstack_find ( nil , nil , & gcstacksize ,
& g - > gcnextsegment , & g - > gcnextsp ,
& g - > gcinitialsp ) ;
g - > gcstacksize = ( uintptr ) gcstacksize ;
}
2013-07-16 06:54:42 +00:00
# else
2013-07-16 15:44:54 +00:00
{
2014-06-13 13:50:13 +00:00
void * v ;
2013-07-16 15:44:54 +00:00
2016-08-30 21:07:47 +00:00
g - > gcnextsp = ( byte * ) & v ;
2013-07-16 15:44:54 +00:00
}
2013-07-16 06:54:42 +00:00
# endif
2016-11-10 22:53:23 +00:00
g - > syscallsp = sp ;
g - > syscallpc = pc ;
2016-08-30 21:07:47 +00:00
g - > atomicstatus = _Gsyscall ;
2013-07-16 06:54:42 +00:00
2016-11-18 17:48:29 +00:00
if ( runtime_atomicload ( & runtime_sched - > sysmonwait ) ) { // TODO: fast atomic
runtime_lock ( & runtime_sched - > lock ) ;
if ( runtime_atomicload ( & runtime_sched - > sysmonwait ) ) {
runtime_atomicstore ( & runtime_sched - > sysmonwait , 0 ) ;
runtime_notewakeup ( & runtime_sched - > sysmonnote ) ;
2013-07-16 06:54:42 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
}
2016-08-30 21:07:47 +00:00
g - > m - > mcache = nil ;
( ( P * ) ( g - > m - > p ) ) - > m = 0 ;
runtime_atomicstore ( & ( ( P * ) g - > m - > p ) - > status , _Psyscall ) ;
2016-11-18 17:48:29 +00:00
if ( runtime_atomicload ( & runtime_sched - > gcwaiting ) ) {
runtime_lock ( & runtime_sched - > lock ) ;
if ( runtime_sched - > stopwait > 0 & & runtime_cas ( & ( ( P * ) g - > m - > p ) - > status , _Psyscall , _Pgcstop ) ) {
if ( - - runtime_sched - > stopwait = = 0 )
runtime_notewakeup ( & runtime_sched - > stopnote ) ;
2013-07-16 06:54:42 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
}
2013-11-06 19:49:01 +00:00
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2013-07-16 06:54:42 +00:00
}
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// The same as runtime_entersyscall(), but with a hint that the syscall is blocking.
2011-11-28 05:45:49 +00:00
void
2016-09-30 13:45:08 +00:00
runtime_entersyscallblock ( int32 dummy __attribute__ ( ( unused ) ) )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
P * p ;
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ; // see comment in entersyscall
2012-03-06 17:57:23 +00:00
2013-11-06 19:49:01 +00:00
// Leave SP around for GC and traceback.
2011-11-28 05:45:49 +00:00
# ifdef USING_SPLIT_STACK
2016-09-20 16:48:19 +00:00
{
size_t gcstacksize ;
g - > gcstack = __splitstack_find ( nil , nil , & gcstacksize ,
& g - > gcnextsegment , & g - > gcnextsp ,
& g - > gcinitialsp ) ;
g - > gcstacksize = ( uintptr ) gcstacksize ;
}
2011-11-28 05:45:49 +00:00
# else
2016-08-30 21:07:47 +00:00
g - > gcnextsp = ( byte * ) & p ;
2011-11-28 05:45:49 +00:00
# endif
// Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector.
2016-09-09 13:31:49 +00:00
getcontext ( ucontext_arg ( & g - > gcregs [ 0 ] ) ) ;
2011-11-28 05:45:49 +00:00
2016-11-10 22:53:23 +00:00
g - > syscallpc = ( uintptr ) runtime_getcallerpc ( & dummy ) ;
g - > syscallsp = ( uintptr ) runtime_getcallersp ( & dummy ) ;
2016-08-30 21:07:47 +00:00
g - > atomicstatus = _Gsyscall ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
p = releasep ( ) ;
handoffp ( p ) ;
if ( g - > isbackground ) // do not consider blocked scavenger for deadlock detection
2013-11-06 19:49:01 +00:00
incidlelocked ( 1 ) ;
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
}
// The goroutine g exited its system call.
// Arrange for it to run on a cpu again.
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
void
2016-09-30 13:45:08 +00:00
runtime_exitsyscall ( int32 dummy __attribute__ ( ( unused ) ) )
2011-11-28 05:45:49 +00:00
{
G * gp ;
2013-07-16 06:54:42 +00:00
2011-11-28 05:45:49 +00:00
gp = g ;
2016-08-30 21:07:47 +00:00
gp - > m - > locks + + ; // see comment in entersyscall
2013-11-06 19:49:01 +00:00
if ( gp - > isbackground ) // do not consider blocked scavenger for deadlock detection
incidlelocked ( - 1 ) ;
2016-08-30 21:07:47 +00:00
gp - > waitsince = 0 ;
2013-11-06 19:49:01 +00:00
if ( exitsyscallfast ( ) ) {
2011-11-28 05:45:49 +00:00
// There's a cpu for us, so we can run.
2016-08-30 21:07:47 +00:00
( ( P * ) gp - > m - > p ) - > syscalltick + + ;
gp - > atomicstatus = _Grunning ;
2011-11-28 05:45:49 +00:00
// Garbage collector isn't running (since we are),
2013-07-16 06:54:42 +00:00
// so okay to clear gcstack and gcsp.
2011-11-28 05:45:49 +00:00
# ifdef USING_SPLIT_STACK
gp - > gcstack = nil ;
# endif
2016-08-30 21:07:47 +00:00
gp - > gcnextsp = nil ;
runtime_memclr ( & gp - > gcregs [ 0 ] , sizeof gp - > gcregs ) ;
2016-11-10 22:53:23 +00:00
gp - > syscallsp = 0 ;
2016-08-30 21:07:47 +00:00
gp - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
return ;
}
2016-08-30 21:07:47 +00:00
gp - > m - > locks - - ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// Call the scheduler.
runtime_mcall ( exitsyscall0 ) ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
// Scheduler returned, so we're allowed to run now.
2011-11-28 05:45:49 +00:00
// Delete the gcstack information that we left for
// the garbage collector during the system call.
// Must wait until now because until gosched returns
// we don't know for sure that the garbage collector
// is not running.
# ifdef USING_SPLIT_STACK
gp - > gcstack = nil ;
# endif
2016-08-30 21:07:47 +00:00
gp - > gcnextsp = nil ;
runtime_memclr ( & gp - > gcregs [ 0 ] , sizeof gp - > gcregs ) ;
2013-11-15 17:20:25 +00:00
2016-11-10 22:53:23 +00:00
gp - > syscallsp = 0 ;
2016-08-30 21:07:47 +00:00
// Note that this gp->m might be different than the earlier
// gp->m after returning from runtime_mcall.
( ( P * ) gp - > m - > p ) - > syscalltick + + ;
2013-11-06 19:49:01 +00:00
}
static bool
exitsyscallfast ( void )
{
2016-08-30 21:07:47 +00:00
G * gp ;
2013-11-06 19:49:01 +00:00
P * p ;
2016-08-30 21:07:47 +00:00
gp = g ;
2013-11-06 19:49:01 +00:00
// Freezetheworld sets stopwait but does not retake P's.
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > stopwait ) {
2016-08-30 21:07:47 +00:00
gp - > m - > p = 0 ;
2013-11-06 19:49:01 +00:00
return false ;
}
// Try to re-acquire the last P.
2016-08-30 21:07:47 +00:00
if ( gp - > m - > p & & ( ( P * ) gp - > m - > p ) - > status = = _Psyscall & & runtime_cas ( & ( ( P * ) gp - > m - > p ) - > status , _Psyscall , _Prunning ) ) {
2013-11-06 19:49:01 +00:00
// There's a cpu for us, so we can run.
2016-08-30 21:07:47 +00:00
gp - > m - > mcache = ( ( P * ) gp - > m - > p ) - > mcache ;
( ( P * ) gp - > m - > p ) - > m = ( uintptr ) gp - > m ;
2013-11-06 19:49:01 +00:00
return true ;
}
// Try to get any other idle P.
2016-08-30 21:07:47 +00:00
gp - > m - > p = 0 ;
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > pidle ) {
runtime_lock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
p = pidleget ( ) ;
2016-11-18 17:48:29 +00:00
if ( p & & runtime_atomicload ( & runtime_sched - > sysmonwait ) ) {
runtime_atomicstore ( & runtime_sched - > sysmonwait , 0 ) ;
runtime_notewakeup ( & runtime_sched - > sysmonnote ) ;
2013-11-06 19:49:01 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
if ( p ) {
acquirep ( p ) ;
return true ;
}
}
return false ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
// runtime_exitsyscall slow path on g0.
// Failed to acquire P, enqueue gp as runnable.
static void
exitsyscall0 ( G * gp )
{
2016-08-30 21:07:47 +00:00
M * m ;
2013-07-16 06:54:42 +00:00
P * p ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
gp - > atomicstatus = _Grunnable ;
2013-07-16 06:54:42 +00:00
gp - > m = nil ;
m - > curg = nil ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
p = pidleget ( ) ;
if ( p = = nil )
globrunqput ( gp ) ;
2016-11-18 17:48:29 +00:00
else if ( runtime_atomicload ( & runtime_sched - > sysmonwait ) ) {
runtime_atomicstore ( & runtime_sched - > sysmonwait , 0 ) ;
runtime_notewakeup ( & runtime_sched - > sysmonnote ) ;
2013-11-06 19:49:01 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
if ( p ) {
acquirep ( p ) ;
execute ( gp ) ; // Never returns.
}
if ( m - > lockedg ) {
// Wait until another thread schedules gp and so m again.
stoplockedm ( ) ;
execute ( gp ) ; // Never returns.
}
stopm ( ) ;
schedule ( ) ; // Never returns.
}
2016-09-30 13:45:08 +00:00
void syscall_entersyscall ( void )
__asm__ ( GOSYM_PREFIX " syscall.Entersyscall " ) ;
void syscall_entersyscall ( void ) __attribute__ ( ( no_split_stack ) ) ;
void
syscall_entersyscall ( )
{
runtime_entersyscall ( 0 ) ;
}
void syscall_exitsyscall ( void )
__asm__ ( GOSYM_PREFIX " syscall.Exitsyscall " ) ;
void syscall_exitsyscall ( void ) __attribute__ ( ( no_split_stack ) ) ;
void
syscall_exitsyscall ( )
{
runtime_exitsyscall ( 0 ) ;
}
2013-11-06 19:49:01 +00:00
// Called from syscall package before fork.
void syscall_runtime_BeforeFork ( void )
__asm__ ( GOSYM_PREFIX " syscall.runtime_BeforeFork " ) ;
void
syscall_runtime_BeforeFork ( void )
{
// Fork can hang if preempted with signals frequently enough (see issue 5517).
// Ensure that we stay on the same M where we disable profiling.
2014-07-19 08:53:52 +00:00
runtime_m ( ) - > locks + + ;
if ( runtime_m ( ) - > profilehz ! = 0 )
2013-11-06 19:49:01 +00:00
runtime_resetcpuprofiler ( 0 ) ;
}
// Called from syscall package after fork in parent.
void syscall_runtime_AfterFork ( void )
__asm__ ( GOSYM_PREFIX " syscall.runtime_AfterFork " ) ;
void
syscall_runtime_AfterFork ( void )
{
int32 hz ;
2016-11-18 17:48:29 +00:00
hz = runtime_sched - > profilehz ;
2013-11-06 19:49:01 +00:00
if ( hz ! = 0 )
runtime_resetcpuprofiler ( hz ) ;
2014-07-19 08:53:52 +00:00
runtime_m ( ) - > locks - - ;
2013-11-06 19:49:01 +00:00
}
2011-12-12 23:40:51 +00:00
// Allocate a new g, with a stack big enough for stacksize bytes.
2011-11-28 05:45:49 +00:00
G *
2016-08-30 21:07:47 +00:00
runtime_malg ( int32 stacksize , byte * * ret_stack , uintptr * ret_stacksize )
2011-11-28 05:45:49 +00:00
{
G * newg ;
2014-07-19 08:53:52 +00:00
newg = allocg ( ) ;
2011-11-28 05:45:49 +00:00
if ( stacksize > = 0 ) {
# if USING_SPLIT_STACK
2011-12-21 22:24:47 +00:00
int dont_block_signals = 0 ;
2016-08-30 21:07:47 +00:00
size_t ss_stacksize ;
2011-12-21 22:24:47 +00:00
2011-11-28 05:45:49 +00:00
* ret_stack = __splitstack_makecontext ( stacksize ,
2016-08-30 21:07:47 +00:00
& newg - > stackcontext [ 0 ] ,
& ss_stacksize ) ;
* ret_stacksize = ( uintptr ) ss_stacksize ;
__splitstack_block_signals_context ( & newg - > stackcontext [ 0 ] ,
2011-12-21 22:24:47 +00:00
& dont_block_signals , nil ) ;
2011-11-28 05:45:49 +00:00
# else
runtime: If no split stacks, allocate stacks using mmap on 64-bit systems.
When not using split stacks, libgo allocate large stacks for each
goroutine. On a 64-bit system, libgo allocates a maximum of 128G for
the Go heap, and allocates 4M for each stack. When the stacks are
allocated from the Go heap, the result is that a program can only create
32K goroutines, which is not enough for an active Go server. This patch
changes libgo to allocate the stacks using mmap directly, rather than
allocating them out of the Go heap. This change is only done for 64-bit
systems when not using split stacks. When using split stacks, the
stacks are allocated using mmap directly anyhow. On a 32-bit system,
there is no maximum size for the Go heap, or, rather, the maximum size
is the available address space anyhow.
Reviewed-on: https://go-review.googlesource.com/16531
From-SVN: r229636
2015-10-31 23:48:19 +00:00
// 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 ) {
2016-10-13 15:24:50 +00:00
void * p = runtime_SysAlloc ( stacksize , & mstats ( ) - > other_sys ) ;
runtime: If no split stacks, allocate stacks using mmap on 64-bit systems.
When not using split stacks, libgo allocate large stacks for each
goroutine. On a 64-bit system, libgo allocates a maximum of 128G for
the Go heap, and allocates 4M for each stack. When the stacks are
allocated from the Go heap, the result is that a program can only create
32K goroutines, which is not enough for an active Go server. This patch
changes libgo to allocate the stacks using mmap directly, rather than
allocating them out of the Go heap. This change is only done for 64-bit
systems when not using split stacks. When using split stacks, the
stacks are allocated using mmap directly anyhow. On a 32-bit system,
there is no maximum size for the Go heap, or, rather, the maximum size
is the available address space anyhow.
Reviewed-on: https://go-review.googlesource.com/16531
From-SVN: r229636
2015-10-31 23:48:19 +00:00
if ( p = = nil )
runtime_throw ( " runtime: cannot allocate memory for goroutine stack " ) ;
* ret_stack = ( byte * ) p ;
} else {
* ret_stack = runtime_mallocgc ( stacksize , 0 , FlagNoProfiling | FlagNoGC ) ;
runtime_xadd ( & runtime_stacks_sys , stacksize ) ;
}
2016-08-30 21:07:47 +00:00
* ret_stacksize = ( uintptr ) stacksize ;
newg - > gcinitialsp = * ret_stack ;
newg - > gcstacksize = ( uintptr ) stacksize ;
2011-11-28 05:45:49 +00:00
# endif
}
return newg ;
}
G *
__go_go ( void ( * fn ) ( void * ) , void * arg )
{
byte * sp ;
size_t spsize ;
2012-05-15 18:56:48 +00:00
G * newg ;
2014-06-06 22:37:27 +00:00
P * p ;
2012-10-23 04:31:11 +00:00
2013-11-06 19:49:01 +00:00
//runtime_printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret);
2014-07-19 08:53:52 +00:00
if ( fn = = nil ) {
2016-08-30 21:07:47 +00:00
g - > m - > throwing = - 1 ; // do not dump full stacks
2014-07-19 08:53:52 +00:00
runtime_throw ( " go of nil func value " ) ;
}
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ; // disable preemption because it can be holding p in a local var
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
p = ( P * ) g - > m - > p ;
2014-06-06 22:37:27 +00:00
if ( ( newg = gfget ( p ) ) ! = nil ) {
2011-11-28 05:45:49 +00:00
# ifdef USING_SPLIT_STACK
2011-12-21 22:24:47 +00:00
int dont_block_signals = 0 ;
2016-08-30 21:07:47 +00:00
sp = __splitstack_resetcontext ( & newg - > stackcontext [ 0 ] ,
2011-11-28 05:45:49 +00:00
& spsize ) ;
2016-08-30 21:07:47 +00:00
__splitstack_block_signals_context ( & newg - > stackcontext [ 0 ] ,
2011-12-21 22:24:47 +00:00
& dont_block_signals , nil ) ;
2011-11-28 05:45:49 +00:00
# else
2016-08-30 21:07:47 +00:00
sp = newg - > gcinitialsp ;
spsize = newg - > gcstacksize ;
2012-02-10 15:55:37 +00:00
if ( spsize = = 0 )
runtime_throw ( " bad spsize in __go_go " ) ;
2016-08-30 21:07:47 +00:00
newg - > gcnextsp = sp ;
2011-11-28 05:45:49 +00:00
# endif
} else {
2016-08-30 21:07:47 +00:00
uintptr malsize ;
newg = runtime_malg ( StackMin , & sp , & malsize ) ;
spsize = ( size_t ) malsize ;
2014-06-06 22:37:27 +00:00
allgadd ( newg ) ;
2011-11-28 05:45:49 +00:00
}
newg - > entry = ( byte * ) fn ;
newg - > param = arg ;
newg - > gopc = ( uintptr ) __builtin_return_address ( 0 ) ;
2016-08-30 21:07:47 +00:00
newg - > atomicstatus = _Grunnable ;
2014-06-06 22:37:27 +00:00
if ( p - > goidcache = = p - > goidcacheend ) {
2016-11-18 17:48:29 +00:00
p - > goidcache = runtime_xadd64 ( & runtime_sched - > goidgen , GoidCacheBatch ) ;
2014-06-06 22:37:27 +00:00
p - > goidcacheend = p - > goidcache + GoidCacheBatch ;
}
newg - > goid = p - > goidcache + + ;
2011-11-28 05:45:49 +00:00
2012-05-15 18:56:48 +00:00
{
// Avoid warnings about variables clobbered by
// longjmp.
byte * volatile vsp = sp ;
size_t volatile vspsize = spsize ;
G * volatile vnewg = newg ;
2016-09-09 13:31:49 +00:00
ucontext_t * volatile uc ;
2012-05-15 18:56:48 +00:00
2016-09-09 13:31:49 +00:00
uc = ucontext_arg ( & vnewg - > context [ 0 ] ) ;
getcontext ( uc ) ;
uc - > uc_stack . ss_sp = vsp ;
uc - > uc_stack . ss_size = vspsize ;
makecontext ( uc , kickoff , 0 ) ;
2011-11-28 05:45:49 +00:00
2014-06-06 22:37:27 +00:00
runqput ( p , vnewg ) ;
2011-11-28 05:45:49 +00:00
2016-11-18 17:48:29 +00:00
if ( runtime_atomicload ( & runtime_sched - > npidle ) ! = 0 & & runtime_atomicload ( & runtime_sched - > nmspinning ) = = 0 & & fn ! = runtime_main ) // TODO: fast atomic
2013-07-16 06:54:42 +00:00
wakep ( ) ;
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2012-05-15 18:56:48 +00:00
return vnewg ;
}
2011-11-28 05:45:49 +00:00
}
2014-06-06 22:37:27 +00:00
static void
allgadd ( G * gp )
{
G * * new ;
uintptr cap ;
runtime_lock ( & allglock ) ;
if ( runtime_allglen > = allgcap ) {
cap = 4096 / sizeof ( new [ 0 ] ) ;
if ( cap < 2 * allgcap )
cap = 2 * allgcap ;
new = runtime_malloc ( cap * sizeof ( new [ 0 ] ) ) ;
if ( new = = nil )
runtime_throw ( " runtime: cannot allocate memory " ) ;
if ( runtime_allg ! = nil ) {
runtime_memmove ( new , runtime_allg , runtime_allglen * sizeof ( new [ 0 ] ) ) ;
runtime_free ( runtime_allg ) ;
}
runtime_allg = new ;
allgcap = cap ;
}
runtime_allg [ runtime_allglen + + ] = gp ;
runtime_unlock ( & allglock ) ;
}
2013-07-16 06:54:42 +00:00
// Put on gfree list.
// If local list is too long, transfer a batch to the global list.
2011-11-28 05:45:49 +00:00
static void
2013-07-16 06:54:42 +00:00
gfput ( P * p , G * gp )
{
2016-08-30 21:07:47 +00:00
gp - > schedlink = ( uintptr ) p - > gfree ;
2013-07-16 06:54:42 +00:00
p - > gfree = gp ;
p - > gfreecnt + + ;
if ( p - > gfreecnt > = 64 ) {
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > gflock ) ;
2013-07-16 06:54:42 +00:00
while ( p - > gfreecnt > = 32 ) {
p - > gfreecnt - - ;
gp = p - > gfree ;
2016-08-30 21:07:47 +00:00
p - > gfree = ( G * ) gp - > schedlink ;
2016-11-18 17:48:29 +00:00
gp - > schedlink = ( uintptr ) runtime_sched - > gfree ;
runtime_sched - > gfree = gp ;
2013-07-16 06:54:42 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > gflock ) ;
2013-07-16 06:54:42 +00:00
}
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
// Get from gfree list.
// If local list is empty, grab a batch from global list.
2011-11-28 05:45:49 +00:00
static G *
2013-07-16 06:54:42 +00:00
gfget ( P * p )
2011-11-28 05:45:49 +00:00
{
2012-10-23 04:31:11 +00:00
G * gp ;
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
retry :
gp = p - > gfree ;
2016-11-18 17:48:29 +00:00
if ( gp = = nil & & runtime_sched - > gfree ) {
runtime_lock ( & runtime_sched - > gflock ) ;
while ( p - > gfreecnt < 32 & & runtime_sched - > gfree ) {
2013-07-16 06:54:42 +00:00
p - > gfreecnt + + ;
2016-11-18 17:48:29 +00:00
gp = runtime_sched - > gfree ;
runtime_sched - > gfree = ( G * ) gp - > schedlink ;
2016-08-30 21:07:47 +00:00
gp - > schedlink = ( uintptr ) p - > gfree ;
2013-07-16 06:54:42 +00:00
p - > gfree = gp ;
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > gflock ) ;
2013-07-16 06:54:42 +00:00
goto retry ;
}
if ( gp ) {
2016-08-30 21:07:47 +00:00
p - > gfree = ( G * ) gp - > schedlink ;
2013-07-16 06:54:42 +00:00
p - > gfreecnt - - ;
}
2012-10-23 04:31:11 +00:00
return gp ;
2011-11-28 05:45:49 +00:00
}
2013-07-16 06:54:42 +00:00
// Purge all cached G's from gfree list to the global list.
static void
gfpurge ( P * p )
{
G * gp ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > gflock ) ;
2013-07-16 06:54:42 +00:00
while ( p - > gfreecnt ) {
p - > gfreecnt - - ;
gp = p - > gfree ;
2016-08-30 21:07:47 +00:00
p - > gfree = ( G * ) gp - > schedlink ;
2016-11-18 17:48:29 +00:00
gp - > schedlink = ( uintptr ) runtime_sched - > gfree ;
runtime_sched - > gfree = gp ;
2013-07-16 06:54:42 +00:00
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > gflock ) ;
2013-07-16 06:54:42 +00:00
}
void
runtime_Breakpoint ( void )
{
runtime_breakpoint ( ) ;
}
2013-01-24 19:44:23 +00:00
void runtime_Gosched ( void ) __asm__ ( GOSYM_PREFIX " runtime.Gosched " ) ;
2011-11-28 05:45:49 +00:00
void
runtime_Gosched ( void )
{
runtime_gosched ( ) ;
}
2011-12-12 23:40:51 +00:00
// Implementation of runtime.GOMAXPROCS.
2013-07-16 06:54:42 +00:00
// delete when scheduler is even stronger
2016-11-16 18:33:11 +00:00
intgo runtime_GOMAXPROCS ( intgo )
__asm__ ( GOSYM_PREFIX " runtime.GOMAXPROCS " ) ;
intgo
runtime_GOMAXPROCS ( intgo n )
2011-11-28 05:45:49 +00:00
{
2016-11-16 18:33:11 +00:00
intgo ret ;
2011-11-28 05:45:49 +00:00
2016-08-30 21:07:47 +00:00
if ( n > _MaxGomaxprocs )
n = _MaxGomaxprocs ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2016-11-16 18:33:11 +00:00
ret = ( intgo ) runtime_gomaxprocs ;
2013-07-16 06:54:42 +00:00
if ( n < = 0 | | n = = ret ) {
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
return ret ;
}
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
2016-10-13 15:24:50 +00:00
runtime_acquireWorldsema ( ) ;
2016-08-30 21:07:47 +00:00
g - > m - > gcing = 1 ;
2016-10-13 15:24:50 +00:00
runtime_stopTheWorldWithSema ( ) ;
2016-11-16 18:33:11 +00:00
newprocs = ( int32 ) n ;
2016-08-30 21:07:47 +00:00
g - > m - > gcing = 0 ;
2016-10-13 15:24:50 +00:00
runtime_releaseWorldsema ( ) ;
runtime_startTheWorldWithSema ( ) ;
2011-11-28 05:45:49 +00:00
return ret ;
}
2013-11-06 19:49:01 +00:00
// lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below
// after they modify m->locked. Do not allow preemption during this call,
// or else the m might be different in this function than in the caller.
2013-07-16 06:54:42 +00:00
static void
2013-11-06 19:49:01 +00:00
lockOSThread ( void )
2011-12-02 19:34:41 +00:00
{
2016-08-30 21:07:47 +00:00
g - > m - > lockedg = g ;
g - > lockedm = g - > m ;
2011-12-02 19:34:41 +00:00
}
2011-11-28 05:45:49 +00:00
2013-07-16 06:54:42 +00:00
void runtime_LockOSThread ( void ) __asm__ ( GOSYM_PREFIX " runtime.LockOSThread " ) ;
2011-11-28 05:45:49 +00:00
void
2013-07-16 06:54:42 +00:00
runtime_LockOSThread ( void )
{
2016-08-30 21:07:47 +00:00
g - > m - > locked | = _LockExternal ;
2013-11-06 19:49:01 +00:00
lockOSThread ( ) ;
2013-07-16 06:54:42 +00:00
}
void
runtime_lockOSThread ( void )
{
2016-08-30 21:07:47 +00:00
g - > m - > locked + = _LockInternal ;
2013-11-06 19:49:01 +00:00
lockOSThread ( ) ;
2013-07-16 06:54:42 +00:00
}
2013-11-06 19:49:01 +00:00
// unlockOSThread is called by runtime.UnlockOSThread and runtime.unlockOSThread below
// after they update m->locked. Do not allow preemption during this call,
// or else the m might be in different in this function than in the caller.
2013-07-16 06:54:42 +00:00
static void
2013-11-06 19:49:01 +00:00
unlockOSThread ( void )
2011-11-28 05:45:49 +00:00
{
2016-08-30 21:07:47 +00:00
if ( g - > m - > locked ! = 0 )
2011-12-02 19:34:41 +00:00
return ;
2016-08-30 21:07:47 +00:00
g - > m - > lockedg = nil ;
2011-11-28 05:45:49 +00:00
g - > lockedm = nil ;
}
2013-07-16 06:54:42 +00:00
void runtime_UnlockOSThread ( void ) __asm__ ( GOSYM_PREFIX " runtime.UnlockOSThread " ) ;
void
runtime_UnlockOSThread ( void )
{
2016-08-30 21:07:47 +00:00
g - > m - > locked & = ~ _LockExternal ;
2013-11-06 19:49:01 +00:00
unlockOSThread ( ) ;
2013-07-16 06:54:42 +00:00
}
void
runtime_unlockOSThread ( void )
{
2016-08-30 21:07:47 +00:00
if ( g - > m - > locked < _LockInternal )
2013-07-16 06:54:42 +00:00
runtime_throw ( " runtime: internal error: misuse of lockOSThread/unlockOSThread " ) ;
2016-08-30 21:07:47 +00:00
g - > m - > locked - = _LockInternal ;
2013-11-06 19:49:01 +00:00
unlockOSThread ( ) ;
2013-07-16 06:54:42 +00:00
}
2011-11-28 05:45:49 +00:00
bool
runtime_lockedOSThread ( void )
{
2016-08-30 21:07:47 +00:00
return g - > lockedm ! = nil & & g - > m - > lockedg ! = nil ;
2011-11-28 05:45:49 +00:00
}
int32
2012-03-02 20:01:37 +00:00
runtime_gcount ( void )
2011-11-28 05:45:49 +00:00
{
2013-07-16 06:54:42 +00:00
G * gp ;
int32 n , s ;
2014-06-06 22:37:27 +00:00
uintptr i ;
2013-07-16 06:54:42 +00:00
n = 0 ;
2014-06-06 22:37:27 +00:00
runtime_lock ( & allglock ) ;
2013-07-16 06:54:42 +00:00
// TODO(dvyukov): runtime.NumGoroutine() is O(N).
// We do not want to increment/decrement centralized counter in newproc/goexit,
// just to make runtime.NumGoroutine() faster.
// Compromise solution is to introduce per-P counters of active goroutines.
2014-06-06 22:37:27 +00:00
for ( i = 0 ; i < runtime_allglen ; i + + ) {
gp = runtime_allg [ i ] ;
2016-08-30 21:07:47 +00:00
s = gp - > atomicstatus ;
if ( s = = _Grunnable | | s = = _Grunning | | s = = _Gsyscall | | s = = _Gwaiting )
2013-07-16 06:54:42 +00:00
n + + ;
}
2014-06-06 22:37:27 +00:00
runtime_unlock ( & allglock ) ;
2013-07-16 06:54:42 +00:00
return n ;
2011-11-28 05:45:49 +00:00
}
int32
runtime_mcount ( void )
{
2016-11-18 17:48:29 +00:00
return runtime_sched - > mcount ;
2011-11-28 05:45:49 +00:00
}
2011-03-27 19:14:55 +00:00
static struct {
2016-10-14 13:36:35 +00:00
uint32 lock ;
2011-03-27 19:14:55 +00:00
int32 hz ;
} prof ;
2014-06-06 22:37:27 +00:00
static void System ( void ) { }
static void GC ( void ) { }
2013-11-06 19:49:01 +00:00
2011-12-12 23:40:51 +00:00
// Called if we receive a SIGPROF signal.
2011-03-27 19:14:55 +00:00
void
2012-07-26 01:57:04 +00:00
runtime_sigprof ( )
2011-03-27 19:14:55 +00:00
{
2016-08-30 21:07:47 +00:00
M * mp = g - > m ;
2013-01-30 22:24:40 +00:00
int32 n , i ;
2013-11-06 19:49:01 +00:00
bool traceback ;
2016-10-14 13:36:35 +00:00
uintptr pcbuf [ TracebackMaxFrames ] ;
Location locbuf [ TracebackMaxFrames ] ;
Slice stk ;
2011-11-28 05:45:49 +00:00
2016-10-14 13:36:35 +00:00
if ( prof . hz = = 0 )
2011-03-27 19:14:55 +00:00
return ;
2014-06-06 22:37:27 +00:00
if ( mp = = nil )
return ;
2014-07-19 08:53:52 +00:00
// Profiling runs concurrently with GC, so it must not allocate.
mp - > mallocing + + ;
2013-11-06 19:49:01 +00:00
traceback = true ;
2014-06-06 22:37:27 +00:00
if ( mp - > mcache = = nil )
2013-11-06 19:49:01 +00:00
traceback = false ;
2014-06-06 22:37:27 +00:00
2013-11-06 19:49:01 +00:00
n = 0 ;
2013-12-01 01:40:16 +00:00
if ( runtime_atomicload ( & runtime_in_callers ) > 0 ) {
// If SIGPROF arrived while already fetching runtime
// callers we can have trouble on older systems
// because the unwind library calls dl_iterate_phdr
// which was not recursive in the past.
traceback = false ;
}
2013-11-06 19:49:01 +00:00
if ( traceback ) {
2016-10-14 13:36:35 +00:00
n = runtime_callers ( 0 , locbuf , nelem ( locbuf ) , false ) ;
2013-11-06 19:49:01 +00:00
for ( i = 0 ; i < n ; i + + )
2016-10-14 13:36:35 +00:00
pcbuf [ i ] = locbuf [ i ] . pc ;
2013-11-06 19:49:01 +00:00
}
2014-06-06 22:37:27 +00:00
if ( ! traceback | | n < = 0 ) {
2013-11-06 19:49:01 +00:00
n = 2 ;
2016-10-14 13:36:35 +00:00
pcbuf [ 0 ] = ( uintptr ) runtime_getcallerpc ( & n ) ;
2014-06-06 22:37:27 +00:00
if ( mp - > gcing | | mp - > helpgc )
2016-10-14 13:36:35 +00:00
pcbuf [ 1 ] = ( uintptr ) GC ;
2014-06-06 22:37:27 +00:00
else
2016-10-14 13:36:35 +00:00
pcbuf [ 1 ] = ( uintptr ) System ;
}
if ( prof . hz ! = 0 ) {
stk . __values = & pcbuf [ 0 ] ;
stk . __count = n ;
stk . __capacity = n ;
// Simple cas-lock to coordinate with setcpuprofilerate.
while ( ! runtime_cas ( & prof . lock , 0 , 1 ) ) {
runtime_osyield ( ) ;
}
if ( prof . hz ! = 0 ) {
runtime_cpuprofAdd ( stk ) ;
}
runtime_atomicstore ( & prof . lock , 0 ) ;
2013-11-06 19:49:01 +00:00
}
2016-10-14 13:36:35 +00:00
2014-06-06 22:37:27 +00:00
mp - > mallocing - - ;
2011-03-27 19:14:55 +00:00
}
2011-12-12 23:40:51 +00:00
// Arrange to call fn with a traceback hz times a second.
2011-03-27 19:14:55 +00:00
void
2016-10-14 13:36:35 +00:00
runtime_setcpuprofilerate_m ( int32 hz )
2011-03-27 19:14:55 +00:00
{
// Force sane arguments.
if ( hz < 0 )
hz = 0 ;
2013-11-06 19:49:01 +00:00
// Disable preemption, otherwise we can be rescheduled to another thread
// that has profiling enabled.
2016-08-30 21:07:47 +00:00
g - > m - > locks + + ;
2013-11-06 19:49:01 +00:00
// Stop profiler on this thread so that it is safe to lock prof.
2011-03-27 19:14:55 +00:00
// if a profiling signal came in while we had prof locked,
// it would deadlock.
runtime_resetcpuprofiler ( 0 ) ;
2016-10-14 13:36:35 +00:00
while ( ! runtime_cas ( & prof . lock , 0 , 1 ) ) {
runtime_osyield ( ) ;
}
2011-03-27 19:14:55 +00:00
prof . hz = hz ;
2016-10-14 13:36:35 +00:00
runtime_atomicstore ( & prof . lock , 0 ) ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
runtime_sched - > profilehz = hz ;
runtime_unlock ( & runtime_sched - > lock ) ;
2011-11-28 05:45:49 +00:00
2011-03-27 19:14:55 +00:00
if ( hz ! = 0 )
runtime_resetcpuprofiler ( hz ) ;
2013-11-06 19:49:01 +00:00
2016-08-30 21:07:47 +00:00
g - > m - > locks - - ;
2011-03-27 19:14:55 +00:00
}
2013-07-16 06:54:42 +00:00
// Change number of processors. The world is stopped, sched is locked.
static void
procresize ( int32 new )
{
int32 i , old ;
compiler, runtime: replace hashmap code with Go 1.7 hashmap
This change removes the gccgo-specific hashmap code and replaces it with
the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is
more efficient, does a better job on details like when to update a key,
and provides some support against denial-of-service attacks.
The compiler is changed to call the new hashmap functions instead of the
old ones.
The compiler now tracks which types are reflexive and which require
updating when used as a map key, and records the information in map type
descriptors.
Map_index_expression is simplified. The special case for a map index on
the right hand side of a tuple expression has been unnecessary for some
time, and is removed. The support for specially marking a map index as
an lvalue is removed, in favor of lowering an assignment to a map index
into a function call. The long-obsolete support for a map index of a
pointer to a map is removed.
The __go_new_map_big function (known to the compiler as
Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap
function takes an int64 hint argument.
The old map descriptor type and supporting expression is removed.
The compiler was still supporting the long-obsolete syntax `m[k] = 0,
false` to delete a value from a map. That is now removed, requiring a
change to one of the gccgo-specific tests.
The builtin len function applied to a map or channel p is now compiled
as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to
the compiler as Runtime::CHAN_LEN) is removed.
Support for a shared zero value for maps to large value types is
introduced, along the lines of the gc compiler. The zero value is
handled as a common variable.
The hash function is changed to take a seed argument, changing the
runtime hash functions and the compiler-generated hash functions.
Unlike the gc compiler, both the hash and equal functions continue to
take the type length.
Types that can not be compared now store nil for the hash and equal
functions, rather than pointing to functions that throw. Interface hash
and comparison functions now check explicitly for nil. This matches the
gc compiler and permits a simple implementation for ismapkey.
The compiler is changed to permit marking struct and array types as
incomparable, meaning that they have no hash or equal function. We use
this for thunk types, removing the existing special code to avoid
generating hash/equal functions for them.
The C runtime code adds memclr, memequal, and memmove functions.
The hashmap code uses go:linkname comments to make the functions
visible, as otherwise the compiler would discard them.
The hashmap code comments out the unused reference to the address of the
first parameter in the race code, as otherwise the compiler thinks that
the parameter escapes and copies it onto the heap. This is probably not
needed when we enable escape analysis.
Several runtime map tests that ere previously skipped for gccgo are now
run.
The Go runtime picks up type kind information and stubs. The type kind
information causes the generated runtime header file to define some
constants, including `empty`, and the C code is adjusted accordingly.
A Go-callable version of runtime.throw, that takes a Go string, is
added to be called from the hashmap code.
Reviewed-on: https://go-review.googlesource.com/29447
* go.go-torture/execute/map-1.go: Replace old map deletion syntax
with call to builtin delete function.
From-SVN: r240334
2016-09-21 20:58:51 +00:00
bool pempty ;
2013-07-16 06:54:42 +00:00
G * gp ;
P * p ;
old = runtime_gomaxprocs ;
2016-08-30 21:07:47 +00:00
if ( old < 0 | | old > _MaxGomaxprocs | | new < = 0 | | new > _MaxGomaxprocs )
2013-07-16 06:54:42 +00:00
runtime_throw ( " procresize: invalid arg " ) ;
// initialize new P's
for ( i = 0 ; i < new ; i + + ) {
p = runtime_allp [ i ] ;
if ( p = = nil ) {
2013-11-06 19:49:01 +00:00
p = ( P * ) runtime_mallocgc ( sizeof ( * p ) , 0 , FlagNoInvokeGC ) ;
p - > id = i ;
2016-08-30 21:07:47 +00:00
p - > status = _Pgcstop ;
2013-07-16 06:54:42 +00:00
runtime_atomicstorep ( & runtime_allp [ i ] , p ) ;
}
if ( p - > mcache = = nil ) {
if ( old = = 0 & & i = = 0 )
2016-08-30 21:07:47 +00:00
p - > mcache = g - > m - > mcache ; // bootstrap
2013-07-16 06:54:42 +00:00
else
p - > mcache = runtime_allocmcache ( ) ;
}
}
// redistribute runnable G's evenly
2014-06-06 22:37:27 +00:00
// collect all runnable goroutines in global queue preserving FIFO order
// FIFO order is required to ensure fairness even during frequent GCs
// see http://golang.org/issue/7126
compiler, runtime: replace hashmap code with Go 1.7 hashmap
This change removes the gccgo-specific hashmap code and replaces it with
the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is
more efficient, does a better job on details like when to update a key,
and provides some support against denial-of-service attacks.
The compiler is changed to call the new hashmap functions instead of the
old ones.
The compiler now tracks which types are reflexive and which require
updating when used as a map key, and records the information in map type
descriptors.
Map_index_expression is simplified. The special case for a map index on
the right hand side of a tuple expression has been unnecessary for some
time, and is removed. The support for specially marking a map index as
an lvalue is removed, in favor of lowering an assignment to a map index
into a function call. The long-obsolete support for a map index of a
pointer to a map is removed.
The __go_new_map_big function (known to the compiler as
Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap
function takes an int64 hint argument.
The old map descriptor type and supporting expression is removed.
The compiler was still supporting the long-obsolete syntax `m[k] = 0,
false` to delete a value from a map. That is now removed, requiring a
change to one of the gccgo-specific tests.
The builtin len function applied to a map or channel p is now compiled
as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to
the compiler as Runtime::CHAN_LEN) is removed.
Support for a shared zero value for maps to large value types is
introduced, along the lines of the gc compiler. The zero value is
handled as a common variable.
The hash function is changed to take a seed argument, changing the
runtime hash functions and the compiler-generated hash functions.
Unlike the gc compiler, both the hash and equal functions continue to
take the type length.
Types that can not be compared now store nil for the hash and equal
functions, rather than pointing to functions that throw. Interface hash
and comparison functions now check explicitly for nil. This matches the
gc compiler and permits a simple implementation for ismapkey.
The compiler is changed to permit marking struct and array types as
incomparable, meaning that they have no hash or equal function. We use
this for thunk types, removing the existing special code to avoid
generating hash/equal functions for them.
The C runtime code adds memclr, memequal, and memmove functions.
The hashmap code uses go:linkname comments to make the functions
visible, as otherwise the compiler would discard them.
The hashmap code comments out the unused reference to the address of the
first parameter in the race code, as otherwise the compiler thinks that
the parameter escapes and copies it onto the heap. This is probably not
needed when we enable escape analysis.
Several runtime map tests that ere previously skipped for gccgo are now
run.
The Go runtime picks up type kind information and stubs. The type kind
information causes the generated runtime header file to define some
constants, including `empty`, and the C code is adjusted accordingly.
A Go-callable version of runtime.throw, that takes a Go string, is
added to be called from the hashmap code.
Reviewed-on: https://go-review.googlesource.com/29447
* go.go-torture/execute/map-1.go: Replace old map deletion syntax
with call to builtin delete function.
From-SVN: r240334
2016-09-21 20:58:51 +00:00
pempty = false ;
while ( ! pempty ) {
pempty = true ;
2014-06-06 22:37:27 +00:00
for ( i = 0 ; i < old ; i + + ) {
p = runtime_allp [ i ] ;
if ( p - > runqhead = = p - > runqtail )
continue ;
compiler, runtime: replace hashmap code with Go 1.7 hashmap
This change removes the gccgo-specific hashmap code and replaces it with
the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is
more efficient, does a better job on details like when to update a key,
and provides some support against denial-of-service attacks.
The compiler is changed to call the new hashmap functions instead of the
old ones.
The compiler now tracks which types are reflexive and which require
updating when used as a map key, and records the information in map type
descriptors.
Map_index_expression is simplified. The special case for a map index on
the right hand side of a tuple expression has been unnecessary for some
time, and is removed. The support for specially marking a map index as
an lvalue is removed, in favor of lowering an assignment to a map index
into a function call. The long-obsolete support for a map index of a
pointer to a map is removed.
The __go_new_map_big function (known to the compiler as
Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap
function takes an int64 hint argument.
The old map descriptor type and supporting expression is removed.
The compiler was still supporting the long-obsolete syntax `m[k] = 0,
false` to delete a value from a map. That is now removed, requiring a
change to one of the gccgo-specific tests.
The builtin len function applied to a map or channel p is now compiled
as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to
the compiler as Runtime::CHAN_LEN) is removed.
Support for a shared zero value for maps to large value types is
introduced, along the lines of the gc compiler. The zero value is
handled as a common variable.
The hash function is changed to take a seed argument, changing the
runtime hash functions and the compiler-generated hash functions.
Unlike the gc compiler, both the hash and equal functions continue to
take the type length.
Types that can not be compared now store nil for the hash and equal
functions, rather than pointing to functions that throw. Interface hash
and comparison functions now check explicitly for nil. This matches the
gc compiler and permits a simple implementation for ismapkey.
The compiler is changed to permit marking struct and array types as
incomparable, meaning that they have no hash or equal function. We use
this for thunk types, removing the existing special code to avoid
generating hash/equal functions for them.
The C runtime code adds memclr, memequal, and memmove functions.
The hashmap code uses go:linkname comments to make the functions
visible, as otherwise the compiler would discard them.
The hashmap code comments out the unused reference to the address of the
first parameter in the race code, as otherwise the compiler thinks that
the parameter escapes and copies it onto the heap. This is probably not
needed when we enable escape analysis.
Several runtime map tests that ere previously skipped for gccgo are now
run.
The Go runtime picks up type kind information and stubs. The type kind
information causes the generated runtime header file to define some
constants, including `empty`, and the C code is adjusted accordingly.
A Go-callable version of runtime.throw, that takes a Go string, is
added to be called from the hashmap code.
Reviewed-on: https://go-review.googlesource.com/29447
* go.go-torture/execute/map-1.go: Replace old map deletion syntax
with call to builtin delete function.
From-SVN: r240334
2016-09-21 20:58:51 +00:00
pempty = false ;
2014-06-06 22:37:27 +00:00
// pop from tail of local queue
p - > runqtail - - ;
2016-08-30 21:07:47 +00:00
gp = ( G * ) p - > runq [ p - > runqtail % nelem ( p - > runq ) ] ;
2014-06-06 22:37:27 +00:00
// push onto head of global queue
2016-11-18 17:48:29 +00:00
gp - > schedlink = runtime_sched - > runqhead ;
runtime_sched - > runqhead = ( uintptr ) gp ;
if ( runtime_sched - > runqtail = = 0 )
runtime_sched - > runqtail = ( uintptr ) gp ;
runtime_sched - > runqsize + + ;
2014-06-06 22:37:27 +00:00
}
2013-07-16 06:54:42 +00:00
}
2014-06-06 22:37:27 +00:00
// fill local queues with at most nelem(p->runq)/2 goroutines
2013-07-16 06:54:42 +00:00
// start at 1 because current M already executes some G and will acquire allp[0] below,
// so if we have a spare G we want to put it into allp[1].
2016-11-18 17:48:29 +00:00
for ( i = 1 ; ( uint32 ) i < ( uint32 ) new * nelem ( p - > runq ) / 2 & & runtime_sched - > runqsize > 0 ; i + + ) {
gp = ( G * ) runtime_sched - > runqhead ;
runtime_sched - > runqhead = gp - > schedlink ;
if ( runtime_sched - > runqhead = = 0 )
runtime_sched - > runqtail = 0 ;
runtime_sched - > runqsize - - ;
2013-07-16 06:54:42 +00:00
runqput ( runtime_allp [ i % new ] , gp ) ;
}
// free unused P's
for ( i = new ; i < old ; i + + ) {
p = runtime_allp [ i ] ;
runtime_freemcache ( p - > mcache ) ;
p - > mcache = nil ;
gfpurge ( p ) ;
2016-08-30 21:07:47 +00:00
p - > status = _Pdead ;
2013-07-16 06:54:42 +00:00
// can't free P itself because it can be referenced by an M in syscall
}
2016-08-30 21:07:47 +00:00
if ( g - > m - > p )
( ( P * ) g - > m - > p ) - > m = 0 ;
g - > m - > p = 0 ;
g - > m - > mcache = nil ;
2013-07-16 06:54:42 +00:00
p = runtime_allp [ 0 ] ;
2016-08-30 21:07:47 +00:00
p - > m = 0 ;
p - > status = _Pidle ;
2013-07-16 06:54:42 +00:00
acquirep ( p ) ;
for ( i = new - 1 ; i > 0 ; i - - ) {
p = runtime_allp [ i ] ;
2016-08-30 21:07:47 +00:00
p - > status = _Pidle ;
2013-07-16 06:54:42 +00:00
pidleput ( p ) ;
}
runtime_atomicstore ( ( uint32 * ) & runtime_gomaxprocs , new ) ;
}
// Associate p and the current m.
static void
acquirep ( P * p )
{
2016-08-30 21:07:47 +00:00
M * m ;
m = g - > m ;
2013-07-16 06:54:42 +00:00
if ( m - > p | | m - > mcache )
runtime_throw ( " acquirep: already in go " ) ;
2016-08-30 21:07:47 +00:00
if ( p - > m | | p - > status ! = _Pidle ) {
runtime_printf ( " acquirep: p->m=%p(%d) p->status=%d \n " , p - > m , p - > m ? ( ( M * ) p - > m ) - > id : 0 , p - > status ) ;
2013-07-16 06:54:42 +00:00
runtime_throw ( " acquirep: invalid p state " ) ;
}
m - > mcache = p - > mcache ;
2016-08-30 21:07:47 +00:00
m - > p = ( uintptr ) p ;
p - > m = ( uintptr ) m ;
p - > status = _Prunning ;
2013-07-16 06:54:42 +00:00
}
// Disassociate p and the current m.
static P *
releasep ( void )
{
2016-08-30 21:07:47 +00:00
M * m ;
2013-07-16 06:54:42 +00:00
P * p ;
2016-08-30 21:07:47 +00:00
m = g - > m ;
if ( m - > p = = 0 | | m - > mcache = = nil )
2013-07-16 06:54:42 +00:00
runtime_throw ( " releasep: invalid arg " ) ;
2016-08-30 21:07:47 +00:00
p = ( P * ) m - > p ;
if ( ( M * ) p - > m ! = m | | p - > mcache ! = m - > mcache | | p - > status ! = _Prunning ) {
2013-07-16 06:54:42 +00:00
runtime_printf ( " releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d \n " ,
m , m - > p , p - > m , m - > mcache , p - > mcache , p - > status ) ;
runtime_throw ( " releasep: invalid p state " ) ;
}
2016-08-30 21:07:47 +00:00
m - > p = 0 ;
2013-07-16 06:54:42 +00:00
m - > mcache = nil ;
2016-08-30 21:07:47 +00:00
p - > m = 0 ;
p - > status = _Pidle ;
2013-07-16 06:54:42 +00:00
return p ;
}
static void
2013-11-06 19:49:01 +00:00
incidlelocked ( int32 v )
2013-07-16 06:54:42 +00:00
{
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
runtime_sched - > nmidlelocked + = v ;
2013-07-16 06:54:42 +00:00
if ( v > 0 )
checkdead ( ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
}
// Check for deadlock situation.
// The check is based on number of running M's, if 0 -> deadlock.
static void
checkdead ( void )
{
G * gp ;
int32 run , grunning , s ;
2014-06-06 22:37:27 +00:00
uintptr i ;
2013-07-16 06:54:42 +00:00
2015-04-29 21:31:53 +00:00
// For -buildmode=c-shared or -buildmode=c-archive it's OK if
// there are no running goroutines. The calling program is
// assumed to be running.
if ( runtime_isarchive ) {
return ;
}
2013-07-16 06:54:42 +00:00
// -1 for sysmon
2016-11-18 17:48:29 +00:00
run = runtime_sched - > mcount - runtime_sched - > nmidle - runtime_sched - > nmidlelocked - 1 - countextra ( ) ;
2013-07-16 06:54:42 +00:00
if ( run > 0 )
return ;
2014-06-06 22:37:27 +00:00
// If we are dying because of a signal caught on an already idle thread,
// freezetheworld will cause all running threads to block.
// And runtime will essentially enter into deadlock state,
// except that there is a thread that will call runtime_exit soon.
if ( runtime_panicking > 0 )
return ;
2013-07-16 06:54:42 +00:00
if ( run < 0 ) {
2014-06-06 22:37:27 +00:00
runtime_printf ( " runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d \n " ,
2016-11-18 17:48:29 +00:00
runtime_sched - > nmidle , runtime_sched - > nmidlelocked , runtime_sched - > mcount ) ;
2013-07-16 06:54:42 +00:00
runtime_throw ( " checkdead: inconsistent counts " ) ;
}
grunning = 0 ;
2014-06-06 22:37:27 +00:00
runtime_lock ( & allglock ) ;
for ( i = 0 ; i < runtime_allglen ; i + + ) {
gp = runtime_allg [ i ] ;
2013-07-16 06:54:42 +00:00
if ( gp - > isbackground )
continue ;
2016-08-30 21:07:47 +00:00
s = gp - > atomicstatus ;
if ( s = = _Gwaiting )
2013-07-16 06:54:42 +00:00
grunning + + ;
2016-08-30 21:07:47 +00:00
else if ( s = = _Grunnable | | s = = _Grunning | | s = = _Gsyscall ) {
2014-06-06 22:37:27 +00:00
runtime_unlock ( & allglock ) ;
runtime_printf ( " runtime: checkdead: find g %D in status %d \n " , gp - > goid , s ) ;
2013-07-16 06:54:42 +00:00
runtime_throw ( " checkdead: runnable g " ) ;
}
}
2014-06-06 22:37:27 +00:00
runtime_unlock ( & allglock ) ;
2013-07-16 06:54:42 +00:00
if ( grunning = = 0 ) // possible if main goroutine calls runtime_Goexit()
2014-07-19 08:53:52 +00:00
runtime_throw ( " no goroutines (main called runtime.Goexit) - deadlock! " ) ;
2016-08-30 21:07:47 +00:00
g - > m - > throwing = - 1 ; // do not dump full stacks
2013-07-16 06:54:42 +00:00
runtime_throw ( " all goroutines are asleep - deadlock! " ) ;
}
static void
sysmon ( void )
{
uint32 idle , delay ;
2013-11-06 19:49:01 +00:00
int64 now , lastpoll , lasttrace ;
2013-07-16 06:54:42 +00:00
G * gp ;
2013-11-06 19:49:01 +00:00
lasttrace = 0 ;
2013-07-16 06:54:42 +00:00
idle = 0 ; // how many cycles in succession we had not wokeup somebody
delay = 0 ;
for ( ; ; ) {
if ( idle = = 0 ) // start with 20us sleep...
delay = 20 ;
else if ( idle > 50 ) // start doubling the sleep after 1ms...
delay * = 2 ;
if ( delay > 10 * 1000 ) // up to 10ms
delay = 10 * 1000 ;
runtime_usleep ( delay ) ;
2013-11-06 19:49:01 +00:00
if ( runtime_debug . schedtrace < = 0 & &
2016-11-18 17:48:29 +00:00
( runtime_sched - > gcwaiting | | runtime_atomicload ( & runtime_sched - > npidle ) = = ( uint32 ) runtime_gomaxprocs ) ) { // TODO: fast atomic
runtime_lock ( & runtime_sched - > lock ) ;
if ( runtime_atomicload ( & runtime_sched - > gcwaiting ) | | runtime_atomicload ( & runtime_sched - > npidle ) = = ( uint32 ) runtime_gomaxprocs ) {
runtime_atomicstore ( & runtime_sched - > sysmonwait , 1 ) ;
runtime_unlock ( & runtime_sched - > lock ) ;
runtime_notesleep ( & runtime_sched - > sysmonnote ) ;
runtime_noteclear ( & runtime_sched - > sysmonnote ) ;
2013-07-16 06:54:42 +00:00
idle = 0 ;
delay = 20 ;
} else
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-07-16 06:54:42 +00:00
}
// poll network if not polled for more than 10ms
2016-11-18 17:48:29 +00:00
lastpoll = runtime_atomicload64 ( & runtime_sched - > lastpoll ) ;
2013-07-16 06:54:42 +00:00
now = runtime_nanotime ( ) ;
2013-11-06 19:49:01 +00:00
if ( lastpoll ! = 0 & & lastpoll + 10 * 1000 * 1000 < now ) {
2016-11-18 17:48:29 +00:00
runtime_cas64 ( & runtime_sched - > lastpoll , lastpoll , now ) ;
2013-07-16 06:54:42 +00:00
gp = runtime_netpoll ( false ) ; // non-blocking
2013-11-06 19:49:01 +00:00
if ( gp ) {
// Need to decrement number of idle locked M's
// (pretending that one more is running) before injectglist.
// Otherwise it can lead to the following situation:
// injectglist grabs all P's but before it starts M's to run the P's,
// another M returns from syscall, finishes running its G,
// observes that there is no work to do and no other running M's
// and reports deadlock.
incidlelocked ( - 1 ) ;
injectglist ( gp ) ;
incidlelocked ( 1 ) ;
}
2013-07-16 06:54:42 +00:00
}
// retake P's blocked in syscalls
2013-11-06 19:49:01 +00:00
// and preempt long running G's
if ( retake ( now ) )
2013-07-16 06:54:42 +00:00
idle = 0 ;
else
idle + + ;
2013-11-06 19:49:01 +00:00
if ( runtime_debug . schedtrace > 0 & & lasttrace + runtime_debug . schedtrace * 1000000ll < = now ) {
lasttrace = now ;
runtime_schedtrace ( runtime_debug . scheddetail ) ;
}
2013-07-16 06:54:42 +00:00
}
}
2013-11-06 19:49:01 +00:00
typedef struct Pdesc Pdesc ;
struct Pdesc
{
uint32 schedtick ;
int64 schedwhen ;
uint32 syscalltick ;
int64 syscallwhen ;
} ;
2016-08-30 21:07:47 +00:00
static Pdesc pdesc [ _MaxGomaxprocs ] ;
2013-11-06 19:49:01 +00:00
2013-07-16 06:54:42 +00:00
static uint32
2013-11-06 19:49:01 +00:00
retake ( int64 now )
2013-07-16 06:54:42 +00:00
{
uint32 i , s , n ;
int64 t ;
P * p ;
2013-11-06 19:49:01 +00:00
Pdesc * pd ;
2013-07-16 06:54:42 +00:00
n = 0 ;
for ( i = 0 ; i < ( uint32 ) runtime_gomaxprocs ; i + + ) {
p = runtime_allp [ i ] ;
if ( p = = nil )
continue ;
2013-11-06 19:49:01 +00:00
pd = & pdesc [ i ] ;
2013-07-16 06:54:42 +00:00
s = p - > status ;
2016-08-30 21:07:47 +00:00
if ( s = = _Psyscall ) {
2014-06-06 22:37:27 +00:00
// Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
2013-11-06 19:49:01 +00:00
t = p - > syscalltick ;
if ( pd - > syscalltick ! = t ) {
pd - > syscalltick = t ;
pd - > syscallwhen = now ;
continue ;
}
2014-06-06 22:37:27 +00:00
// On the one hand we don't want to retake Ps if there is no other work to do,
// but on the other hand we want to retake them eventually
// because they can prevent the sysmon thread from deep sleep.
2013-11-06 19:49:01 +00:00
if ( p - > runqhead = = p - > runqtail & &
2016-11-18 17:48:29 +00:00
runtime_atomicload ( & runtime_sched - > nmspinning ) + runtime_atomicload ( & runtime_sched - > npidle ) > 0 & &
2014-06-06 22:37:27 +00:00
pd - > syscallwhen + 10 * 1000 * 1000 > now )
2013-11-06 19:49:01 +00:00
continue ;
// Need to decrement number of idle locked M's
// (pretending that one more is running) before the CAS.
// Otherwise the M from which we retake can exit the syscall,
// increment nmidle and report deadlock.
incidlelocked ( - 1 ) ;
2016-08-30 21:07:47 +00:00
if ( runtime_cas ( & p - > status , s , _Pidle ) ) {
2013-11-06 19:49:01 +00:00
n + + ;
handoffp ( p ) ;
}
incidlelocked ( 1 ) ;
2016-08-30 21:07:47 +00:00
} else if ( s = = _Prunning ) {
2013-11-06 19:49:01 +00:00
// Preempt G if it's running for more than 10ms.
t = p - > schedtick ;
if ( pd - > schedtick ! = t ) {
pd - > schedtick = t ;
pd - > schedwhen = now ;
continue ;
}
if ( pd - > schedwhen + 10 * 1000 * 1000 > now )
continue ;
// preemptone(p);
2013-07-16 06:54:42 +00:00
}
}
return n ;
}
2013-11-06 19:49:01 +00:00
// Tell all goroutines that they have been preempted and they should stop.
// This function is purely best-effort. It can fail to inform a goroutine if a
// processor just started running it.
// No locks need to be held.
// Returns true if preemption request was issued to at least one goroutine.
static bool
preemptall ( void )
{
return false ;
}
void
runtime_schedtrace ( bool detailed )
{
static int64 starttime ;
int64 now ;
int64 id1 , id2 , id3 ;
2014-06-06 22:37:27 +00:00
int32 i , t , h ;
uintptr gi ;
2013-11-06 19:49:01 +00:00
const char * fmt ;
M * mp , * lockedm ;
G * gp , * lockedg ;
P * p ;
now = runtime_nanotime ( ) ;
if ( starttime = = 0 )
starttime = now ;
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
runtime_printf ( " SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d idlethreads=%d runqueue=%d " ,
2016-11-18 17:48:29 +00:00
( now - starttime ) / 1000000 , runtime_gomaxprocs , runtime_sched - > npidle , runtime_sched - > mcount ,
runtime_sched - > nmidle , runtime_sched - > runqsize ) ;
2013-11-06 19:49:01 +00:00
if ( detailed ) {
runtime_printf ( " gcwaiting=%d nmidlelocked=%d nmspinning=%d stopwait=%d sysmonwait=%d \n " ,
2016-11-18 17:48:29 +00:00
runtime_sched - > gcwaiting , runtime_sched - > nmidlelocked , runtime_sched - > nmspinning ,
runtime_sched - > stopwait , runtime_sched - > sysmonwait ) ;
2013-11-06 19:49:01 +00:00
}
// We must be careful while reading data from P's, M's and G's.
// Even if we hold schedlock, most data can be changed concurrently.
// E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
for ( i = 0 ; i < runtime_gomaxprocs ; i + + ) {
p = runtime_allp [ i ] ;
if ( p = = nil )
continue ;
2016-08-30 21:07:47 +00:00
mp = ( M * ) p - > m ;
2014-06-06 22:37:27 +00:00
h = runtime_atomicload ( & p - > runqhead ) ;
t = runtime_atomicload ( & p - > runqtail ) ;
2013-11-06 19:49:01 +00:00
if ( detailed )
2014-06-06 22:37:27 +00:00
runtime_printf ( " P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d \n " ,
i , p - > status , p - > schedtick , p - > syscalltick , mp ? mp - > id : - 1 , t - h , p - > gfreecnt ) ;
2013-11-06 19:49:01 +00:00
else {
// In non-detailed mode format lengths of per-P run queues as:
// [len1 len2 len3 len4]
fmt = " %d " ;
if ( runtime_gomaxprocs = = 1 )
fmt = " [%d] \n " ;
else if ( i = = 0 )
fmt = " [%d " ;
else if ( i = = runtime_gomaxprocs - 1 )
fmt = " %d] \n " ;
2014-06-06 22:37:27 +00:00
runtime_printf ( fmt , t - h ) ;
2013-11-06 19:49:01 +00:00
}
}
if ( ! detailed ) {
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
return ;
}
for ( mp = runtime_allm ; mp ; mp = mp - > alllink ) {
2016-08-30 21:07:47 +00:00
p = ( P * ) mp - > p ;
2013-11-06 19:49:01 +00:00
gp = mp - > curg ;
lockedg = mp - > lockedg ;
id1 = - 1 ;
if ( p )
id1 = p - > id ;
id2 = - 1 ;
if ( gp )
id2 = gp - > goid ;
id3 = - 1 ;
if ( lockedg )
id3 = lockedg - > goid ;
runtime_printf ( " M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d "
2014-06-06 22:37:27 +00:00
" locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D \n " ,
2013-11-06 19:49:01 +00:00
mp - > id , id1 , id2 ,
mp - > mallocing , mp - > throwing , mp - > gcing , mp - > locks , mp - > dying , mp - > helpgc ,
2016-08-30 21:07:47 +00:00
mp - > spinning , mp - > blocked , id3 ) ;
2013-11-06 19:49:01 +00:00
}
2014-06-06 22:37:27 +00:00
runtime_lock ( & allglock ) ;
for ( gi = 0 ; gi < runtime_allglen ; gi + + ) {
gp = runtime_allg [ gi ] ;
2013-11-06 19:49:01 +00:00
mp = gp - > m ;
lockedm = gp - > lockedm ;
2016-08-30 21:07:47 +00:00
runtime_printf ( " G%D: status=%d(%S) m=%d lockedm=%d \n " ,
gp - > goid , gp - > atomicstatus , gp - > waitreason , mp ? mp - > id : - 1 ,
2013-11-06 19:49:01 +00:00
lockedm ? lockedm - > id : - 1 ) ;
}
2014-06-06 22:37:27 +00:00
runtime_unlock ( & allglock ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
}
2013-07-16 06:54:42 +00:00
// Put mp on midle list.
// Sched must be locked.
static void
mput ( M * mp )
{
2016-11-18 17:48:29 +00:00
mp - > schedlink = runtime_sched - > midle ;
runtime_sched - > midle = ( uintptr ) mp ;
runtime_sched - > nmidle + + ;
2013-07-16 06:54:42 +00:00
checkdead ( ) ;
}
// Try to get an m from midle list.
// Sched must be locked.
static M *
mget ( void )
{
M * mp ;
2016-11-18 17:48:29 +00:00
if ( ( mp = ( M * ) runtime_sched - > midle ) ! = nil ) {
runtime_sched - > midle = mp - > schedlink ;
runtime_sched - > nmidle - - ;
2013-07-16 06:54:42 +00:00
}
return mp ;
}
// Put gp on the global runnable queue.
// Sched must be locked.
static void
globrunqput ( G * gp )
{
2016-08-30 21:07:47 +00:00
gp - > schedlink = 0 ;
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqtail )
( ( G * ) runtime_sched - > runqtail ) - > schedlink = ( uintptr ) gp ;
2013-07-16 06:54:42 +00:00
else
2016-11-18 17:48:29 +00:00
runtime_sched - > runqhead = ( uintptr ) gp ;
runtime_sched - > runqtail = ( uintptr ) gp ;
runtime_sched - > runqsize + + ;
2013-07-16 06:54:42 +00:00
}
2014-06-06 22:37:27 +00:00
// Put a batch of runnable goroutines on the global runnable queue.
// Sched must be locked.
static void
globrunqputbatch ( G * ghead , G * gtail , int32 n )
{
2016-08-30 21:07:47 +00:00
gtail - > schedlink = 0 ;
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqtail )
( ( G * ) runtime_sched - > runqtail ) - > schedlink = ( uintptr ) ghead ;
2014-06-06 22:37:27 +00:00
else
2016-11-18 17:48:29 +00:00
runtime_sched - > runqhead = ( uintptr ) ghead ;
runtime_sched - > runqtail = ( uintptr ) gtail ;
runtime_sched - > runqsize + = n ;
2014-06-06 22:37:27 +00:00
}
2013-07-16 06:54:42 +00:00
// Try get a batch of G's from the global runnable queue.
// Sched must be locked.
static G *
2013-11-06 19:49:01 +00:00
globrunqget ( P * p , int32 max )
2013-07-16 06:54:42 +00:00
{
G * gp , * gp1 ;
int32 n ;
2016-11-18 17:48:29 +00:00
if ( runtime_sched - > runqsize = = 0 )
2013-07-16 06:54:42 +00:00
return nil ;
2016-11-18 17:48:29 +00:00
n = runtime_sched - > runqsize / runtime_gomaxprocs + 1 ;
if ( n > runtime_sched - > runqsize )
n = runtime_sched - > runqsize ;
2013-11-06 19:49:01 +00:00
if ( max > 0 & & n > max )
n = max ;
2014-06-06 22:37:27 +00:00
if ( ( uint32 ) n > nelem ( p - > runq ) / 2 )
n = nelem ( p - > runq ) / 2 ;
2016-11-18 17:48:29 +00:00
runtime_sched - > runqsize - = n ;
if ( runtime_sched - > runqsize = = 0 )
runtime_sched - > runqtail = 0 ;
gp = ( G * ) runtime_sched - > runqhead ;
runtime_sched - > runqhead = gp - > schedlink ;
2013-07-16 06:54:42 +00:00
n - - ;
while ( n - - ) {
2016-11-18 17:48:29 +00:00
gp1 = ( G * ) runtime_sched - > runqhead ;
runtime_sched - > runqhead = gp1 - > schedlink ;
2013-07-16 06:54:42 +00:00
runqput ( p , gp1 ) ;
}
return gp ;
}
// Put p to on pidle list.
// Sched must be locked.
static void
pidleput ( P * p )
{
2016-11-18 17:48:29 +00:00
p - > link = runtime_sched - > pidle ;
runtime_sched - > pidle = ( uintptr ) p ;
runtime_xadd ( & runtime_sched - > npidle , 1 ) ; // TODO: fast atomic
2013-07-16 06:54:42 +00:00
}
// Try get a p from pidle list.
// Sched must be locked.
static P *
pidleget ( void )
{
P * p ;
2016-11-18 17:48:29 +00:00
p = ( P * ) runtime_sched - > pidle ;
2013-07-16 06:54:42 +00:00
if ( p ) {
2016-11-18 17:48:29 +00:00
runtime_sched - > pidle = p - > link ;
runtime_xadd ( & runtime_sched - > npidle , - 1 ) ; // TODO: fast atomic
2013-07-16 06:54:42 +00:00
}
return p ;
}
2014-06-06 22:37:27 +00:00
// Try to put g on local runnable queue.
// If it's full, put onto global queue.
// Executed only by the owner P.
2013-07-16 06:54:42 +00:00
static void
runqput ( P * p , G * gp )
{
2014-06-06 22:37:27 +00:00
uint32 h , t ;
2013-07-16 06:54:42 +00:00
retry :
2014-06-06 22:37:27 +00:00
h = runtime_atomicload ( & p - > runqhead ) ; // load-acquire, synchronize with consumers
2013-07-16 06:54:42 +00:00
t = p - > runqtail ;
2014-06-06 22:37:27 +00:00
if ( t - h < nelem ( p - > runq ) ) {
2016-08-30 21:07:47 +00:00
p - > runq [ t % nelem ( p - > runq ) ] = ( uintptr ) gp ;
2014-06-06 22:37:27 +00:00
runtime_atomicstore ( & p - > runqtail , t + 1 ) ; // store-release, makes the item available for consumption
return ;
2013-07-16 06:54:42 +00:00
}
2014-06-06 22:37:27 +00:00
if ( runqputslow ( p , gp , h , t ) )
return ;
// the queue is not full, now the put above must suceed
goto retry ;
}
// Put g and a batch of work from local runnable queue on global queue.
// Executed only by the owner P.
static bool
runqputslow ( P * p , G * gp , uint32 h , uint32 t )
{
G * batch [ nelem ( p - > runq ) / 2 + 1 ] ;
uint32 n , i ;
// First, grab a batch from local queue.
n = t - h ;
n = n / 2 ;
if ( n ! = nelem ( p - > runq ) / 2 )
runtime_throw ( " runqputslow: queue is not full " ) ;
for ( i = 0 ; i < n ; i + + )
2016-08-30 21:07:47 +00:00
batch [ i ] = ( G * ) p - > runq [ ( h + i ) % nelem ( p - > runq ) ] ;
2014-06-06 22:37:27 +00:00
if ( ! runtime_cas ( & p - > runqhead , h , h + n ) ) // cas-release, commits consume
return false ;
batch [ n ] = gp ;
// Link the goroutines.
for ( i = 0 ; i < n ; i + + )
2016-08-30 21:07:47 +00:00
batch [ i ] - > schedlink = ( uintptr ) batch [ i + 1 ] ;
2014-06-06 22:37:27 +00:00
// Now put the batch on global queue.
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
2014-06-06 22:37:27 +00:00
globrunqputbatch ( batch [ 0 ] , batch [ n ] , n + 1 ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2014-06-06 22:37:27 +00:00
return true ;
2013-07-16 06:54:42 +00:00
}
// Get g from local runnable queue.
2014-06-06 22:37:27 +00:00
// Executed only by the owner P.
2013-07-16 06:54:42 +00:00
static G *
runqget ( P * p )
{
G * gp ;
2014-06-06 22:37:27 +00:00
uint32 t , h ;
2013-07-16 06:54:42 +00:00
2014-06-06 22:37:27 +00:00
for ( ; ; ) {
h = runtime_atomicload ( & p - > runqhead ) ; // load-acquire, synchronize with other consumers
t = p - > runqtail ;
if ( t = = h )
return nil ;
2016-08-30 21:07:47 +00:00
gp = ( G * ) p - > runq [ h % nelem ( p - > runq ) ] ;
2014-06-06 22:37:27 +00:00
if ( runtime_cas ( & p - > runqhead , h , h + 1 ) ) // cas-release, commits consume
return gp ;
2013-07-16 06:54:42 +00:00
}
}
2014-06-06 22:37:27 +00:00
// Grabs a batch of goroutines from local runnable queue.
// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
// Can be executed by any P.
static uint32
runqgrab ( P * p , G * * batch )
2013-07-16 06:54:42 +00:00
{
2014-06-06 22:37:27 +00:00
uint32 t , h , n , i ;
2013-07-16 06:54:42 +00:00
2014-06-06 22:37:27 +00:00
for ( ; ; ) {
h = runtime_atomicload ( & p - > runqhead ) ; // load-acquire, synchronize with other consumers
t = runtime_atomicload ( & p - > runqtail ) ; // load-acquire, synchronize with the producer
n = t - h ;
n = n - n / 2 ;
if ( n = = 0 )
break ;
if ( n > nelem ( p - > runq ) / 2 ) // read inconsistent h and t
continue ;
for ( i = 0 ; i < n ; i + + )
2016-08-30 21:07:47 +00:00
batch [ i ] = ( G * ) p - > runq [ ( h + i ) % nelem ( p - > runq ) ] ;
2014-06-06 22:37:27 +00:00
if ( runtime_cas ( & p - > runqhead , h , h + n ) ) // cas-release, commits consume
break ;
2013-07-16 06:54:42 +00:00
}
2014-06-06 22:37:27 +00:00
return n ;
2013-07-16 06:54:42 +00:00
}
// Steal half of elements from local runnable queue of p2
// and put onto local runnable queue of p.
// Returns one of the stolen elements (or nil if failed).
static G *
runqsteal ( P * p , P * p2 )
{
2014-06-06 22:37:27 +00:00
G * gp ;
G * batch [ nelem ( p - > runq ) / 2 ] ;
uint32 t , h , n , i ;
2013-07-16 06:54:42 +00:00
2014-06-06 22:37:27 +00:00
n = runqgrab ( p2 , batch ) ;
if ( n = = 0 )
2013-07-16 06:54:42 +00:00
return nil ;
2014-06-06 22:37:27 +00:00
n - - ;
gp = batch [ n ] ;
if ( n = = 0 )
return gp ;
h = runtime_atomicload ( & p - > runqhead ) ; // load-acquire, synchronize with consumers
2013-07-16 06:54:42 +00:00
t = p - > runqtail ;
2014-06-06 22:37:27 +00:00
if ( t - h + n > = nelem ( p - > runq ) )
runtime_throw ( " runqsteal: runq overflow " ) ;
for ( i = 0 ; i < n ; i + + , t + + )
2016-08-30 21:07:47 +00:00
p - > runq [ t % nelem ( p - > runq ) ] = ( uintptr ) batch [ i ] ;
2014-06-06 22:37:27 +00:00
runtime_atomicstore ( & p - > runqtail , t ) ; // store-release, makes the item available for consumption
2013-07-16 06:54:42 +00:00
return gp ;
}
void runtime_testSchedLocalQueue ( void )
__asm__ ( " runtime.testSchedLocalQueue " ) ;
void
runtime_testSchedLocalQueue ( void )
{
P p ;
2014-06-06 22:37:27 +00:00
G gs [ nelem ( p . runq ) ] ;
2013-07-16 06:54:42 +00:00
int32 i , j ;
runtime_memclr ( ( byte * ) & p , sizeof ( p ) ) ;
for ( i = 0 ; i < ( int32 ) nelem ( gs ) ; i + + ) {
if ( runqget ( & p ) ! = nil )
runtime_throw ( " runq is not empty initially " ) ;
for ( j = 0 ; j < i ; j + + )
runqput ( & p , & gs [ i ] ) ;
for ( j = 0 ; j < i ; j + + ) {
if ( runqget ( & p ) ! = & gs [ i ] ) {
runtime_printf ( " bad element at iter %d/%d \n " , i , j ) ;
runtime_throw ( " bad element " ) ;
}
}
if ( runqget ( & p ) ! = nil )
runtime_throw ( " runq is not empty afterwards " ) ;
}
}
void runtime_testSchedLocalQueueSteal ( void )
__asm__ ( " runtime.testSchedLocalQueueSteal " ) ;
void
runtime_testSchedLocalQueueSteal ( void )
{
P p1 , p2 ;
2014-06-06 22:37:27 +00:00
G gs [ nelem ( p1 . runq ) ] , * gp ;
2013-07-16 06:54:42 +00:00
int32 i , j , s ;
runtime_memclr ( ( byte * ) & p1 , sizeof ( p1 ) ) ;
runtime_memclr ( ( byte * ) & p2 , sizeof ( p2 ) ) ;
for ( i = 0 ; i < ( int32 ) nelem ( gs ) ; i + + ) {
for ( j = 0 ; j < i ; j + + ) {
gs [ j ] . sig = 0 ;
runqput ( & p1 , & gs [ j ] ) ;
}
gp = runqsteal ( & p2 , & p1 ) ;
s = 0 ;
if ( gp ) {
s + + ;
gp - > sig + + ;
}
while ( ( gp = runqget ( & p2 ) ) ! = nil ) {
s + + ;
gp - > sig + + ;
}
while ( ( gp = runqget ( & p1 ) ) ! = nil )
gp - > sig + + ;
for ( j = 0 ; j < i ; j + + ) {
if ( gs [ j ] . sig ! = 1 ) {
runtime_printf ( " bad element %d(%d) at iter %d \n " , j , gs [ j ] . sig , i ) ;
runtime_throw ( " bad element " ) ;
}
}
if ( s ! = i / 2 & & s ! = i / 2 + 1 ) {
runtime_printf ( " bad steal %d, want %d or %d, iter %d \n " ,
s , i / 2 , i / 2 + 1 , i ) ;
runtime_throw ( " bad steal " ) ;
}
}
}
2016-10-17 16:54:25 +00:00
intgo
runtime_setmaxthreads ( intgo in )
2013-11-06 19:49:01 +00:00
{
2016-10-17 16:54:25 +00:00
intgo out ;
2013-11-06 19:49:01 +00:00
2016-11-18 17:48:29 +00:00
runtime_lock ( & runtime_sched - > lock ) ;
out = ( intgo ) runtime_sched - > maxmcount ;
runtime_sched - > maxmcount = ( int32 ) in ;
2013-11-06 19:49:01 +00:00
checkmcount ( ) ;
2016-11-18 17:48:29 +00:00
runtime_unlock ( & runtime_sched - > lock ) ;
2013-11-06 19:49:01 +00:00
return out ;
}
2016-11-16 18:33:11 +00:00
static intgo
procPin ( )
{
M * mp ;
mp = runtime_m ( ) ;
mp - > locks + + ;
return ( intgo ) ( ( ( P * ) mp - > p ) - > id ) ;
}
static void
procUnpin ( )
{
runtime_m ( ) - > locks - - ;
}
intgo sync_runtime_procPin ( void )
__asm__ ( GOSYM_PREFIX " sync.runtime_procPin " ) ;
intgo
sync_runtime_procPin ( )
{
return procPin ( ) ;
}
void sync_runtime_procUnpin ( void )
__asm__ ( GOSYM_PREFIX " sync.runtime_procUnpin " ) ;
void
sync_runtime_procUnpin ( )
{
procUnpin ( ) ;
}
intgo sync_atomic_runtime_procPin ( void )
__asm__ ( GOSYM_PREFIX " sync_atomic.runtime_procPin " ) ;
intgo
sync_atomic_runtime_procPin ( )
{
return procPin ( ) ;
}
void sync_atomic_runtime_procUnpin ( void )
__asm__ ( GOSYM_PREFIX " sync_atomic.runtime_procUnpin " ) ;
void
sync_atomic_runtime_procUnpin ( )
{
procUnpin ( ) ;
}
2013-07-16 06:54:42 +00:00
void
2014-06-06 22:37:27 +00:00
runtime_proc_scan ( struct Workbuf * * wbufp , void ( * enqueue1 ) ( struct Workbuf * * , Obj ) )
2013-07-16 06:54:42 +00:00
{
2015-04-29 21:31:53 +00:00
enqueue1 ( wbufp , ( Obj ) { ( byte * ) & runtime_main_init_done , sizeof runtime_main_init_done , 0 } ) ;
2013-07-16 06:54:42 +00:00
}
2013-09-03 21:52:37 +00:00
2013-11-06 19:49:01 +00:00
// Return whether we are waiting for a GC. This gc toolchain uses
// preemption instead.
bool
runtime_gcwaiting ( void )
{
2016-11-18 17:48:29 +00:00
return runtime_sched - > gcwaiting ;
2013-11-06 19:49:01 +00:00
}
2015-10-31 00:59:47 +00:00
// os_beforeExit is called from os.Exit(0).
//go:linkname os_beforeExit os.runtime_beforeExit
extern void os_beforeExit ( ) __asm__ ( GOSYM_PREFIX " os.runtime_beforeExit " ) ;
void
os_beforeExit ( )
{
}
// Active spinning for sync.Mutex.
//go:linkname sync_runtime_canSpin sync.runtime_canSpin
enum
{
ACTIVE_SPIN = 4 ,
ACTIVE_SPIN_CNT = 30 ,
} ;
extern _Bool sync_runtime_canSpin ( intgo i )
__asm__ ( GOSYM_PREFIX " sync.runtime_canSpin " ) ;
_Bool
sync_runtime_canSpin ( intgo i )
{
P * p ;
// sync.Mutex is cooperative, so we are conservative with spinning.
// Spin only few times and only if running on a multicore machine and
// GOMAXPROCS>1 and there is at least one other running P and local runq is empty.
// As opposed to runtime mutex we don't do passive spinning here,
// because there can be work on global runq on on other Ps.
2016-11-18 17:48:29 +00:00
if ( i > = ACTIVE_SPIN | | runtime_ncpu < = 1 | | runtime_gomaxprocs < = ( int32 ) ( runtime_sched - > npidle + runtime_sched - > nmspinning ) + 1 ) {
2015-10-31 00:59:47 +00:00
return false ;
}
2016-08-30 21:07:47 +00:00
p = ( P * ) g - > m - > p ;
2015-10-31 00:59:47 +00:00
return p ! = nil & & p - > runqhead = = p - > runqtail ;
}
//go:linkname sync_runtime_doSpin sync.runtime_doSpin
//go:nosplit
extern void sync_runtime_doSpin ( void )
__asm__ ( GOSYM_PREFIX " sync.runtime_doSpin " ) ;
void
sync_runtime_doSpin ( )
{
runtime_procyield ( ACTIVE_SPIN_CNT ) ;
}
2016-10-14 22:51:46 +00:00
// For Go code to look at variables, until we port proc.go.
extern M * * runtime_go_allm ( void )
__asm__ ( GOSYM_PREFIX " runtime.allm " ) ;
M * *
runtime_go_allm ( )
{
return & runtime_allm ;
}
extern Slice runtime_go_allgs ( void )
__asm__ ( GOSYM_PREFIX " runtime.allgs " ) ;
Slice
runtime_go_allgs ( )
{
Slice s ;
s . __values = runtime_allg ;
s . __count = runtime_allglen ;
s . __capacity = allgcap ;
return s ;
}
2016-11-16 18:33:11 +00:00
intgo NumCPU ( void ) __asm__ ( GOSYM_PREFIX " runtime.NumCPU " ) ;
intgo
NumCPU ( )
{
return ( intgo ) ( runtime_ncpu ) ;
}