/// <summary> /// Init SMT (Size Map Table). /// </summary> /// <param name="aMaxItemSize">A max item size.</param> static void InitSMT(uint aMaxItemSize) { mMaxItemSize = aMaxItemSize; var page = InitSMTPage(); SMT = page; }
/// <summary> /// Add a new root block for a certain size /// </summary> /// <param name="aSize">Size must be divisible by 2 otherwise Alloc breaks</param> private static void AddRootSMTBlock(SMTPage *aPage, uint aSize) { RootSMTBlock *ptr = aPage->First; while (ptr->LargerSize != null) { ptr = ptr->LargerSize; } if (aSize < ptr->Size) { // we cant later add a block with a size smaller than an earlier block. That would break the algorithm Debugger.DoSendNumber(aSize); Debugger.DoSendNumber(ptr->Size); Debugger.SendKernelPanic(0x83); while (true) { } } if (ptr->Size == 0) { ptr->Size = aSize; } else { var block = (RootSMTBlock *)NextFreeBlock(aPage); // we should actually check that this is not null //but we should also only call this code right at the beginning so it should be fine block->Size = aSize; ptr->LargerSize = block; } CreatePage(aPage, aSize); }
/// <summary> /// Create a page with the size of an item and add it to the SMT at a certain page /// </summary> /// <param name="aItemSize">Object size in bytes</param> /// <exception cref="Exception">Thrown if: /// <list type="bullet"> /// <item>aItemSize is 0.</item> /// <item>aItemSize is not word aligned.</item> /// <item>SMT is not initialized.</item> /// <item>The item size is bigger then a small heap size.</item> /// </list> /// </exception> static void CreatePage(SMTPage *aPage, uint aItemSize) { var xPtr = (byte *)RAT.AllocPages(RAT.PageType.HeapSmall, 1); if (xPtr == null) { return; // we failed to create the page, Alloc should still handle this case } uint xSlotSize = aItemSize + PrefixItemBytes; uint xItemCount = RAT.PageSize / xSlotSize; for (uint i = 0; i < xItemCount; i++) { byte * xSlotPtr = xPtr + i * xSlotSize; ushort *xMetaDataPtr = (ushort *)xSlotPtr; xMetaDataPtr[0] = 0; // Actual data size. 0 is empty. xMetaDataPtr[1] = 0; // Ref count } //now add it to the smt var parent = GetLastBlock(aPage, aItemSize); var smtBlock = NextFreeBlock(aPage); //get the next free block in the smt if (smtBlock == null) // we could not allocate a new block since the SMT table is all full { // we need to expand the SMT table by a page var last = SMT; while (last->Next != null) { last = last->Next; } last->Next = InitSMTPage(); parent = GetLastBlock(last->Next, aItemSize); smtBlock = NextFreeBlock(); if (smtBlock == null) { Debugger.SendKernelPanic(0x93); while (true) { } ; } } if (parent != null) { // there is already a block for the same size on the same page parent->NextBlock = smtBlock; } else { // in this case this is the first block of the size, so we can link it to root var root = GetFirstBlock(aPage, aItemSize); root->First = smtBlock; } smtBlock->SpacesLeft = xItemCount; smtBlock->PagePtr = xPtr; }
/// <summary> /// Counts how many elements are currently allocated on a certain page /// </summary> /// <param name="aSize"></param> /// <returns></returns> private static int GetAllocatedObjectCount(SMTPage *aPage) { var ptr = aPage->First; int count = 0; while (ptr != null) { count += GetAllocatedObjectCount(aPage, ptr->Size); ptr = ptr->LargerSize; } return(count); }
/// <summary> /// Find the next free block in a page /// </summary> /// <returns>Pointer to the start of block in the SMT. null if all SMT pages are full</returns> private static SMTBlock *NextFreeBlock(SMTPage *aPage) { var ptr = (SMTBlock *)aPage->First; // since both RootSMTBlock and SMTBlock have the same size (20) it doesnt matter if cast is wrong while (ptr->PagePtr != null) // this would check Size if its actually a RootSMTBlock { ptr += 1; if (ptr >= (byte *)aPage + RAT.PageSize - 8) { return(null); } } return(ptr); }
/// <summary> /// Gets the last block on a certain page for objects of this size /// </summary> /// <param name="page">Page to search</param> /// <param name="aSize"></param> /// <returns></returns> private static SMTBlock *GetLastBlock(SMTPage *page, uint aSize) { SMTBlock *ptr = GetFirstBlock(page, aSize)->First; if (ptr == null) { return(null); } while (ptr->NextBlock != null) { ptr = ptr->NextBlock; } return(ptr); }
/// <summary> /// Counts how many elements are currently allocated in this category on a certain page /// </summary> /// <param name="aSize"></param> /// <returns></returns> private static int GetAllocatedObjectCount(SMTPage *aPage, uint aSize) { var root = GetFirstBlock(aPage, aSize); var ptr = root->First; uint size = root->Size; int count = 0; while (ptr != null) { count += (int)(RAT.PageSize / (size + PrefixItemBytes)) - (int)ptr->SpacesLeft; ptr = ptr->NextBlock; } return(count); }
/// <summary> /// Gets the root block in the SMT for objects of this size /// </summary> /// <param name="aSize">Size of allocated block</param> /// <param name="aPage">Page to seach in</param> /// <returns>Pointer of block in SMT.</returns> private static RootSMTBlock *GetFirstBlock(SMTPage *aPage, uint aSize) { RootSMTBlock *ptr = aPage->First; uint curSize = ptr->Size; while (curSize < aSize) { ptr = ptr->LargerSize; if (ptr == null) { return(null); } curSize = ptr->Size; } return(ptr); }
/// <summary> /// Get the first block for this size, which has space left to allocate to /// </summary> /// <param name="aSize"></param> /// <returns></returns> private static SMTBlock *GetFirstWithSpace(SMTPage *aPage, uint aSize) { return(GetFirstWithSpace(aSize, GetFirstBlock(aPage, aSize))); }