static void applyMemoryPool(const char* pathname) { struct stat st; stat(pathname, &st); initMemoryPool(st.st_size); }
void* allocate(size_t size) { if (!pool) { initMemoryPool(32, 1024); } #ifdef LOG_ALLOCATIONS LOG("Allocating %d bytes...", size); #endif // add padding to compensate for alignment and add the size of the header size += (((size % ALIGNMENT) > 0) ? ALIGNMENT - (size % ALIGNMENT) : 0); size += sizeof(AllocationHeader); // calculate pages and tracking units needed unsigned int pagesRequested = size / pageSize + ((size % pageSize) ? 1 : 0); unsigned int trackingUnitsRequested = pagesRequested / PAGES_PER_UNIT + ((pagesRequested % PAGES_PER_UNIT) ? 1 : 0); // make sure it isn't more than the entire pool if (trackingUnitsRequested > numTrackingUnits) { return NULL; } // search through all tracking units unsigned int beginningTrackingUnit = 0; while (beginningTrackingUnit < numTrackingUnits) { unsigned int preOffset = 0; TrackingUnit preBitMask = 0; if (pagesRequested < PAGES_PER_UNIT) { // build a bitmask that will find contiguous pages within a tracking unit preBitMask = ALL_PAGES_IN_USE << (PAGES_PER_UNIT - pagesRequested); } else { preBitMask = ALL_PAGES_IN_USE; } for (; preOffset < PAGES_PER_UNIT; ++preOffset) { if ((~(trackingBits[beginningTrackingUnit]) & preBitMask) == preBitMask) { // found a bitmask with enough contiguous pages break; } preBitMask = preBitMask >> 1; } if (preOffset == PAGES_PER_UNIT) { beginningTrackingUnit++; // skip subsequent fully used tracking units while (trackingBits[beginningTrackingUnit] == ALL_PAGES_IN_USE) { beginningTrackingUnit++; } continue; } TrackingUnit remainingPagesNeeded = ((pagesRequested >= (PAGES_PER_UNIT - preOffset)) ? (pagesRequested - (PAGES_PER_UNIT - preOffset)) : 0); // check if all the required pages have been found if (remainingPagesNeeded == 0) { // mark the tracking unit as used trackingBits[beginningTrackingUnit] |= preBitMask; // calculate the memory address unsigned int address = ((beginningTrackingUnit * PAGES_PER_UNIT) + preOffset) * pageSize; // write the allocation header *(unsigned int*)((unsigned int)(const_cast<void*>(pool)) + address) = size; // return the memory! return (void*)((unsigned int)(const_cast<void*>(pool)) + address + sizeof(AllocationHeader)); } // uhm... early out unsigned int nextTrackingUnit = (beginningTrackingUnit + 1) % numTrackingUnits; if (nextTrackingUnit < beginningTrackingUnit) { return NULL; } // look for contiguous unused tracking units unsigned int contiguousTrackingUnitsAvailable = 0; unsigned int contiguousTrackingUnitsNeeded = remainingPagesNeeded / PAGES_PER_UNIT; for (unsigned int i = nextTrackingUnit; i < numTrackingUnits && contiguousTrackingUnitsAvailable < contiguousTrackingUnitsNeeded; ++i) { if (trackingBits[i] == 0) { contiguousTrackingUnitsAvailable++; } else { // not gonna fit... bail! contiguousTrackingUnitsAvailable = 0; beginningTrackingUnit = i; break; } } // make sure we found enough... if (contiguousTrackingUnitsAvailable < contiguousTrackingUnitsNeeded) { continue; } remainingPagesNeeded = remainingPagesNeeded - (contiguousTrackingUnitsAvailable * PAGES_PER_UNIT); if (remainingPagesNeeded == 0) { trackingBits[beginningTrackingUnit] |= preBitMask; for (unsigned int i = nextTrackingUnit; i < (nextTrackingUnit + contiguousTrackingUnitsAvailable); ++i) { trackingBits[i] |= ALL_PAGES_IN_USE; // calculate the memory address unsigned int address = ((beginningTrackingUnit * PAGES_PER_UNIT) + preOffset) * pageSize; // write the allocation header *(unsigned int*)((unsigned int)(const_cast<void*>(pool)) + address) = size; // return the memory! return (void*)((unsigned int)(const_cast<void*>(pool)) + address + sizeof(AllocationHeader)); } } // again.. uhm... early out nextTrackingUnit = (nextTrackingUnit + contiguousTrackingUnitsAvailable) % numTrackingUnits; if (nextTrackingUnit <= beginningTrackingUnit) { return NULL; } // build a bitmask for finding the last batch of contiguous pages within a tracking unit TrackingUnit postBitMask = ALL_PAGES_IN_USE << (PAGES_PER_UNIT - remainingPagesNeeded); if ((~(trackingBits[nextTrackingUnit]) & postBitMask) == postBitMask) { // mark the pages used trackingBits[beginningTrackingUnit] |= preBitMask; for (unsigned int i = (beginningTrackingUnit + 1); i < nextTrackingUnit; ++i) { trackingBits[i] = ALL_PAGES_IN_USE; } trackingBits[nextTrackingUnit] |= postBitMask; // calculate the memory address unsigned int address = ((beginningTrackingUnit * PAGES_PER_UNIT) + preOffset) * pageSize; // write the allocation header *(unsigned int*)((unsigned int)(const_cast<void*>(pool)) + address) = size; // return the memory! return (void*)((unsigned int)(const_cast<void*>(pool)) + address + sizeof(AllocationHeader)); } // set the next tracking unit beginningTrackingUnit = nextTrackingUnit; } // finish loop through tracking bits return NULL; }