aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/proc.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/proc.go')
-rw-r--r--src/runtime/proc.go65
1 files changed, 47 insertions, 18 deletions
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index d251c314d4..d83b1bebf4 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -167,17 +167,6 @@ func goready(gp *g) {
//go:nosplit
func acquireSudog() *sudog {
- c := gomcache()
- s := c.sudogcache
- if s != nil {
- if s.elem != nil {
- throw("acquireSudog: found s.elem != nil in cache")
- }
- c.sudogcache = s.next
- s.next = nil
- return s
- }
-
// Delicate dance: the semaphore implementation calls
// acquireSudog, acquireSudog calls new(sudog),
// new calls malloc, malloc can call the garbage collector,
@@ -187,12 +176,31 @@ func acquireSudog() *sudog {
// The acquirem/releasem increments m.locks during new(sudog),
// which keeps the garbage collector from being invoked.
mp := acquirem()
- p := new(sudog)
- if p.elem != nil {
- throw("acquireSudog: found p.elem != nil after new")
+ pp := mp.p
+ if len(pp.sudogcache) == 0 {
+ lock(&sched.sudoglock)
+ // First, try to grab a batch from central cache.
+ for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
+ s := sched.sudogcache
+ sched.sudogcache = s.next
+ s.next = nil
+ pp.sudogcache = append(pp.sudogcache, s)
+ }
+ unlock(&sched.sudoglock)
+ // If the central cache is empty, allocate a new one.
+ if len(pp.sudogcache) == 0 {
+ pp.sudogcache = append(pp.sudogcache, new(sudog))
+ }
+ }
+ ln := len(pp.sudogcache)
+ s := pp.sudogcache[ln-1]
+ pp.sudogcache[ln-1] = nil
+ pp.sudogcache = pp.sudogcache[:ln-1]
+ if s.elem != nil {
+ throw("acquireSudog: found s.elem != nil in cache")
}
releasem(mp)
- return p
+ return s
}
//go:nosplit
@@ -216,9 +224,30 @@ func releaseSudog(s *sudog) {
if gp.param != nil {
throw("runtime: releaseSudog with non-nil gp.param")
}
- c := gomcache()
- s.next = c.sudogcache
- c.sudogcache = s
+ mp := acquirem() // avoid rescheduling to another P
+ pp := mp.p
+ if len(pp.sudogcache) == cap(pp.sudogcache) {
+ // Transfer half of local cache to the central cache.
+ var first, last *sudog
+ for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
+ ln := len(pp.sudogcache)
+ p := pp.sudogcache[ln-1]
+ pp.sudogcache[ln-1] = nil
+ pp.sudogcache = pp.sudogcache[:ln-1]
+ if first == nil {
+ first = p
+ } else {
+ last.next = p
+ }
+ last = p
+ }
+ lock(&sched.sudoglock)
+ last.next = sched.sudogcache
+ sched.sudogcache = first
+ unlock(&sched.sudoglock)
+ }
+ pp.sudogcache = append(pp.sudogcache, s)
+ releasem(mp)
}
// funcPC returns the entry PC of the function f.