github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/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  //go:linkname main_main main.main
    16  func main_main()
    17  
    18  // The main goroutine.
    19  func main() {
    20  	g := getg()
    21  
    22  	// Racectx of m0->g0 is used only as the parent of the main goroutine.
    23  	// It must not be used for anything else.
    24  	g.m.g0.racectx = 0
    25  
    26  	// Max stack size is 1 GB on 64-bit, 250 MB on 32-bit.
    27  	// Using decimal instead of binary GB and MB because
    28  	// they look nicer in the stack overflow failure message.
    29  	if ptrSize == 8 {
    30  		maxstacksize = 1000000000
    31  	} else {
    32  		maxstacksize = 250000000
    33  	}
    34  
    35  	systemstack(newsysmon)
    36  
    37  	// Lock the main goroutine onto this, the main OS thread,
    38  	// during initialization.  Most programs won't care, but a few
    39  	// do require certain calls to be made by the main thread.
    40  	// Those can arrange for main.main to run in the main thread
    41  	// by calling runtime.LockOSThread during initialization
    42  	// to preserve the lock.
    43  	lockOSThread()
    44  
    45  	if g.m != &m0 {
    46  		throw("runtime.main not on m0")
    47  	}
    48  
    49  	runtime_init() // must be before defer
    50  
    51  	// Defer unlock so that runtime.Goexit during init does the unlock too.
    52  	needUnlock := true
    53  	defer func() {
    54  		if needUnlock {
    55  			unlockOSThread()
    56  		}
    57  	}()
    58  
    59  	memstats.enablegc = true // now that runtime is initialized, GC is okay
    60  
    61  	if iscgo {
    62  		if _cgo_thread_start == nil {
    63  			throw("_cgo_thread_start missing")
    64  		}
    65  		if _cgo_malloc == nil {
    66  			throw("_cgo_malloc missing")
    67  		}
    68  		if _cgo_free == nil {
    69  			throw("_cgo_free missing")
    70  		}
    71  		if GOOS != "windows" {
    72  			if _cgo_setenv == nil {
    73  				throw("_cgo_setenv missing")
    74  			}
    75  			if _cgo_unsetenv == nil {
    76  				throw("_cgo_unsetenv missing")
    77  			}
    78  		}
    79  	}
    80  
    81  	main_init()
    82  
    83  	needUnlock = false
    84  	unlockOSThread()
    85  
    86  	main_main()
    87  	if raceenabled {
    88  		racefini()
    89  	}
    90  
    91  	// Make racy client program work: if panicking on
    92  	// another goroutine at the same time as main returns,
    93  	// let the other goroutine finish printing the panic trace.
    94  	// Once it does, it will exit. See issue 3934.
    95  	if panicking != 0 {
    96  		gopark(nil, nil, "panicwait")
    97  	}
    98  
    99  	exit(0)
   100  	for {
   101  		var x *int32
   102  		*x = 0
   103  	}
   104  }
   105  
   106  // start forcegc helper goroutine
   107  func init() {
   108  	go forcegchelper()
   109  }
   110  
   111  func forcegchelper() {
   112  	forcegc.g = getg()
   113  	forcegc.g.issystem = true
   114  	for {
   115  		lock(&forcegc.lock)
   116  		if forcegc.idle != 0 {
   117  			throw("forcegc: phase error")
   118  		}
   119  		atomicstore(&forcegc.idle, 1)
   120  		goparkunlock(&forcegc.lock, "force gc (idle)")
   121  		// this goroutine is explicitly resumed by sysmon
   122  		if debug.gctrace > 0 {
   123  			println("GC forced")
   124  		}
   125  		gogc(1)
   126  	}
   127  }
   128  
   129  //go:nosplit
   130  
   131  // Gosched yields the processor, allowing other goroutines to run.  It does not
   132  // suspend the current goroutine, so execution resumes automatically.
   133  func Gosched() {
   134  	mcall(gosched_m)
   135  }
   136  
   137  // Puts the current goroutine into a waiting state and calls unlockf.
   138  // If unlockf returns false, the goroutine is resumed.
   139  func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string) {
   140  	mp := acquirem()
   141  	gp := mp.curg
   142  	status := readgstatus(gp)
   143  	if status != _Grunning && status != _Gscanrunning {
   144  		throw("gopark: bad g status")
   145  	}
   146  	mp.waitlock = lock
   147  	mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
   148  	gp.waitreason = reason
   149  	releasem(mp)
   150  	// can't do anything that might move the G between Ms here.
   151  	mcall(park_m)
   152  }
   153  
   154  // Puts the current goroutine into a waiting state and unlocks the lock.
   155  // The goroutine can be made runnable again by calling goready(gp).
   156  func goparkunlock(lock *mutex, reason string) {
   157  	gopark(parkunlock_c, unsafe.Pointer(lock), reason)
   158  }
   159  
   160  func goready(gp *g) {
   161  	systemstack(func() {
   162  		ready(gp)
   163  	})
   164  }
   165  
   166  //go:nosplit
   167  func acquireSudog() *sudog {
   168  	c := gomcache()
   169  	s := c.sudogcache
   170  	if s != nil {
   171  		if s.elem != nil {
   172  			throw("acquireSudog: found s.elem != nil in cache")
   173  		}
   174  		c.sudogcache = s.next
   175  		s.next = nil
   176  		return s
   177  	}
   178  
   179  	// Delicate dance: the semaphore implementation calls
   180  	// acquireSudog, acquireSudog calls new(sudog),
   181  	// new calls malloc, malloc can call the garbage collector,
   182  	// and the garbage collector calls the semaphore implementation
   183  	// in stoptheworld.
   184  	// Break the cycle by doing acquirem/releasem around new(sudog).
   185  	// The acquirem/releasem increments m.locks during new(sudog),
   186  	// which keeps the garbage collector from being invoked.
   187  	mp := acquirem()
   188  	p := new(sudog)
   189  	if p.elem != nil {
   190  		throw("acquireSudog: found p.elem != nil after new")
   191  	}
   192  	releasem(mp)
   193  	return p
   194  }
   195  
   196  //go:nosplit
   197  func releaseSudog(s *sudog) {
   198  	if s.elem != nil {
   199  		throw("runtime: sudog with non-nil elem")
   200  	}
   201  	if s.selectdone != nil {
   202  		throw("runtime: sudog with non-nil selectdone")
   203  	}
   204  	if s.next != nil {
   205  		throw("runtime: sudog with non-nil next")
   206  	}
   207  	if s.prev != nil {
   208  		throw("runtime: sudog with non-nil prev")
   209  	}
   210  	if s.waitlink != nil {
   211  		throw("runtime: sudog with non-nil waitlink")
   212  	}
   213  	gp := getg()
   214  	if gp.param != nil {
   215  		throw("runtime: releaseSudog with non-nil gp.param")
   216  	}
   217  	c := gomcache()
   218  	s.next = c.sudogcache
   219  	c.sudogcache = s
   220  }
   221  
   222  // funcPC returns the entry PC of the function f.
   223  // It assumes that f is a func value. Otherwise the behavior is undefined.
   224  //go:nosplit
   225  func funcPC(f interface{}) uintptr {
   226  	return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
   227  }
   228  
   229  // called from assembly
   230  func badmcall(fn func(*g)) {
   231  	throw("runtime: mcall called on m->g0 stack")
   232  }
   233  
   234  func badmcall2(fn func(*g)) {
   235  	throw("runtime: mcall function returned")
   236  }
   237  
   238  func badreflectcall() {
   239  	panic("runtime: arg size to reflect.call more than 1GB")
   240  }
   241  
   242  func lockedOSThread() bool {
   243  	gp := getg()
   244  	return gp.lockedm != nil && gp.m.lockedg != nil
   245  }
   246  
   247  func newP() *p {
   248  	return new(p)
   249  }
   250  
   251  func newM() *m {
   252  	return new(m)
   253  }
   254  
   255  func newG() *g {
   256  	return new(g)
   257  }
   258  
   259  var (
   260  	allgs    []*g
   261  	allglock mutex
   262  )
   263  
   264  func allgadd(gp *g) {
   265  	if readgstatus(gp) == _Gidle {
   266  		throw("allgadd: bad status Gidle")
   267  	}
   268  
   269  	lock(&allglock)
   270  	allgs = append(allgs, gp)
   271  	allg = &allgs[0]
   272  	allglen = uintptr(len(allgs))
   273  	unlock(&allglock)
   274  }