// Allocate up to n objects from the central free list. // Return the number of objects allocated. // The objects are linked together by their first words. // On return, *pstart points at the first object and *pend at the last. int32 runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) { MLink *first, *last, *v; int32 i; runtime_lock(c); // Replenish central list if empty. if(runtime_MSpanList_IsEmpty(&c->nonempty)) { if(!MCentral_Grow(c)) { runtime_unlock(c); *pfirst = nil; return 0; } } // Copy from list, up to n. // First one is guaranteed to work, because we just grew the list. first = MCentral_Alloc(c); last = first; for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) { last->next = v; last = v; } last->next = nil; c->nfree -= i; runtime_unlock(c); *pfirst = first; return i; }
// Allocate up to n objects from the central free list. // Return the number of objects allocated. // The objects are linked together by their first words. // On return, *pstart points at the first object. int32 runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) { MSpan *s; MLink *first, *last; int32 cap, avail, i; runtime·lock(c); // Replenish central list if empty. if(runtime·MSpanList_IsEmpty(&c->nonempty)) { if(!MCentral_Grow(c)) { runtime·unlock(c); *pfirst = nil; return 0; } } s = c->nonempty.next; cap = (s->npages << PageShift) / s->elemsize; avail = cap - s->ref; if(avail < n) n = avail; // First one is guaranteed to work, because we just grew the list. first = s->freelist; last = first; for(i=1; i<n; i++) { last = last->next; } s->freelist = last->next; last->next = nil; s->ref += n; c->nfree -= n; if(n == avail) { if(s->freelist != nil || s->ref != cap) { runtime·throw("invalid freelist"); } runtime·MSpanList_Remove(s); runtime·MSpanList_Insert(&c->empty, s); } runtime·unlock(c); *pfirst = first; return n; }
runtime·MCentral_CacheSpan(MCentral *c) { MSpan *s; int32 cap, n; uint32 sg; runtime·lock(&c->lock); 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->lock); runtime·MSpan_Sweep(s); runtime·lock(&c->lock); // 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->lock); runtime·MSpan_Sweep(s); runtime·lock(&c->lock); // 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->lock); return nil; } goto retry; havespan: cap = (s->npages << PageShift) / s->elemsize; n = cap - s->ref; if(n == 0) runtime·throw("empty span"); if(s->freelist == nil) runtime·throw("freelist empty"); runtime·MSpanList_Remove(s); runtime·MSpanList_InsertBack(&c->empty, s); s->incache = true; runtime·unlock(&c->lock); return s; }
// 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; }