1*58964d0bSSergey Makeev #include <MTScheduler.h> 2*58964d0bSSergey Makeev 3*58964d0bSSergey Makeev namespace MT 4*58964d0bSSergey Makeev { 5*58964d0bSSergey Makeev 6*58964d0bSSergey Makeev TaskScheduler::TaskScheduler() 7*58964d0bSSergey Makeev : roundRobinThreadIndex(0) 8*58964d0bSSergey Makeev { 9*58964d0bSSergey Makeev //query number of processor 10*58964d0bSSergey Makeev threadsCount = Max(Thread::GetNumberOfHardwareThreads() - 2, 1); 11*58964d0bSSergey Makeev 12*58964d0bSSergey Makeev if (threadsCount > MT_MAX_THREAD_COUNT) 13*58964d0bSSergey Makeev { 14*58964d0bSSergey Makeev threadsCount = MT_MAX_THREAD_COUNT; 15*58964d0bSSergey Makeev } 16*58964d0bSSergey Makeev 17*58964d0bSSergey Makeev // create fiber pool 18*58964d0bSSergey Makeev for (uint32 i = 0; i < MT_MAX_FIBERS_COUNT; i++) 19*58964d0bSSergey Makeev { 20*58964d0bSSergey Makeev FiberContext& context = fiberContext[i]; 21*58964d0bSSergey Makeev context.fiber.Create(MT_FIBER_STACK_SIZE, FiberMain, &context); 22*58964d0bSSergey Makeev availableFibers.Push( &context ); 23*58964d0bSSergey Makeev } 24*58964d0bSSergey Makeev 25*58964d0bSSergey Makeev // create worker thread pool 26*58964d0bSSergey Makeev for (uint32 i = 0; i < threadsCount; i++) 27*58964d0bSSergey Makeev { 28*58964d0bSSergey Makeev threadContext[i].taskScheduler = this; 29*58964d0bSSergey Makeev threadContext[i].thread.Start( MT_SCHEDULER_STACK_SIZE, ThreadMain, &threadContext[i] ); 30*58964d0bSSergey Makeev } 31*58964d0bSSergey Makeev } 32*58964d0bSSergey Makeev 33*58964d0bSSergey Makeev TaskScheduler::~TaskScheduler() 34*58964d0bSSergey Makeev { 35*58964d0bSSergey Makeev for (uint32 i = 0; i < threadsCount; i++) 36*58964d0bSSergey Makeev { 37*58964d0bSSergey Makeev threadContext[i].state.Set(internal::ThreadState::EXIT); 38*58964d0bSSergey Makeev threadContext[i].hasNewTasksEvent.Signal(); 39*58964d0bSSergey Makeev } 40*58964d0bSSergey Makeev 41*58964d0bSSergey Makeev for (uint32 i = 0; i < threadsCount; i++) 42*58964d0bSSergey Makeev { 43*58964d0bSSergey Makeev threadContext[i].thread.Stop(); 44*58964d0bSSergey Makeev } 45*58964d0bSSergey Makeev } 46*58964d0bSSergey Makeev 47*58964d0bSSergey Makeev FiberContext* TaskScheduler::RequestFiberContext(internal::GroupedTask& task) 48*58964d0bSSergey Makeev { 49*58964d0bSSergey Makeev FiberContext *fiberContext = task.awaitingFiber; 50*58964d0bSSergey Makeev if (fiberContext) 51*58964d0bSSergey Makeev { 52*58964d0bSSergey Makeev task.awaitingFiber = nullptr; 53*58964d0bSSergey Makeev return fiberContext; 54*58964d0bSSergey Makeev } 55*58964d0bSSergey Makeev 56*58964d0bSSergey Makeev if (!availableFibers.TryPop(fiberContext)) 57*58964d0bSSergey Makeev { 58*58964d0bSSergey Makeev ASSERT(false, "Fibers pool is empty"); 59*58964d0bSSergey Makeev } 60*58964d0bSSergey Makeev 61*58964d0bSSergey Makeev fiberContext->currentTask = task.desc; 62*58964d0bSSergey Makeev fiberContext->currentGroup = task.group; 63*58964d0bSSergey Makeev fiberContext->parentFiber = task.parentFiber; 64*58964d0bSSergey Makeev return fiberContext; 65*58964d0bSSergey Makeev } 66*58964d0bSSergey Makeev 67*58964d0bSSergey Makeev void TaskScheduler::ReleaseFiberContext(FiberContext* fiberContext) 68*58964d0bSSergey Makeev { 69*58964d0bSSergey Makeev ASSERT(fiberContext != nullptr, "Can't release nullptr Fiber"); 70*58964d0bSSergey Makeev fiberContext->Reset(); 71*58964d0bSSergey Makeev availableFibers.Push(fiberContext); 72*58964d0bSSergey Makeev } 73*58964d0bSSergey Makeev 74*58964d0bSSergey Makeev FiberContext* TaskScheduler::ExecuteTask(internal::ThreadContext& threadContext, FiberContext* fiberContext) 75*58964d0bSSergey Makeev { 76*58964d0bSSergey Makeev ASSERT(threadContext.thread.IsCurrentThread(), "Thread context sanity check failed"); 77*58964d0bSSergey Makeev 78*58964d0bSSergey Makeev ASSERT(fiberContext, "Invalid fiber context"); 79*58964d0bSSergey Makeev ASSERT(fiberContext->currentTask.IsValid(), "Invalid task"); 80*58964d0bSSergey Makeev ASSERT(fiberContext->currentGroup < TaskGroup::COUNT, "Invalid task group"); 81*58964d0bSSergey Makeev 82*58964d0bSSergey Makeev // Set actual thread context to fiber 83*58964d0bSSergey Makeev fiberContext->SetThreadContext(&threadContext); 84*58964d0bSSergey Makeev 85*58964d0bSSergey Makeev // Update task status 86*58964d0bSSergey Makeev fiberContext->SetStatus(FiberTaskStatus::RUNNED); 87*58964d0bSSergey Makeev 88*58964d0bSSergey Makeev ASSERT(fiberContext->GetThreadContext()->thread.IsCurrentThread(), "Thread context sanity check failed"); 89*58964d0bSSergey Makeev 90*58964d0bSSergey Makeev // Run current task code 91*58964d0bSSergey Makeev Fiber::SwitchTo(threadContext.schedulerFiber, fiberContext->fiber); 92*58964d0bSSergey Makeev 93*58964d0bSSergey Makeev // If task was done 94*58964d0bSSergey Makeev FiberTaskStatus::Type taskStatus = fiberContext->GetStatus(); 95*58964d0bSSergey Makeev if (taskStatus == FiberTaskStatus::FINISHED) 96*58964d0bSSergey Makeev { 97*58964d0bSSergey Makeev TaskGroup::Type taskGroup = fiberContext->currentGroup; 98*58964d0bSSergey Makeev ASSERT(taskGroup < TaskGroup::COUNT, "Invalid group."); 99*58964d0bSSergey Makeev 100*58964d0bSSergey Makeev // Update group status 101*58964d0bSSergey Makeev int groupTaskCount = threadContext.taskScheduler->groupStats[taskGroup].inProgressTaskCount.Dec(); 102*58964d0bSSergey Makeev ASSERT(groupTaskCount >= 0, "Sanity check failed!"); 103*58964d0bSSergey Makeev if (groupTaskCount == 0) 104*58964d0bSSergey Makeev { 105*58964d0bSSergey Makeev // Restore awaiting tasks 106*58964d0bSSergey Makeev threadContext.RestoreAwaitingTasks(taskGroup); 107*58964d0bSSergey Makeev threadContext.taskScheduler->groupStats[taskGroup].allDoneEvent.Signal(); 108*58964d0bSSergey Makeev } 109*58964d0bSSergey Makeev 110*58964d0bSSergey Makeev // Update total task count 111*58964d0bSSergey Makeev groupTaskCount = threadContext.taskScheduler->allGroupStats.inProgressTaskCount.Dec(); 112*58964d0bSSergey Makeev ASSERT(groupTaskCount >= 0, "Sanity check failed!"); 113*58964d0bSSergey Makeev if (groupTaskCount == 0) 114*58964d0bSSergey Makeev { 115*58964d0bSSergey Makeev // Notify all tasks in all group finished 116*58964d0bSSergey Makeev threadContext.taskScheduler->allGroupStats.allDoneEvent.Signal(); 117*58964d0bSSergey Makeev } 118*58964d0bSSergey Makeev 119*58964d0bSSergey Makeev FiberContext* parentFiberContext = fiberContext->parentFiber; 120*58964d0bSSergey Makeev if (parentFiberContext != nullptr) 121*58964d0bSSergey Makeev { 122*58964d0bSSergey Makeev int childrenFibersCount = parentFiberContext->childrenFibersCount.Dec(); 123*58964d0bSSergey Makeev ASSERT(childrenFibersCount >= 0, "Sanity check failed!"); 124*58964d0bSSergey Makeev 125*58964d0bSSergey Makeev if (childrenFibersCount == 0) 126*58964d0bSSergey Makeev { 127*58964d0bSSergey Makeev // This is a last subtask. Restore parent task 128*58964d0bSSergey Makeev #if FIBER_DEBUG 129*58964d0bSSergey Makeev 130*58964d0bSSergey Makeev int ownerThread = parentFiberContext->fiber.GetOwnerThread(); 131*58964d0bSSergey Makeev FiberTaskStatus::Type parentTaskStatus = parentFiberContext->GetStatus(); 132*58964d0bSSergey Makeev internal::ThreadContext * parentThreadContext = parentFiberContext->GetThreadContext(); 133*58964d0bSSergey Makeev int fiberUsageCounter = parentFiberContext->fiber.GetUsageCounter(); 134*58964d0bSSergey Makeev ASSERT(fiberUsageCounter == 0, "Parent fiber in invalid state"); 135*58964d0bSSergey Makeev 136*58964d0bSSergey Makeev ownerThread; 137*58964d0bSSergey Makeev parentTaskStatus; 138*58964d0bSSergey Makeev parentThreadContext; 139*58964d0bSSergey Makeev fiberUsageCounter; 140*58964d0bSSergey Makeev #endif 141*58964d0bSSergey Makeev 142*58964d0bSSergey Makeev ASSERT(threadContext.thread.IsCurrentThread(), "Thread context sanity check failed"); 143*58964d0bSSergey Makeev ASSERT(parentFiberContext->GetThreadContext() == nullptr, "Inactive parent should not have a valid thread context"); 144*58964d0bSSergey Makeev 145*58964d0bSSergey Makeev // WARNING!! Thread context can changed here! Set actual current thread context. 146*58964d0bSSergey Makeev parentFiberContext->SetThreadContext(&threadContext); 147*58964d0bSSergey Makeev 148*58964d0bSSergey Makeev ASSERT(parentFiberContext->GetThreadContext()->thread.IsCurrentThread(), "Thread context sanity check failed"); 149*58964d0bSSergey Makeev 150*58964d0bSSergey Makeev // All subtasks is done. 151*58964d0bSSergey Makeev // Exiting and return parent fiber to scheduler 152*58964d0bSSergey Makeev return parentFiberContext; 153*58964d0bSSergey Makeev } else 154*58964d0bSSergey Makeev { 155*58964d0bSSergey Makeev // Other subtasks still exist 156*58964d0bSSergey Makeev // Exiting 157*58964d0bSSergey Makeev return nullptr; 158*58964d0bSSergey Makeev } 159*58964d0bSSergey Makeev } else 160*58964d0bSSergey Makeev { 161*58964d0bSSergey Makeev // Task is finished and no parent task 162*58964d0bSSergey Makeev // Exiting 163*58964d0bSSergey Makeev return nullptr; 164*58964d0bSSergey Makeev } 165*58964d0bSSergey Makeev } 166*58964d0bSSergey Makeev 167*58964d0bSSergey Makeev ASSERT(taskStatus != FiberTaskStatus::RUNNED, "Incorrect task status") 168*58964d0bSSergey Makeev return nullptr; 169*58964d0bSSergey Makeev } 170*58964d0bSSergey Makeev 171*58964d0bSSergey Makeev 172*58964d0bSSergey Makeev void TaskScheduler::FiberMain(void* userData) 173*58964d0bSSergey Makeev { 174*58964d0bSSergey Makeev FiberContext& fiberContext = *(FiberContext*)(userData); 175*58964d0bSSergey Makeev for(;;) 176*58964d0bSSergey Makeev { 177*58964d0bSSergey Makeev ASSERT(fiberContext.currentTask.IsValid(), "Invalid task in fiber context"); 178*58964d0bSSergey Makeev ASSERT(fiberContext.currentGroup < TaskGroup::COUNT, "Invalid task group"); 179*58964d0bSSergey Makeev ASSERT(fiberContext.GetThreadContext(), "Invalid thread context"); 180*58964d0bSSergey Makeev ASSERT(fiberContext.GetThreadContext()->thread.IsCurrentThread(), "Thread context sanity check failed"); 181*58964d0bSSergey Makeev 182*58964d0bSSergey Makeev fiberContext.currentTask.taskFunc( fiberContext, fiberContext.currentTask.userData ); 183*58964d0bSSergey Makeev 184*58964d0bSSergey Makeev fiberContext.SetStatus(FiberTaskStatus::FINISHED); 185*58964d0bSSergey Makeev 186*58964d0bSSergey Makeev Fiber::SwitchTo(fiberContext.fiber, fiberContext.GetThreadContext()->schedulerFiber); 187*58964d0bSSergey Makeev } 188*58964d0bSSergey Makeev 189*58964d0bSSergey Makeev } 190*58964d0bSSergey Makeev 191*58964d0bSSergey Makeev 192*58964d0bSSergey Makeev void TaskScheduler::ThreadMain( void* userData ) 193*58964d0bSSergey Makeev { 194*58964d0bSSergey Makeev internal::ThreadContext& context = *(internal::ThreadContext*)(userData); 195*58964d0bSSergey Makeev ASSERT(context.taskScheduler, "Task scheduler must be not null!"); 196*58964d0bSSergey Makeev context.schedulerFiber.CreateFromThread(context.thread); 197*58964d0bSSergey Makeev 198*58964d0bSSergey Makeev while(context.state.Get() != internal::ThreadState::EXIT) 199*58964d0bSSergey Makeev { 200*58964d0bSSergey Makeev internal::GroupedTask task; 201*58964d0bSSergey Makeev if (context.queue.TryPop(task)) 202*58964d0bSSergey Makeev { 203*58964d0bSSergey Makeev // There is a new task 204*58964d0bSSergey Makeev FiberContext* fiberContext = context.taskScheduler->RequestFiberContext(task); 205*58964d0bSSergey Makeev ASSERT(fiberContext, "Can't get execution context from pool"); 206*58964d0bSSergey Makeev ASSERT(fiberContext->currentTask.IsValid(), "Sanity check failed"); 207*58964d0bSSergey Makeev 208*58964d0bSSergey Makeev while(fiberContext) 209*58964d0bSSergey Makeev { 210*58964d0bSSergey Makeev // prevent invalid fiber resume from child tasks, before ExecuteTask is done 211*58964d0bSSergey Makeev fiberContext->childrenFibersCount.Inc(); 212*58964d0bSSergey Makeev 213*58964d0bSSergey Makeev FiberContext* parentFiber = ExecuteTask(context, fiberContext); 214*58964d0bSSergey Makeev 215*58964d0bSSergey Makeev FiberTaskStatus::Type taskStatus = fiberContext->GetStatus(); 216*58964d0bSSergey Makeev 217*58964d0bSSergey Makeev //release guard 218*58964d0bSSergey Makeev int childrenFibersCount = fiberContext->childrenFibersCount.Dec(); 219*58964d0bSSergey Makeev 220*58964d0bSSergey Makeev // Can drop fiber context - task is finished 221*58964d0bSSergey Makeev if (taskStatus == FiberTaskStatus::FINISHED) 222*58964d0bSSergey Makeev { 223*58964d0bSSergey Makeev ASSERT( childrenFibersCount == 0, "Sanity check failed"); 224*58964d0bSSergey Makeev 225*58964d0bSSergey Makeev context.taskScheduler->ReleaseFiberContext(fiberContext); 226*58964d0bSSergey Makeev 227*58964d0bSSergey Makeev // If parent fiber is exist transfer flow control to parent fiber, if parent fiber is null, exit 228*58964d0bSSergey Makeev fiberContext = parentFiber; 229*58964d0bSSergey Makeev } else 230*58964d0bSSergey Makeev { 231*58964d0bSSergey Makeev ASSERT( childrenFibersCount >= 0, "Sanity check failed"); 232*58964d0bSSergey Makeev 233*58964d0bSSergey Makeev // No subtasks here and status is not finished, this mean all subtasks already finished before parent return from ExecuteTask 234*58964d0bSSergey Makeev if (childrenFibersCount == 0) 235*58964d0bSSergey Makeev { 236*58964d0bSSergey Makeev ASSERT(parentFiber == nullptr, "Sanity check failed"); 237*58964d0bSSergey Makeev } else 238*58964d0bSSergey Makeev { 239*58964d0bSSergey Makeev // If subtasks still exist, drop current task execution. task will be resumed when last subtask finished 240*58964d0bSSergey Makeev break; 241*58964d0bSSergey Makeev } 242*58964d0bSSergey Makeev 243*58964d0bSSergey Makeev // If task is in await state drop execution. task will be resumed when RestoreAwaitingTasks called 244*58964d0bSSergey Makeev if (taskStatus == FiberTaskStatus::AWAITING_GROUP) 245*58964d0bSSergey Makeev { 246*58964d0bSSergey Makeev break; 247*58964d0bSSergey Makeev } 248*58964d0bSSergey Makeev } 249*58964d0bSSergey Makeev } //while(fiberContext) 250*58964d0bSSergey Makeev 251*58964d0bSSergey Makeev } else 252*58964d0bSSergey Makeev { 253*58964d0bSSergey Makeev // Queue is empty 254*58964d0bSSergey Makeev // TODO: can try to steal tasks from other threads 255*58964d0bSSergey Makeev context.hasNewTasksEvent.Wait(2000); 256*58964d0bSSergey Makeev } 257*58964d0bSSergey Makeev 258*58964d0bSSergey Makeev } // main thread loop 259*58964d0bSSergey Makeev } 260*58964d0bSSergey Makeev 261*58964d0bSSergey Makeev void TaskScheduler::RunTasksImpl(fixed_array<internal::TaskBucket>& buckets, FiberContext * parentFiber, bool restoredFromAwaitState) 262*58964d0bSSergey Makeev { 263*58964d0bSSergey Makeev // Reset counter to initial value 264*58964d0bSSergey Makeev int taskCountInGroup[TaskGroup::COUNT]; 265*58964d0bSSergey Makeev for (size_t i = 0; i < TaskGroup::COUNT; ++i) 266*58964d0bSSergey Makeev { 267*58964d0bSSergey Makeev taskCountInGroup[i] = 0; 268*58964d0bSSergey Makeev } 269*58964d0bSSergey Makeev 270*58964d0bSSergey Makeev // Set parent fiber pointer 271*58964d0bSSergey Makeev // Calculate the number of tasks per group 272*58964d0bSSergey Makeev // Calculate total number of tasks 273*58964d0bSSergey Makeev size_t count = 0; 274*58964d0bSSergey Makeev for (size_t i = 0; i < buckets.size(); ++i) 275*58964d0bSSergey Makeev { 276*58964d0bSSergey Makeev internal::TaskBucket& bucket = buckets[i]; 277*58964d0bSSergey Makeev for (size_t taskIndex = 0; taskIndex < bucket.count; taskIndex++) 278*58964d0bSSergey Makeev { 279*58964d0bSSergey Makeev internal::GroupedTask & task = bucket.tasks[taskIndex]; 280*58964d0bSSergey Makeev 281*58964d0bSSergey Makeev ASSERT(task.group < TaskGroup::COUNT, "Invalid group."); 282*58964d0bSSergey Makeev 283*58964d0bSSergey Makeev task.parentFiber = parentFiber; 284*58964d0bSSergey Makeev taskCountInGroup[task.group]++; 285*58964d0bSSergey Makeev } 286*58964d0bSSergey Makeev count += bucket.count; 287*58964d0bSSergey Makeev } 288*58964d0bSSergey Makeev 289*58964d0bSSergey Makeev // Increments child fibers count on parent fiber 290*58964d0bSSergey Makeev if (parentFiber) 291*58964d0bSSergey Makeev { 292*58964d0bSSergey Makeev parentFiber->childrenFibersCount.Add((uint32)count); 293*58964d0bSSergey Makeev } 294*58964d0bSSergey Makeev 295*58964d0bSSergey Makeev if (restoredFromAwaitState == false) 296*58964d0bSSergey Makeev { 297*58964d0bSSergey Makeev // Increments all task in progress counter 298*58964d0bSSergey Makeev allGroupStats.allDoneEvent.Reset(); 299*58964d0bSSergey Makeev allGroupStats.inProgressTaskCount.Add((uint32)count); 300*58964d0bSSergey Makeev 301*58964d0bSSergey Makeev // Increments task in progress counters (per group) 302*58964d0bSSergey Makeev for (size_t i = 0; i < TaskGroup::COUNT; ++i) 303*58964d0bSSergey Makeev { 304*58964d0bSSergey Makeev int groupTaskCount = taskCountInGroup[i]; 305*58964d0bSSergey Makeev if (groupTaskCount > 0) 306*58964d0bSSergey Makeev { 307*58964d0bSSergey Makeev groupStats[i].allDoneEvent.Reset(); 308*58964d0bSSergey Makeev groupStats[i].inProgressTaskCount.Add((uint32)groupTaskCount); 309*58964d0bSSergey Makeev } 310*58964d0bSSergey Makeev } 311*58964d0bSSergey Makeev } else 312*58964d0bSSergey Makeev { 313*58964d0bSSergey Makeev // If task's restored from await state, counters already in correct state 314*58964d0bSSergey Makeev } 315*58964d0bSSergey Makeev 316*58964d0bSSergey Makeev // Add to thread queue 317*58964d0bSSergey Makeev for (size_t i = 0; i < buckets.size(); ++i) 318*58964d0bSSergey Makeev { 319*58964d0bSSergey Makeev int bucketIndex = roundRobinThreadIndex.Inc() % threadsCount; 320*58964d0bSSergey Makeev internal::ThreadContext & context = threadContext[bucketIndex]; 321*58964d0bSSergey Makeev 322*58964d0bSSergey Makeev internal::TaskBucket& bucket = buckets[i]; 323*58964d0bSSergey Makeev 324*58964d0bSSergey Makeev context.queue.PushRange(bucket.tasks, bucket.count); 325*58964d0bSSergey Makeev context.hasNewTasksEvent.Signal(); 326*58964d0bSSergey Makeev } 327*58964d0bSSergey Makeev } 328*58964d0bSSergey Makeev 329*58964d0bSSergey Makeev bool TaskScheduler::WaitGroup(TaskGroup::Type group, uint32 milliseconds) 330*58964d0bSSergey Makeev { 331*58964d0bSSergey Makeev VERIFY(IsWorkerThread() == false, "Can't use WaitGroup inside Task. Use FiberContext.WaitGroupAndYield() instead.", return false); 332*58964d0bSSergey Makeev 333*58964d0bSSergey Makeev return groupStats[group].allDoneEvent.Wait(milliseconds); 334*58964d0bSSergey Makeev } 335*58964d0bSSergey Makeev 336*58964d0bSSergey Makeev bool TaskScheduler::WaitAll(uint32 milliseconds) 337*58964d0bSSergey Makeev { 338*58964d0bSSergey Makeev VERIFY(IsWorkerThread() == false, "Can't use WaitAll inside Task.", return false); 339*58964d0bSSergey Makeev 340*58964d0bSSergey Makeev return allGroupStats.allDoneEvent.Wait(milliseconds); 341*58964d0bSSergey Makeev } 342*58964d0bSSergey Makeev 343*58964d0bSSergey Makeev bool TaskScheduler::IsEmpty() 344*58964d0bSSergey Makeev { 345*58964d0bSSergey Makeev for (uint32 i = 0; i < MT_MAX_THREAD_COUNT; i++) 346*58964d0bSSergey Makeev { 347*58964d0bSSergey Makeev if (!threadContext[i].queue.IsEmpty()) 348*58964d0bSSergey Makeev { 349*58964d0bSSergey Makeev return false; 350*58964d0bSSergey Makeev } 351*58964d0bSSergey Makeev } 352*58964d0bSSergey Makeev return true; 353*58964d0bSSergey Makeev } 354*58964d0bSSergey Makeev 355*58964d0bSSergey Makeev uint32 TaskScheduler::GetWorkerCount() const 356*58964d0bSSergey Makeev { 357*58964d0bSSergey Makeev return threadsCount; 358*58964d0bSSergey Makeev } 359*58964d0bSSergey Makeev 360*58964d0bSSergey Makeev bool TaskScheduler::IsWorkerThread() const 361*58964d0bSSergey Makeev { 362*58964d0bSSergey Makeev for (uint32 i = 0; i < MT_MAX_THREAD_COUNT; i++) 363*58964d0bSSergey Makeev { 364*58964d0bSSergey Makeev if (threadContext[i].thread.IsCurrentThread()) 365*58964d0bSSergey Makeev { 366*58964d0bSSergey Makeev return true; 367*58964d0bSSergey Makeev } 368*58964d0bSSergey Makeev } 369*58964d0bSSergey Makeev return false; 370*58964d0bSSergey Makeev } 371*58964d0bSSergey Makeev 372*58964d0bSSergey Makeev } 373