// else for a while, so kick everything out of its run
// queue.
} else {
- if _p_.gcw.wbuf == 0 && work.full == 0 && work.partial == 0 {
+ if _p_.gcw.wbuf == 0 && work.full == 0 {
// No work to be done right now. This can
// happen at the end of the mark phase when
// there are still assists tapering off. Don't
}
var work struct {
- full uint64 // lock-free list of full blocks workbuf
- empty uint64 // lock-free list of empty blocks workbuf
- // TODO(rlh): partial no longer used, remove. (issue #11922)
- partial uint64 // lock-free list of partially filled blocks workbuf
+ full uint64 // lock-free list of full blocks workbuf
+ empty uint64 // lock-free list of empty blocks workbuf
pad0 [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait
nproc uint32
tstart int64
"work.nwait=", incnwait, "work.nproc=", work.nproc)
throw("work.nwait > work.nproc")
}
- done = incnwait == work.nproc && work.full == 0 && work.partial == 0
+ done = incnwait == work.nproc && work.full == 0
}
// If this worker reached a background mark completion
if !p.gcw.empty() {
return true
}
- if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 {
+ if atomicload64(&work.full) != 0 {
return true // global work available
}
return false
if work.full != 0 {
throw("work.full != 0")
}
- if work.partial != 0 {
- throw("work.partial != 0")
- }
if work.nproc > 1 {
notesleep(&work.alldone)
wbuf := w.wbuf.ptr()
if wbuf == nil {
- wbuf = getpartialorempty(42)
+ wbuf = getempty(42)
w.wbuf = wbufptrOf(wbuf)
}
type workbufhdr struct {
node lfnode // must be first
nobj int
- inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues.
+ inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/full queues.
log [4]int // line numbers forming a history of ownership changes to workbuf
}
// workbuf factory routines. These funcs are used to manage the
// workbufs.
// If the GC asks for some work these are the only routines that
-// make partially full wbufs available to the GC.
+// make wbufs available to the GC.
// Each of the gets and puts also take an distinct integer that is used
// to record a brief history of changes to ownership of the workbuf.
// The convention is to use a unique line number but any encoding
lfstackpush(&work.full, &b.node)
}
-// getpartialorempty tries to return a partially empty
-// and if none are available returns an empty one.
-// entry is used to provide a brief history of ownership
-// using entry + xxx00000 to
-// indicating that two line numbers in the call chain.
-//go:nowritebarrier
-func getpartialorempty(entry int) *workbuf {
- b := (*workbuf)(lfstackpop(&work.partial))
- if b != nil {
- b.logget(entry)
- return b
- }
- // Let getempty do the logget check but
- // use the entry to encode that it passed
- // through this routine.
- b = getempty(entry + 80700000)
- return b
-}
-
-// putpartial puts empty buffers on the work.empty queue,
-// full buffers on the work.full queue and
-// others on the work.partial queue.
-// entry is used to provide a brief history of ownership
-// using entry + xxx00000 to
-// indicating that two call chain line numbers.
-//go:nowritebarrier
-func putpartial(b *workbuf, entry int) {
- if b.nobj == 0 {
- putempty(b, entry+81500000)
- } else if b.nobj < len(b.obj) {
- b.logput(entry)
- lfstackpush(&work.partial, &b.node)
- } else if b.nobj == len(b.obj) {
- b.logput(entry)
- lfstackpush(&work.full, &b.node)
- } else {
- throw("putpartial: bad Workbuf b.nobj")
- }
-}
-
// trygetfull tries to get a full or partially empty workbuffer.
// If one is not immediately available return nil
//go:nowritebarrier
func trygetfull(entry int) *workbuf {
b := (*workbuf)(lfstackpop(&work.full))
- if b == nil {
- b = (*workbuf)(lfstackpop(&work.partial))
- }
if b != nil {
b.logget(entry)
b.checknonempty()
return b
}
-// Get a full work buffer off the work.full or a partially
-// filled one off the work.partial list. If nothing is available
-// wait until all the other gc helpers have finished and then
-// return nil.
+// Get a full work buffer off the work.full list.
+// If nothing is available wait until all the other gc helpers have
+// finished and then return nil.
// getfull acts as a barrier for work.nproc helpers. As long as one
// gchelper is actively marking objects it
// may create a workbuffer that the other helpers can work on.
b.checknonempty()
return b
}
- b = (*workbuf)(lfstackpop(&work.partial))
- if b != nil {
- b.logget(entry)
- return b
- }
incnwait := xadd(&work.nwait, +1)
if incnwait > work.nproc {
throw("work.nwait > work.nproc")
}
for i := 0; ; i++ {
- if work.full != 0 || work.partial != 0 {
+ if work.full != 0 {
decnwait := xadd(&work.nwait, -1)
if decnwait == work.nproc {
println("runtime: work.nwait=", decnwait, "work.nproc=", work.nproc)
throw("work.nwait > work.nproc")
}
b = (*workbuf)(lfstackpop(&work.full))
- if b == nil {
- b = (*workbuf)(lfstackpop(&work.partial))
- }
if b != nil {
b.logget(entry)
b.checknonempty()