/* Copyright (c) 2003-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "buddy.hpp" void Chunk256::setFree(bool free){ // Bit 0 of allocationTimeStamp represents if the segment is free or not Uint32 offMask = 0x0; // A mask to set the 0 bit to 0 allocationTimeStamp = 0x0; if(free) // Set this bit to 0, if segment should be free allocationTimeStamp = allocationTimeStamp & offMask; } bool Chunk256::getFree(){ Uint32 offMask = 0x0; return ((allocationTimeStamp | offMask) == offMask ? true : false); } void Chunk256::setAllocationTimeStamp(Uint32 cTime){ // Bits 1-31 of allocationTimeStamp represent the allocation time for segment // printf("\nSet allocation time. Current time %d", cTime); Uint32 onMask = 0x80000000; // A mask to set the 0 bit to 1 allocationTimeStamp = 0x0; allocationTimeStamp = onMask | cTime; } Uint32 Chunk256::getAllocationTimeStamp(){ Uint32 onMask = 0x80000000; allocationTimeStamp = allocationTimeStamp ^ onMask; printf("\nGet allocation time. Time is %d", allocationTimeStamp); return allocationTimeStamp; }; bool BuddyMemory::allocate(int nChunksToAllocate) { // Allocate the memory block needed. This memory is deallocated in the // destructor of TransporterRegistry. printf("\nAllocating %d chunks...", nChunksToAllocate); startOfMemoryBlock = (Uint32*) malloc(256 * nChunksToAllocate); if (startOfMemoryBlock == NULL) return false; // Allocate the array of 256-byte chunks chunk = new Chunk256[nChunksToAllocate]; // Initialize the chunk-array. Every 8 kB segment consists of 32 chunks. // Set all chunks to free and set the prev and next pointer for (int i=0; i < nChunksToAllocate; i++) { chunk[i].setFree(true); if (i%32 == 0) { // The first chunk in every segment will point to the prev and next segment chunk[i].prevSegmentOfSameSize = i-32; chunk[i].nextSegmentOfSameSize = i + 32; chunk[0].prevSegmentOfSameSize = END_OF_CHUNK_LIST; chunk[totalNoOfChunks-32].nextSegmentOfSameSize = END_OF_CHUNK_LIST; } else { // The rest of the chunks in the segments have undefined prev and next pointers chunk[i].prevSegmentOfSameSize = UNDEFINED_CHUNK; chunk[i].nextSegmentOfSameSize = UNDEFINED_CHUNK; } } // Initialize the freeSegment-pointers for (int i=0; i 256) segmSize ++; printf("\nSegment size: %f", pow(2,int(8+segmSize))); while ((segmSize <= sz_GET_MAX) && (freeSegment[segmSize] == UNDEFINED_CHUNK)) segmSize++; segm = freeSegment[segmSize]; if (segm != UNDEFINED_CHUNK){ // Free segment of asked size or larger is found // Remove the found segment from the freeSegment-list removeFromFreeSegmentList(segmSize, segm); // Set all chunks to allocated (not free) and set the allocation time // for the segment we are about to allocate for (int i = segm; i <= segm+nChunksToAllocate; i++) { chunk[i].setFree(false); chunk[i].setAllocationTimeStamp(currentTime); } // Before returning the segment, check if it is larger than the segment asked for if (nChunksAskedFor < nChunksToAllocate) release(nChunksAskedFor, nChunksToAllocate - nChunksAskedFor - 1); Segment segment; segment.segmentAddress = startOfMemoryBlock+(segm * 256); segment.segmentSize = 256 * nChunksAskedFor; segment.releaseId = segm; printf("\nSegment: segment address = %d, segment size = %d, release Id = %d", segment.segmentAddress, segment.segmentSize, segment.releaseId); return true; } printf("\nNo segments of asked size or larger are found"); return false; } void BuddyMemory::removeFromFreeSegmentList(int sz, int index) { // Remove the segment from the freeSegment list printf("\nRemoving segment from list..."); if (index != UNDEFINED_CHUNK) { Chunk256 prevChunk; Chunk256 nextChunk; int prevChunkIndex = chunk[index].prevSegmentOfSameSize; int nextChunkIndex = chunk[index].nextSegmentOfSameSize; if (prevChunkIndex == END_OF_CHUNK_LIST) { if (nextChunkIndex == END_OF_CHUNK_LIST) // We are about to remove the only element in the list freeSegment[sz] = UNDEFINED_CHUNK; else { // We are about to remove the first element in the list nextChunk = chunk[nextChunkIndex]; nextChunk.prevSegmentOfSameSize = END_OF_CHUNK_LIST; freeSegment[sz] = nextChunkIndex; } } else { if (nextChunkIndex == END_OF_CHUNK_LIST) { // We are about to remove the last element in the list prevChunk = chunk[prevChunkIndex]; prevChunk.nextSegmentOfSameSize = END_OF_CHUNK_LIST; } else { // We are about to remove an element in the middle of the list prevChunk = chunk[prevChunkIndex]; nextChunk = chunk[nextChunkIndex]; prevChunk.nextSegmentOfSameSize = nextChunkIndex; nextChunk.prevSegmentOfSameSize = prevChunkIndex; } } } for (int i=0; i= 0; i--) { if (!chunk[i].getFree()) break; else { startChunk = i; nChunksToRelease++; // Look at the next-pointer. If it is valid, we have a // chunk that is the start of a free segment. Remove it // from the freeSegment-list. if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK) removeFromFreeSegmentList(size, i); } } // Look at the chunks after the segment we are about to release for (int i = endChunk+1; i <= totalNoOfChunks; i++) { if (!chunk[i].getFree()) break; else { endChunk = i; nChunksToRelease++; // Look at the next-pointer. If it is valid, we have a // chunk that is the start of a free segment. Remove it // from the free segment list if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK) removeFromFreeSegmentList(size, i); } } // We have the start and end indexes and total no of free chunks. // Separate the chunks into segments that can be added to the // freeSegments-list. int restChunk = 0; int segmSize; printf("\n%d chunks to release (finally)", nChunksToRelease); segmSize = logTwoPlus(nChunksToRelease) - 1; if (segmSize > sz_MAX) { segmSize = sz_MAX; } nChunksToRelease = pow(2,segmSize); addToFreeSegmentList(nChunksToRelease*256, startChunk); } void BuddyMemory::addToFreeSegmentList(int sz, int index) { // Add a segment to the freeSegment list printf("\nAsked to add segment of size %d", sz); // Get an index in freeSegment list corresponding to sz size int segmSize = logTwoPlus(sz) - 1; if (sz - pow(2,segmSize) >= 256) segmSize ++; sz = segmSize - 8; int nextSegm = freeSegment[sz]; printf("\nAdding a segment of size %f", pow(2,(8 + sz))); freeSegment[sz] = index; if (nextSegm == UNDEFINED_CHUNK) { // We are about to add a segment to an empty list chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST; chunk[index].nextSegmentOfSameSize = END_OF_CHUNK_LIST; } else { // Add the segment first in the list chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST; chunk[index].nextSegmentOfSameSize = nextSegm; chunk[nextSegm].prevSegmentOfSameSize = index; } for (int i=0; i> 8); arg = arg | (arg >> 4); arg = arg | (arg >> 2); arg = arg | (arg >> 1); resValue = (arg & 0x5555) + ((arg >> 1) & 0x5555); resValue = (resValue & 0x3333) + ((resValue >> 2) & 0x3333); resValue = resValue + (resValue >> 4); resValue = (resValue & 0xf) + ((resValue >> 8) & 0xf); return resValue; } bool BuddyMemory::memoryAvailable() { // Return true if there is at least 8 kB memory available for (int i = sz_8192; i < sz_MAX; i++) if (freeSegment[i] != UNDEFINED_CHUNK) return true; return false; } void BuddyMemory::refreshTime(Uint32 time) { if (time - currentTime > 1000) { // Update current time currentTime = time; // Go through the chunk-list every second and release // any chunks that have been allocated for too long for (int i=0; i ALLOCATION_TIMEOUT)) { release(i, 256); printf("\nChunks hve been allocated for too long"); } } } }