/// <summary> /// Releases the memory back in the buddy pool. /// </summary> /// <param name="offset"></param> public void Release(int offset) { // Do not do anything if disposed if (this.Disposed) { return; } // Convert the offset int index = offset / BuddyBlock.Size; if (index < 0 || index >= this.NumberOfBlocks) { throw new ArgumentOutOfRangeException("The specified offset was not found in the pool."); } if (this.Metadata == null) { return; } // Smaller lock, starting where we actually touch the pool lock (this.Lock) { // Get the block address BuddyBlock block = this.Metadata[index]; // Decrement the segments if (block.Status > BuddyBlockStatus.Reserved) { block.Status--; return; } block.Status = BuddyBlockStatus.Available; //BuddyBlock* ptr; //for (ptr = block; ptr->Power < this.NumberOfPowers; (ptr->Power)++) BuddyBlock ptr = block; for (int i = ptr.Power; i < this.NumberOfPowers; i++) { // Instead of hitting this.GetBuddy(ptr), we simply manually inline this BuddyBlock buddy = this.Metadata[((ptr.Offset ^ (1 << (ptr.Power))) / BuddyBlock.Size)]; if (buddy.Status == BuddyBlockStatus.Reserved || buddy.Power != ptr.Power) { break; } Unlink(buddy); //if (buddy < ptr) if (buddy.Offset < ptr.Offset) { ptr = buddy; } } InsertAfter(this.Sentinel[ptr.Power], ptr); } }
private void InsertAfter(BuddyBlock src, BuddyBlock block) { block.Next = src.Next; block.Previous = src; if (src.Next != null) { src.Next.Previous = block; } src.Next = block; }
private void Unlink(BuddyBlock block) { if (block.Next != null) { block.Next.Previous = block.Previous; } if (block.Previous != null) { block.Previous.Next = block.Next; } block.Next = block.Previous = block; }
/// <summary> /// Returns a pointer to the region of memory that is allocated. /// </summary> /// <param name="size">An integer-valued argument which specifies the size of storage area required.</param> /// <returns>A pointer to the region of memory that is allocated.</returns> public int Acquire(int size) { lock (this.Lock) { int kPrime = Log2Ceil(size > BuddyBlock.Size ? size : BuddyBlock.Size); int i = kPrime; while (i <= this.NumberOfPowers && (this.Sentinel[i]).Next == (this.Sentinel[i])) { ++i; } if (i > this.NumberOfPowers) { int powers = this.NumberOfPowers; int blocks = this.NumberOfBlocks; // Resize instead, with a maximum check this.Resize(++this.NumberOfPowers); // Set the sentinel to the newly allocated space BuddyBlock head = this.Metadata[blocks]; head.Status = BuddyBlockStatus.Available; head.Power = powers; InsertAfter(this.Sentinel[powers], head); // Search again return(Acquire(size)); } BuddyBlock block = this.Sentinel[i].Next; Unlink(block); while (block.Power > kPrime) { block.Power--; // Instead of hitting this.GetBuddy(block), we simply manually inline it var buddy = this.Metadata[((block.Offset ^ (1 << (block.Power))) / BuddyBlock.Size)]; buddy.Status = BuddyBlockStatus.Available; buddy.Power = block.Power; InsertAfter(this.Sentinel[buddy.Power], buddy); } block.Status = BuddyBlockStatus.Reserved; // Return the offset of the allocated block return(block.Offset); } }
/// <summary> /// Gets a buddy of a given block. /// </summary> /// <param name="block">The block to get a buddy for.</param> /// <returns>The pointer to the buddy.</returns> private BuddyBlock GetBuddy(BuddyBlock block) { return(this.Metadata[((block.Offset ^ (1 << (block.Power))) / BuddyBlock.Size)]); }