// Sweeps spans in list until reclaims at least npages into heap. // Returns the actual number of pages reclaimed. static uintptr MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages) { MSpan *s; uintptr n; uint32 sg; n = 0; sg = runtime_mheap.sweepgen; retry: for(s = list->next; s != list; s = s->next) { if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) { runtime_MSpanList_Remove(s); // swept spans are at the end of the list runtime_MSpanList_InsertBack(list, s); runtime_unlock(h); n += runtime_MSpan_Sweep(s); runtime_lock(h); if(n >= npages) return n; // the span could have been moved elsewhere goto retry; } if(s->sweepgen == sg-1) { // the span is being sweept by background sweeper, skip continue; } // already swept empty span, // all subsequent ones must also be either swept or in process of sweeping break; } return n; }
// Allocate a list of objects from the central free list. // Return the number of objects allocated. // The objects are linked together by their first words. // On return, *pfirst points at the first object. int32 runtime_MCentral_AllocList(MCentral *c, MLink **pfirst) { MSpan *s; int32 cap, n; uint32 sg; runtime_lock(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); 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; s->freelist = nil; s->ref += n; c->nfree -= n; runtime_MSpanList_Remove(s); runtime_MSpanList_InsertBack(&c->empty, s); runtime_unlock(c); return n; }