github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/runtime/proc.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import "unsafe"
     8  
     9  //go:linkname runtime_init runtime.init
    10  func runtime_init()
    11  
    12  //go:linkname main_init main.init
    13  func main_init()
    14  
    15  // main_init_done is a signal used by cgocallbackg that initialization
    16  // has been completed. It is made before _cgo_notify_runtime_init_done,
    17  // so all cgo calls can rely on it existing. When main_init is complete,
    18  // it is closed, meaning cgocallbackg can reliably receive from it.
    19  var main_init_done chan bool
    20  
    21  //go:linkname main_main main.main
    22  func main_main()
    23  
    24  // runtimeInitTime is the nanotime() at which the runtime started.
    25  var runtimeInitTime int64
    26  
    27  // The main goroutine.
    28  func main() {
    29  	g := getg()
    30  
    31  	// Racectx of m0->g0 is used only as the parent of the main goroutine.
    32  	// It must not be used for anything else.
    33  	g.m.g0.racectx = 0
    34  
    35  	// Max stack size is 1 GB on 64-bit, 250 MB on 32-bit.
    36  	// Using decimal instead of binary GB and MB because
    37  	// they look nicer in the stack overflow failure message.
    38  	if ptrSize == 8 {
    39  		maxstacksize = 1000000000
    40  	} else {
    41  		maxstacksize = 250000000
    42  	}
    43  
    44  	// Record when the world started.
    45  	runtimeInitTime = nanotime()
    46  
    47  	systemstack(func() {
    48  		newm(sysmon, nil)
    49  	})
    50  
    51  	// Lock the main goroutine onto this, the main OS thread,
    52  	// during initialization.  Most programs won't care, but a few
    53  	// do require certain calls to be made by the main thread.
    54  	// Those can arrange for main.main to run in the main thread
    55  	// by calling runtime.LockOSThread during initialization
    56  	// to preserve the lock.
    57  	lockOSThread()
    58  
    59  	if g.m != &m0 {
    60  		throw("runtime.main not on m0")
    61  	}
    62  
    63  	runtime_init() // must be before defer
    64  
    65  	// Defer unlock so that runtime.Goexit during init does the unlock too.
    66  	needUnlock := true
    67  	defer func() {
    68  		if needUnlock {
    69  			unlockOSThread()
    70  		}
    71  	}()
    72  
    73  	gcenable()
    74  
    75  	if islibrary {
    76  		// Allocate new M as main_main() is expected to block forever.
    77  		systemstack(newextram)
    78  	}
    79  	main_init_done = make(chan bool)
    80  	if iscgo {
    81  		if _cgo_thread_start == nil {
    82  			throw("_cgo_thread_start missing")
    83  		}
    84  		if _cgo_malloc == nil {
    85  			throw("_cgo_malloc missing")
    86  		}
    87  		if _cgo_free == nil {
    88  			throw("_cgo_free missing")
    89  		}
    90  		if GOOS != "windows" {
    91  			if _cgo_setenv == nil {
    92  				throw("_cgo_setenv missing")
    93  			}
    94  			if _cgo_unsetenv == nil {
    95  				throw("_cgo_unsetenv missing")
    96  			}
    97  		}
    98  		if _cgo_notify_runtime_init_done == nil {
    99  			throw("_cgo_notify_runtime_init_done missing")
   100  		}
   101  		cgocall(_cgo_notify_runtime_init_done, nil)
   102  	}
   103  
   104  	main_init()
   105  	close(main_init_done)
   106  
   107  	needUnlock = false
   108  	unlockOSThread()
   109  
   110  	if isarchive {
   111  		// A program compiled with -buildmode=c-archive has a main,
   112  		// but it is not executed.
   113  		return
   114  	}
   115  	main_main()
   116  	if raceenabled {
   117  		racefini()
   118  	}
   119  
   120  	// Make racy client program work: if panicking on
   121  	// another goroutine at the same time as main returns,
   122  	// let the other goroutine finish printing the panic trace.
   123  	// Once it does, it will exit. See issue 3934.
   124  	if panicking != 0 {
   125  		gopark(nil, nil, "panicwait", traceEvGoStop, 1)
   126  	}
   127  
   128  	exit(0)
   129  	for {
   130  		var x *int32
   131  		*x = 0
   132  	}
   133  }
   134  
   135  // os_beforeExit is called from os.Exit(0).
   136  //go:linkname os_beforeExit os.runtime_beforeExit
   137  func os_beforeExit() {
   138  	if raceenabled {
   139  		racefini()
   140  	}
   141  }
   142  
   143  // start forcegc helper goroutine
   144  func init() {
   145  	go forcegchelper()
   146  }
   147  
   148  func forcegchelper() {
   149  	forcegc.g = getg()
   150  	for {
   151  		lock(&forcegc.lock)
   152  		if forcegc.idle != 0 {
   153  			throw("forcegc: phase error")
   154  		}
   155  		atomicstore(&forcegc.idle, 1)
   156  		goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock, 1)
   157  		// this goroutine is explicitly resumed by sysmon
   158  		if debug.gctrace > 0 {
   159  			println("GC forced")
   160  		}
   161  		startGC(gcForceMode)
   162  	}
   163  }
   164  
   165  //go:nosplit
   166  
   167  // Gosched yields the processor, allowing other goroutines to run.  It does not
   168  // suspend the current goroutine, so execution resumes automatically.
   169  func Gosched() {
   170  	mcall(gosched_m)
   171  }
   172  
   173  // Puts the current goroutine into a waiting state and calls unlockf.
   174  // If unlockf returns false, the goroutine is resumed.
   175  func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte, traceskip int) {
   176  	mp := acquirem()
   177  	gp := mp.curg
   178  	status := readgstatus(gp)
   179  	if status != _Grunning && status != _Gscanrunning {
   180  		throw("gopark: bad g status")
   181  	}
   182  	mp.waitlock = lock
   183  	mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
   184  	gp.waitreason = reason
   185  	mp.waittraceev = traceEv
   186  	mp.waittraceskip = traceskip
   187  	releasem(mp)
   188  	// can't do anything that might move the G between Ms here.
   189  	mcall(park_m)
   190  }
   191  
   192  // Puts the current goroutine into a waiting state and unlocks the lock.
   193  // The goroutine can be made runnable again by calling goready(gp).
   194  func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
   195  	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)
   196  }
   197  
   198  func goready(gp *g, traceskip int) {
   199  	systemstack(func() {
   200  		ready(gp, traceskip)
   201  	})
   202  }
   203  
   204  //go:nosplit
   205  func acquireSudog() *sudog {
   206  	// Delicate dance: the semaphore implementation calls
   207  	// acquireSudog, acquireSudog calls new(sudog),
   208  	// new calls malloc, malloc can call the garbage collector,
   209  	// and the garbage collector calls the semaphore implementation
   210  	// in stoptheworld.
   211  	// Break the cycle by doing acquirem/releasem around new(sudog).
   212  	// The acquirem/releasem increments m.locks during new(sudog),
   213  	// which keeps the garbage collector from being invoked.
   214  	mp := acquirem()
   215  	pp := mp.p
   216  	if len(pp.sudogcache) == 0 {
   217  		lock(&sched.sudoglock)
   218  		// First, try to grab a batch from central cache.
   219  		for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
   220  			s := sched.sudogcache
   221  			sched.sudogcache = s.next
   222  			s.next = nil
   223  			pp.sudogcache = append(pp.sudogcache, s)
   224  		}
   225  		unlock(&sched.sudoglock)
   226  		// If the central cache is empty, allocate a new one.
   227  		if len(pp.sudogcache) == 0 {
   228  			pp.sudogcache = append(pp.sudogcache, new(sudog))
   229  		}
   230  	}
   231  	n := len(pp.sudogcache)
   232  	s := pp.sudogcache[n-1]
   233  	pp.sudogcache[n-1] = nil
   234  	pp.sudogcache = pp.sudogcache[:n-1]
   235  	if s.elem != nil {
   236  		throw("acquireSudog: found s.elem != nil in cache")
   237  	}
   238  	releasem(mp)
   239  	return s
   240  }
   241  
   242  //go:nosplit
   243  func releaseSudog(s *sudog) {
   244  	if s.elem != nil {
   245  		throw("runtime: sudog with non-nil elem")
   246  	}
   247  	if s.selectdone != nil {
   248  		throw("runtime: sudog with non-nil selectdone")
   249  	}
   250  	if s.next != nil {
   251  		throw("runtime: sudog with non-nil next")
   252  	}
   253  	if s.prev != nil {
   254  		throw("runtime: sudog with non-nil prev")
   255  	}
   256  	if s.waitlink != nil {
   257  		throw("runtime: sudog with non-nil waitlink")
   258  	}
   259  	gp := getg()
   260  	if gp.param != nil {
   261  		throw("runtime: releaseSudog with non-nil gp.param")
   262  	}
   263  	mp := acquirem() // avoid rescheduling to another P
   264  	pp := mp.p
   265  	if len(pp.sudogcache) == cap(pp.sudogcache) {
   266  		// Transfer half of local cache to the central cache.
   267  		var first, last *sudog
   268  		for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
   269  			n := len(pp.sudogcache)
   270  			p := pp.sudogcache[n-1]
   271  			pp.sudogcache[n-1] = nil
   272  			pp.sudogcache = pp.sudogcache[:n-1]
   273  			if first == nil {
   274  				first = p
   275  			} else {
   276  				last.next = p
   277  			}
   278  			last = p
   279  		}
   280  		lock(&sched.sudoglock)
   281  		last.next = sched.sudogcache
   282  		sched.sudogcache = first
   283  		unlock(&sched.sudoglock)
   284  	}
   285  	pp.sudogcache = append(pp.sudogcache, s)
   286  	releasem(mp)
   287  }
   288  
   289  // funcPC returns the entry PC of the function f.
   290  // It assumes that f is a func value. Otherwise the behavior is undefined.
   291  //go:nosplit
   292  func funcPC(f interface{}) uintptr {
   293  	return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
   294  }
   295  
   296  // called from assembly
   297  func badmcall(fn func(*g)) {
   298  	throw("runtime: mcall called on m->g0 stack")
   299  }
   300  
   301  func badmcall2(fn func(*g)) {
   302  	throw("runtime: mcall function returned")
   303  }
   304  
   305  func badreflectcall() {
   306  	panic("runtime: arg size to reflect.call more than 1GB")
   307  }
   308  
   309  func lockedOSThread() bool {
   310  	gp := getg()
   311  	return gp.lockedm != nil && gp.m.lockedg != nil
   312  }
   313  
   314  var (
   315  	allgs    []*g
   316  	allglock mutex
   317  )
   318  
   319  func allgadd(gp *g) {
   320  	if readgstatus(gp) == _Gidle {
   321  		throw("allgadd: bad status Gidle")
   322  	}
   323  
   324  	lock(&allglock)
   325  	allgs = append(allgs, gp)
   326  	allg = &allgs[0]
   327  	allglen = uintptr(len(allgs))
   328  	unlock(&allglock)
   329  }