internal ThreadBucketNode *next; // offset 120 internal static unsafe bool SearchFor(ThreadBucketNode *startNode, ulong threadId, ref ThreadBucketNode *bucketNode) { ThreadBucketNode *prev = startNode; while (startNode != null) { if (startNode->threadId == threadId) { bucketNode = startNode; return(true); } prev = startNode; startNode = startNode->next; } bucketNode = prev; return(false); }
// NOT Burst safe due to string usage // Thread safe internal static unsafe void ThreadSetInfo(ulong threadId, ulong sysTicksStart, bool frameIndependent, string threadGroup, string threadName) { ThreadBucketNode *thread = null; int bucket = (int)threadId & 255; if (threadHashTableHead != null) { // No need for locking yet - read operations on hash table are thread safe as long as we are careful about // modification during write and only allow one thread to write at a time. if (ThreadBucketNode.SearchFor(&threadHashTableHead->ThreadsBuffer[bucket], threadId, ref thread)) { return; } } // The thread info didn't exist in hash table. Need to lock so only one thread can modify at a time. // This path will usually only be taken during startup when creating threads - after which thread info // should be found in the above loop instead of needing to be created. PlayerConnectionMt_LockProfilerHashTables(); if (thread == null) { if (threadHashTableHead == null) { threadHashTableHead = FastHashTableBufferNode.Allocate(sizeof(ThreadBucketNode)); threadHashTableTail = threadHashTableHead; } thread = &threadHashTableHead->ThreadsBuffer[bucket]; } // In case this bucket was added to while another thread had the lock, the end-of-bucket // pointer needs to be increased. Also, it's possible the same exact name appears now. if (ThreadBucketNode.SearchFor(thread, threadId, ref thread)) { PlayerConnectionMt_UnlockProfilerHashTables(); return; } ThreadBucketNode *oldThread = null; if (thread->nameBytes > 0 || thread->groupBytes > 0) { // There is already a valid thread here at the end of the linked list - add a new one threadHashTableTail = threadHashTableTail->ExtendPoolIfFull(sizeof(ThreadBucketNode)); ThreadBucketNode *newThread = &threadHashTableTail->ThreadsBuffer[threadHashTableTail->size]; threadHashTableTail->size++; oldThread = thread; thread = newThread; } thread->init = false; Assert.IsTrue(thread->nameBytes <= k_MaxThreadNameLength); Assert.IsTrue(thread->groupBytes <= k_MaxThreadNameLength); fixed(char *c = threadGroup) thread->groupBytes = UTF8.GetBytes(c, threadGroup.Length, thread->groupUtf8, k_MaxThreadNameLength); fixed(char *c = threadName) thread->nameBytes = UTF8.GetBytes(c, threadName.Length, thread->nameUtf8, k_MaxThreadNameLength); thread->frameIndependent = frameIndependent; thread->sysTicksStart = sysTicksStart; thread->threadId = threadId; // Do this last so if we find the node before locking, we don't have access to it unless it is otherwise fully assigned if (oldThread != null) { oldThread->next = thread; } PlayerConnectionMt_UnlockProfilerHashTables(); NeedsUpdate = true; }