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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        /// <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);
        }
Пример #8
0
        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);
        }
Пример #9
0
 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;
        }
Пример #11
0
        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);
        }
Пример #12
0
 void Deallocate()
 {
     NativeQueueData.DeallocateQueue(m_Buffer, m_QueuePool, m_AllocatorLabel);
     m_Buffer = null;
 }