mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			247 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2014 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.
 | 
						|
 | 
						|
package runtime
 | 
						|
 | 
						|
import "unsafe"
 | 
						|
 | 
						|
func newsysmon()
 | 
						|
 | 
						|
func runtime_init()
 | 
						|
func main_init()
 | 
						|
func main_main()
 | 
						|
 | 
						|
// The main goroutine.
 | 
						|
func main() {
 | 
						|
	g := getg()
 | 
						|
 | 
						|
	// Racectx of m0->g0 is used only as the parent of the main goroutine.
 | 
						|
	// It must not be used for anything else.
 | 
						|
	g.m.g0.racectx = 0
 | 
						|
 | 
						|
	// Max stack size is 1 GB on 64-bit, 250 MB on 32-bit.
 | 
						|
	// Using decimal instead of binary GB and MB because
 | 
						|
	// they look nicer in the stack overflow failure message.
 | 
						|
	if ptrSize == 8 {
 | 
						|
		maxstacksize = 1000000000
 | 
						|
	} else {
 | 
						|
		maxstacksize = 250000000
 | 
						|
	}
 | 
						|
 | 
						|
	onM(newsysmon)
 | 
						|
 | 
						|
	// 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.
 | 
						|
	lockOSThread()
 | 
						|
 | 
						|
	if g.m != &m0 {
 | 
						|
		gothrow("runtime.main not on m0")
 | 
						|
	}
 | 
						|
 | 
						|
	runtime_init() // must be before defer
 | 
						|
 | 
						|
	// Defer unlock so that runtime.Goexit during init does the unlock too.
 | 
						|
	needUnlock := true
 | 
						|
	defer func() {
 | 
						|
		if needUnlock {
 | 
						|
			unlockOSThread()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	memstats.enablegc = true // now that runtime is initialized, GC is okay
 | 
						|
 | 
						|
	main_init()
 | 
						|
 | 
						|
	needUnlock = false
 | 
						|
	unlockOSThread()
 | 
						|
 | 
						|
	main_main()
 | 
						|
	if raceenabled {
 | 
						|
		racefini()
 | 
						|
	}
 | 
						|
 | 
						|
	// 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 panicking != 0 {
 | 
						|
		gopark(nil, nil, "panicwait")
 | 
						|
	}
 | 
						|
 | 
						|
	exit(0)
 | 
						|
	for {
 | 
						|
		var x *int32
 | 
						|
		*x = 0
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
var parkunlock_c byte
 | 
						|
 | 
						|
// start forcegc helper goroutine
 | 
						|
func init() {
 | 
						|
	go forcegchelper()
 | 
						|
}
 | 
						|
 | 
						|
func forcegchelper() {
 | 
						|
	forcegc.g = getg()
 | 
						|
	forcegc.g.issystem = true
 | 
						|
	for {
 | 
						|
		lock(&forcegc.lock)
 | 
						|
		if forcegc.idle != 0 {
 | 
						|
			gothrow("forcegc: phase error")
 | 
						|
		}
 | 
						|
		atomicstore(&forcegc.idle, 1)
 | 
						|
		goparkunlock(&forcegc.lock, "force gc (idle)")
 | 
						|
		// this goroutine is explicitly resumed by sysmon
 | 
						|
		if debug.gctrace > 0 {
 | 
						|
			println("GC forced")
 | 
						|
		}
 | 
						|
		gogc(1)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//go:nosplit
 | 
						|
 | 
						|
// Gosched yields the processor, allowing other goroutines to run.  It does not
 | 
						|
// suspend the current goroutine, so execution resumes automatically.
 | 
						|
func Gosched() {
 | 
						|
	mcall(gosched_m)
 | 
						|
}
 | 
						|
 | 
						|
// Puts the current goroutine into a waiting state and calls unlockf.
 | 
						|
// If unlockf returns false, the goroutine is resumed.
 | 
						|
func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
 | 
						|
	mp := acquirem()
 | 
						|
	gp := mp.curg
 | 
						|
	status := readgstatus(gp)
 | 
						|
	if status != _Grunning && status != _Gscanrunning {
 | 
						|
		gothrow("gopark: bad g status")
 | 
						|
	}
 | 
						|
	mp.waitlock = lock
 | 
						|
	mp.waitunlockf = unlockf
 | 
						|
	gp.waitreason = reason
 | 
						|
	releasem(mp)
 | 
						|
	// can't do anything that might move the G between Ms here.
 | 
						|
	mcall(park_m)
 | 
						|
}
 | 
						|
 | 
						|
// Puts the current goroutine into a waiting state and unlocks the lock.
 | 
						|
// The goroutine can be made runnable again by calling goready(gp).
 | 
						|
func goparkunlock(lock *mutex, reason string) {
 | 
						|
	gopark(unsafe.Pointer(&parkunlock_c), unsafe.Pointer(lock), reason)
 | 
						|
}
 | 
						|
 | 
						|
func goready(gp *g) {
 | 
						|
	mp := acquirem()
 | 
						|
	mp.ptrarg[0] = unsafe.Pointer(gp)
 | 
						|
	onM(ready_m)
 | 
						|
	releasem(mp)
 | 
						|
}
 | 
						|
 | 
						|
//go:nosplit
 | 
						|
func acquireSudog() *sudog {
 | 
						|
	c := gomcache()
 | 
						|
	s := c.sudogcache
 | 
						|
	if s != nil {
 | 
						|
		if s.elem != nil {
 | 
						|
			gothrow("acquireSudog: found s.elem != nil in cache")
 | 
						|
		}
 | 
						|
		c.sudogcache = s.next
 | 
						|
		s.next = nil
 | 
						|
		return s
 | 
						|
	}
 | 
						|
 | 
						|
	// Delicate dance: the semaphore implementation calls
 | 
						|
	// acquireSudog, acquireSudog calls new(sudog),
 | 
						|
	// new calls malloc, malloc can call the garbage collector,
 | 
						|
	// and the garbage collector calls the semaphore implementation
 | 
						|
	// in stoptheworld.
 | 
						|
	// Break the cycle by doing acquirem/releasem around new(sudog).
 | 
						|
	// The acquirem/releasem increments m.locks during new(sudog),
 | 
						|
	// which keeps the garbage collector from being invoked.
 | 
						|
	mp := acquirem()
 | 
						|
	p := new(sudog)
 | 
						|
	releasem(mp)
 | 
						|
	return p
 | 
						|
}
 | 
						|
 | 
						|
//go:nosplit
 | 
						|
func releaseSudog(s *sudog) {
 | 
						|
	if s.elem != nil {
 | 
						|
		gothrow("runtime: sudog with non-nil elem")
 | 
						|
	}
 | 
						|
	if s.selectdone != nil {
 | 
						|
		gothrow("runtime: sudog with non-nil selectdone")
 | 
						|
	}
 | 
						|
	if s.next != nil {
 | 
						|
		gothrow("runtime: sudog with non-nil next")
 | 
						|
	}
 | 
						|
	if s.prev != nil {
 | 
						|
		gothrow("runtime: sudog with non-nil prev")
 | 
						|
	}
 | 
						|
	if s.waitlink != nil {
 | 
						|
		gothrow("runtime: sudog with non-nil waitlink")
 | 
						|
	}
 | 
						|
	gp := getg()
 | 
						|
	if gp.param != nil {
 | 
						|
		gothrow("runtime: releaseSudog with non-nil gp.param")
 | 
						|
	}
 | 
						|
	c := gomcache()
 | 
						|
	s.next = c.sudogcache
 | 
						|
	c.sudogcache = s
 | 
						|
}
 | 
						|
 | 
						|
// funcPC returns the entry PC of the function f.
 | 
						|
// It assumes that f is a func value. Otherwise the behavior is undefined.
 | 
						|
//go:nosplit
 | 
						|
func funcPC(f interface{}) uintptr {
 | 
						|
	return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
 | 
						|
}
 | 
						|
 | 
						|
// called from assembly
 | 
						|
func badmcall(fn func(*g)) {
 | 
						|
	gothrow("runtime: mcall called on m->g0 stack")
 | 
						|
}
 | 
						|
 | 
						|
func badmcall2(fn func(*g)) {
 | 
						|
	gothrow("runtime: mcall function returned")
 | 
						|
}
 | 
						|
 | 
						|
func badreflectcall() {
 | 
						|
	panic("runtime: arg size to reflect.call more than 1GB")
 | 
						|
}
 | 
						|
 | 
						|
func lockedOSThread() bool {
 | 
						|
	gp := getg()
 | 
						|
	return gp.lockedm != nil && gp.m.lockedg != nil
 | 
						|
}
 | 
						|
 | 
						|
func newP() *p {
 | 
						|
	return new(p)
 | 
						|
}
 | 
						|
 | 
						|
func newM() *m {
 | 
						|
	return new(m)
 | 
						|
}
 | 
						|
 | 
						|
func newG() *g {
 | 
						|
	return new(g)
 | 
						|
}
 | 
						|
 | 
						|
func allgadd(gp *g) {
 | 
						|
	if readgstatus(gp) == _Gidle {
 | 
						|
		gothrow("allgadd: bad status Gidle")
 | 
						|
	}
 | 
						|
 | 
						|
	lock(&allglock)
 | 
						|
	allgs = append(allgs, gp)
 | 
						|
	allg = &allgs[0]
 | 
						|
	allglen = uintptr(len(allgs))
 | 
						|
	unlock(&allglock)
 | 
						|
}
 |