private static ImmixChunkHeader *AllocateChunk() { var chunkMemPtr = (nint)mi_malloc_aligned_at( (nuint)ImmixConstants.TotalChunkSize, ImmixConstants.BlockSize, (nuint)ImmixConstants.ChunkMetadataSize); // Assign the chunk header. var chunkPtr = (ImmixChunkHeader *)chunkMemPtr; chunkPtr->Initialize(totalChunks); // Initialize the blocks. var lineMapsStart = (byte *)chunkMemPtr + sizeof(ImmixChunkHeader); for (var i = 0; i < ImmixConstants.BlocksPerChunk; i++) { *ImmixChunkHeader.GetBlock(chunkPtr, i).Header = new ImmixBlockHeader(i, lineMapsStart + (ImmixConstants.LinesCount * i)); } // Add the chunk to the lists and increment the total chunks counter. // TODO: Add these by address order. chunks.Add(chunkPtr); freeChunks.Add(totalChunks); Interlocked.Increment(ref totalChunks); return(chunkPtr); }
internal static ImmixBlockAddress GetBlock() { ImmixBlockAddress block = null; lock (chunks) { if (freeChunks.Count > 0) { var chunkIdx = freeChunks [0]; var chunk = chunks [chunkIdx].Address; Debug.Assert(chunk->FreeBlocks > 0); for (var blockIdx = 0; blockIdx < ImmixConstants.BlocksPerChunk; blockIdx++) { if (chunk->BlockUsed [blockIdx] != 0) { continue; } block = ImmixChunkHeader.GetBlock(chunk, blockIdx); chunk->BlockUsed [blockIdx] = 0xFF; break; } Debug.Assert(block.Header != null, "Free chunks list contains a full chunk."); if (--chunk->FreeBlocks < 1) { freeChunks.RemoveAt(0); } } else { var newChunk = AllocateChunk(); newChunk->BlockUsed [0] = 0xFF; newChunk->FreeBlocks--; block = ImmixChunkHeader.GetBlock(newChunk, 0); } } if (block.Header->UsageLevel != ImmixBlockUsage.Empty) { block.Header->UsageLevel = ImmixBlockUsage.Empty; block.Header->LineMapSpan.Clear(); } return(block); }