2014-08-19 01:49:59 -06:00
|
|
|
// 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
|
|
|
|
|
2014-08-21 10:41:09 -06:00
|
|
|
import "unsafe"
|
|
|
|
|
2014-08-27 09:15:47 -06:00
|
|
|
// This is not mechanically generated
|
|
|
|
// so be very careful and refer to runtime.h
|
|
|
|
// for the definitive enum.
|
2014-08-21 10:41:09 -06:00
|
|
|
const (
|
|
|
|
gStatusidle = iota
|
|
|
|
gStatusRunnable
|
|
|
|
gStatusRunning
|
|
|
|
gStatusSyscall
|
|
|
|
gStatusWaiting
|
|
|
|
gStatusMoribundUnused
|
|
|
|
gStatusDead
|
2014-08-27 09:15:47 -06:00
|
|
|
gStatusEnqueue
|
|
|
|
gStatusCopystack
|
|
|
|
gStatusScan = 0x1000
|
|
|
|
gStatusScanRunnable = gStatusScan + gStatusRunnable
|
|
|
|
gStatusScanRunning = gStatusScan + gStatusRunning
|
|
|
|
gStatusScanSyscall = gStatusScan + gStatusSyscall
|
|
|
|
gStatusScanWaiting = gStatusScan + gStatusWaiting
|
|
|
|
gStatusScanEnqueue = gStatusScan + gStatusEnqueue
|
2014-08-21 10:41:09 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
var parkunlock_c byte
|
|
|
|
|
2014-08-29 01:08:10 -06:00
|
|
|
// start forcegc helper goroutine
|
|
|
|
func init() {
|
2014-09-02 17:18:46 -06:00
|
|
|
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")
|
2014-08-29 01:08:10 -06:00
|
|
|
}
|
2014-09-02 17:18:46 -06:00
|
|
|
gogc(1)
|
|
|
|
}
|
2014-08-29 01:08:10 -06:00
|
|
|
}
|
|
|
|
|
2014-08-19 01:49:59 -06:00
|
|
|
// 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)
|
|
|
|
}
|
2014-08-21 10:41:09 -06:00
|
|
|
|
2014-08-27 09:15:47 -06:00
|
|
|
func readgStatus(gp *g) uint32 {
|
|
|
|
//return atomic.LoadUint32(&gp.atomicstatus) // TODO: add bootstrap code to provide.
|
|
|
|
return gp.atomicstatus
|
|
|
|
}
|
|
|
|
|
2014-08-21 10:41:09 -06:00
|
|
|
// 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
|
2014-08-27 09:15:47 -06:00
|
|
|
status := readgStatus(gp)
|
|
|
|
if status != gStatusRunning && status != gStatusScanRunning {
|
2014-08-21 10:41:09 -06:00
|
|
|
gothrow("gopark: bad g status")
|
|
|
|
}
|
|
|
|
mp.waitlock = lock
|
2014-08-28 14:23:10 -06:00
|
|
|
mp.waitunlockf = unlockf
|
2014-08-21 10:41:09 -06:00
|
|
|
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).
|
2014-08-27 21:32:49 -06:00
|
|
|
func goparkunlock(lock *mutex, reason string) {
|
2014-08-21 10:41:09 -06:00
|
|
|
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 {
|
2014-08-25 10:12:26 -06:00
|
|
|
c.sudogcache = s.next
|
2014-08-21 10:41:09 -06:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
return new(sudog)
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:nosplit
|
|
|
|
func releaseSudog(s *sudog) {
|
|
|
|
c := gomcache()
|
2014-08-25 10:12:26 -06:00
|
|
|
s.next = c.sudogcache
|
2014-08-21 10:41:09 -06:00
|
|
|
c.sudogcache = s
|
|
|
|
}
|
2014-09-03 09:10:38 -06:00
|
|
|
|
|
|
|
// funcPC returns the entry PC of the function f.
|
|
|
|
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
|
|
|
func funcPC(f interface{}) uintptr {
|
|
|
|
return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
|
|
|
|
}
|