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 }