FreePageManagerPut(region->fpm, first_page, span->npages);
/*
- * XXX. Free the span, and possibly the span-of-spans which contains
- * it.
+ * Span-of-spans superblocks store the span which describes them
+ * within the superblock itself, so freeing the storage implicitly
+ * frees the descriptor also. If this is a superblock of any other
+ * type, we need to separately free the span object also.
*/
+ if (span->size_class != SB_SCLASS_SPAN_OF_SPANS)
+ sb_free(span);
}
/* If we locked the heap, release the lock. */
/*
* Compute the number of objects that will fit in a superblock of this
- * size class.
+ * size class. Span-of-spans superblocks are just a single page, and the
+ * first object isn't available for use because it describes the
+ * span-of-spans itself.
*/
if (size_class == SB_SCLASS_SPAN_OF_SPANS)
- nmax = FPM_PAGE_SIZE / obsize;
+ nmax = FPM_PAGE_SIZE / obsize - 1;
else
nmax = SB_SUPERBLOCK_SIZE / obsize;
for (i = 0; i < npages; ++i)
sb_map_set(region->pagemap, first_page + i, span);
- /* For a span-of-spans, record that we allocated ourselves. */
- if (size_class == SB_SCLASS_SPAN_OF_SPANS)
- {
- span->ninitialized = 1;
- span->nallocatable--;
- }
return true;
}
span->size_class = size_class;
span->ninitialized = 0;
if (size_class == SB_SCLASS_SPAN_OF_SPANS)
- span->nallocatable = FPM_PAGE_SIZE / obsize;
+ {
+ /*
+ * A span-of-spans contains its own descriptor, so mark one object
+ * as initialized and reduce the count of allocatable objects by one.
+ * Doing this here has the side effect of also reducing nmax by one,
+ * which is important to make sure we free this object at the correct
+ * time.
+ */
+ span->ninitialized = 1;
+ span->nallocatable = FPM_PAGE_SIZE / obsize - 1;
+ }
else if (size_class != SB_SCLASS_SPAN_LARGE)
span->nallocatable = SB_SUPERBLOCK_SIZE / obsize;
span->firstfree = SB_SPAN_NOTHING_FREE;