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 }