public static byte *AllocateWriteBlockMT <T>(NativeQueueData *data, NativeQueueBlockPoolData *pool, int threadIndex) where T : struct { int tlsIdx = threadIndex; byte *currentWriteBlock = data->m_CurrentWriteBlockTLS[tlsIdx * IntsPerCacheLine]; if (currentWriteBlock != null && ((NativeQueueBlockHeader *)currentWriteBlock)->itemsInBlock == data->m_ItemsPerBlock) { currentWriteBlock = null; } if (currentWriteBlock == null) { currentWriteBlock = pool->AllocateBlock(); ((NativeQueueBlockHeader *)currentWriteBlock)->nextBlock = null; ((NativeQueueBlockHeader *)currentWriteBlock)->itemsInBlock = 0; NativeQueueBlockHeader *prevLast = (NativeQueueBlockHeader *)Interlocked.Exchange(ref data->m_LastBlock, (IntPtr)currentWriteBlock); if (prevLast == null) { data->m_FirstBlock = currentWriteBlock; } else { prevLast->nextBlock = currentWriteBlock; } data->m_CurrentWriteBlockTLS[tlsIdx * IntsPerCacheLine] = currentWriteBlock; } return(currentWriteBlock); }
public static NativeQueueBlockHeader *AllocateWriteBlockMT <T>(NativeQueueData *data, NativeQueueBlockPoolData *pool, int threadIndex) where T : struct { NativeQueueBlockHeader *currentWriteBlock = data->GetCurrentWriteBlockTLS(threadIndex); if (currentWriteBlock != null && currentWriteBlock->m_NumItems == data->m_MaxItems) { currentWriteBlock = null; } if (currentWriteBlock == null) { currentWriteBlock = pool->AllocateBlock(); currentWriteBlock->m_NextBlock = null; currentWriteBlock->m_NumItems = 0; NativeQueueBlockHeader *prevLast = (NativeQueueBlockHeader *)Interlocked.Exchange(ref data->m_LastBlock, (IntPtr)currentWriteBlock); if (prevLast == null) { data->m_FirstBlock = (IntPtr)currentWriteBlock; } else { prevLast->m_NextBlock = currentWriteBlock; } data->SetCurrentWriteBlockTLS(threadIndex, currentWriteBlock); } return(currentWriteBlock); }
/// <summary> /// Safely disposes of this container and deallocates its memory when the jobs that use it have completed. /// </summary> /// <remarks>You can call this function dispose of the container immediately after scheduling the job. Pass /// the [JobHandle](https://docs.unity3d.com/ScriptReference/Unity.Jobs.JobHandle.html) returned by /// the [Job.Schedule](https://docs.unity3d.com/ScriptReference/Unity.Jobs.IJobExtensions.Schedule.html) /// method using the `jobHandle` parameter so the job scheduler can dispose the container after all jobs /// using it have run.</remarks> /// <param name="inputDeps">The job handle or handles for any scheduled jobs that use this container.</param> /// <returns>A new job handle containing the prior handles as well as the handle for the job that deletes /// the container.</returns> public JobHandle Dispose(JobHandle inputDeps) { #if ENABLE_UNITY_COLLECTIONS_CHECKS // [DeallocateOnJobCompletion] is not supported, but we want the deallocation // to happen in a thread. DisposeSentinel needs to be cleared on main thread. // AtomicSafetyHandle can be destroyed after the job was scheduled (Job scheduling // will check that no jobs are writing to the container). DisposeSentinel.Clear(ref m_DisposeSentinel); var jobHandle = new NativeQueueDisposeJob { Data = new NativeQueueDispose { m_Buffer = m_Buffer, m_QueuePool = m_QueuePool, m_AllocatorLabel = m_AllocatorLabel, m_Safety = m_Safety } }.Schedule(inputDeps); AtomicSafetyHandle.Release(m_Safety); #else var jobHandle = new NativeQueueDisposeJob { Data = new NativeQueueDispose { m_Buffer = m_Buffer, m_QueuePool = m_QueuePool, m_AllocatorLabel = m_AllocatorLabel } }.Schedule(inputDeps); #endif m_Buffer = null; return(jobHandle); }
public unsafe static void AllocateQueue <T>(Allocator label, out NativeQueueData *outBuf) where T : struct { var queueDataSize = CollectionHelper.Align(UnsafeUtility.SizeOf <NativeQueueData>(), JobsUtility.CacheLineSize); var data = (NativeQueueData *)UnsafeUtility.Malloc( queueDataSize + JobsUtility.CacheLineSize * JobsUtility.MaxJobThreadCount , JobsUtility.CacheLineSize , label ); data->m_CurrentWriteBlockTLS = (((byte *)data) + queueDataSize); data->m_FirstBlock = IntPtr.Zero; data->m_LastBlock = IntPtr.Zero; data->m_MaxItems = (NativeQueueBlockPoolData.m_BlockSize - UnsafeUtility.SizeOf <NativeQueueBlockHeader>()) / UnsafeUtility.SizeOf <T>(); data->m_CurrentRead = 0; for (int threadIndex = 0; threadIndex < JobsUtility.MaxJobThreadCount; ++threadIndex) { data->SetCurrentWriteBlockTLS(threadIndex, null); } outBuf = data; }
public static byte *AllocateWriteBlockMT <T>(NativeQueueData *data, NativeQueueBlockPoolData *pool, int threadIndex) where T : struct { int tlsIdx = threadIndex; NativeQueueBlockHeader *currentWriteBlock = (NativeQueueBlockHeader *)data->GetCurrentWriteBlockTLS(tlsIdx); if (currentWriteBlock != null && currentWriteBlock->itemsInBlock == data->m_ItemsPerBlock) { currentWriteBlock = null; } if (currentWriteBlock == null) { currentWriteBlock = (NativeQueueBlockHeader *)pool->AllocateBlock(); currentWriteBlock->nextBlock = null; currentWriteBlock->itemsInBlock = 0; NativeQueueBlockHeader *prevLast = (NativeQueueBlockHeader *)Interlocked.Exchange(ref data->m_LastBlock, (IntPtr)currentWriteBlock); if (prevLast == null) { data->m_FirstBlock = currentWriteBlock; } else { prevLast->nextBlock = currentWriteBlock; } data->SetCurrentWriteBlockTLS(tlsIdx, currentWriteBlock); } return((byte *)currentWriteBlock); }
/// <summary> /// Disposes of this container and deallocates its memory immediately. /// </summary> public void Dispose() { #if ENABLE_UNITY_COLLECTIONS_CHECKS DisposeSentinel.Dispose(ref m_Safety, ref m_DisposeSentinel); #endif NativeQueueData.DeallocateQueue(m_Buffer, m_QueuePool, m_AllocatorLabel); m_Buffer = null; }
public unsafe static void DeallocateQueue(NativeQueueData *data, NativeQueueBlockPoolData *pool, Allocator allocation) { NativeQueueBlockHeader *firstBlock = (NativeQueueBlockHeader *)data->m_FirstBlock; while (firstBlock != null) { NativeQueueBlockHeader *next = (NativeQueueBlockHeader *)firstBlock->nextBlock; pool->FreeBlock((byte *)firstBlock); firstBlock = next; } UnsafeUtility.Free(data, allocation); }
public unsafe static void DeallocateQueue(NativeQueueData *data, NativeQueueBlockPoolData *pool, Allocator allocation) { NativeQueueBlockHeader *firstBlock = (NativeQueueBlockHeader *)data->m_FirstBlock; while (firstBlock != null) { NativeQueueBlockHeader *next = firstBlock->m_NextBlock; pool->FreeBlock(firstBlock); firstBlock = next; } Memory.Unmanaged.Free(data, allocation); }
public NativeQueue(int capacity, Allocator alloc) { capacity = Unity.Mathematics.math.max(1, capacity); this.capacity = capacity; nodes = new NativeList <ulong>(capacity, alloc); for (int i = 0; i < capacity; ++i) { void *ptr = MUnsafeUtility.Malloc(sizeof(T) + sizeof(ulong), alloc); UnsafeUtility.MemClear(ptr, sizeof(T) + sizeof(ulong)); nodes.Add((ulong)ptr); } queueData = MUnsafeUtility.Malloc <NativeQueueData>(sizeof(NativeQueueData), alloc); UnsafeUtility.MemClear(queueData, sizeof(NativeQueueData)); queueData->alloc = alloc; }
public unsafe static void AllocateQueue <T>(Allocator label, out NativeQueueData *outBuf) where T : struct { var data = (NativeQueueData *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <NativeQueueData>() + UnsafeUtility.SizeOf <IntPtr>() * JobsUtility.MaxJobThreadCount * IntsPerCacheLine, UnsafeUtility.AlignOf <NativeQueueData>(), label); data->m_CurrentWriteBlockTLS = (byte **)(((byte *)data) + UnsafeUtility.SizeOf <NativeQueueData>()); data->m_FirstBlock = null; data->m_LastBlock = IntPtr.Zero; data->m_ItemsPerBlock = (NativeQueueBlockPoolData.BlockSize - UnsafeUtility.SizeOf <NativeQueueBlockHeader>()) / UnsafeUtility.SizeOf <T>(); data->m_CurrentReadIndexInBlock = 0; for (int tls = 0; tls < JobsUtility.MaxJobThreadCount; ++tls) { data->m_CurrentWriteBlockTLS[tls * IntsPerCacheLine] = null; } outBuf = data; }
public static NativeQueueBlockHeader *GetFirstBlock(NativeQueueData *data, NativeQueueBlockPoolData *pool) { NativeQueueBlockHeader *firstBlock = (NativeQueueBlockHeader *)data->m_FirstBlock; if (firstBlock == null) { return(null); } if (data->m_CurrentRead >= firstBlock->m_NumItems) { var nextBlock = firstBlock->m_NextBlock; // Block should be freed once last reader calls Release. Interlocked.Decrement(ref firstBlock->m_NumReaders); for (int threadIndex = 0; threadIndex < JobsUtility.MaxJobThreadCount; ++threadIndex) { if (data->GetCurrentWriteBlockTLS(threadIndex) == firstBlock) { data->SetCurrentWriteBlockTLS(threadIndex, null); } } firstBlock = nextBlock; data->m_FirstBlock = (IntPtr)nextBlock; data->m_CurrentRead = 0; if (nextBlock == null) { data->m_LastBlock = IntPtr.Zero; } } if (firstBlock == null) { return(null); } Interlocked.Increment(ref firstBlock->m_NumReaders); return(firstBlock); }
void Deallocate() { NativeQueueData.DeallocateQueue(m_Buffer, m_QueuePool, m_AllocatorLabel); m_Buffer = null; }