diff options
Diffstat (limited to 'src/pkg/runtime/mcentral.c')
| -rw-r--r-- | src/pkg/runtime/mcentral.c | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c index 735a7e6a9a..d96a73394d 100644 --- a/src/pkg/runtime/mcentral.c +++ b/src/pkg/runtime/mcentral.c @@ -39,17 +39,58 @@ runtime·MCentral_AllocList(MCentral *c, MLink **pfirst) { MSpan *s; int32 cap, n; + uint32 sg; runtime·lock(c); - // Replenish central list if empty. - if(runtime·MSpanList_IsEmpty(&c->nonempty)) { - if(!MCentral_Grow(c)) { + sg = runtime·mheap.sweepgen; +retry: + for(s = c->nonempty.next; s != &c->nonempty; s = s->next) { + if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) { runtime·unlock(c); - *pfirst = nil; - return 0; + runtime·MSpan_Sweep(s); + runtime·lock(c); + // the span could have been moved to heap, retry + goto retry; + } + if(s->sweepgen == sg-1) { + // the span is being swept by background sweeper, skip + continue; + } + // we have a nonempty span that does not require sweeping, allocate from it + goto havespan; + } + + for(s = c->empty.next; s != &c->empty; s = s->next) { + if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) { + // we have an empty span that requires sweeping, + // sweep it and see if we can free some space in it + runtime·MSpanList_Remove(s); + // swept spans are at the end of the list + runtime·MSpanList_InsertBack(&c->empty, s); + runtime·unlock(c); + runtime·MSpan_Sweep(s); + runtime·lock(c); + // the span could be moved to nonempty or heap, retry + goto retry; + } + if(s->sweepgen == sg-1) { + // the span is being swept by background sweeper, skip + continue; } + // already swept empty span, + // all subsequent ones must also be either swept or in process of sweeping + break; + } + + // Replenish central list if empty. + if(!MCentral_Grow(c)) { + runtime·unlock(c); + *pfirst = nil; + return 0; } s = c->nonempty.next; + +havespan: cap = (s->npages << PageShift) / s->elemsize; n = cap - s->ref; *pfirst = s->freelist; @@ -57,7 +98,7 @@ runtime·MCentral_AllocList(MCentral *c, MLink **pfirst) s->ref += n; c->nfree -= n; runtime·MSpanList_Remove(s); - runtime·MSpanList_Insert(&c->empty, s); + runtime·MSpanList_InsertBack(&c->empty, s); runtime·unlock(c); return n; } @@ -116,8 +157,9 @@ MCentral_Free(MCentral *c, void *v) } // Free n objects from a span s back into the central free list c. -// Called from GC. -void +// Called during sweep. +// Returns true if the span was returned to heap. +bool runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end) { int32 size; @@ -136,19 +178,21 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink * s->ref -= n; c->nfree += n; - // If s is completely freed, return it to the heap. - if(s->ref == 0) { - size = runtime·class_to_size[c->sizeclass]; - runtime·MSpanList_Remove(s); - *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing - s->freelist = nil; - c->nfree -= (s->npages << PageShift) / size; - runtime·unlock(c); - runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift); - runtime·MHeap_Free(&runtime·mheap, s, 0); - } else { + if(s->ref != 0) { runtime·unlock(c); + return false; } + + // s is completely freed, return it to the heap. + size = runtime·class_to_size[c->sizeclass]; + runtime·MSpanList_Remove(s); + *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing + s->freelist = nil; + c->nfree -= (s->npages << PageShift) / size; + runtime·unlock(c); + runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift); + runtime·MHeap_Free(&runtime·mheap, s, 0); + return true; } void |
