1f25ce65dSSergey Makeev // The MIT License (MIT)
2f25ce65dSSergey Makeev //
3f25ce65dSSergey Makeev // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4f25ce65dSSergey Makeev //
5f25ce65dSSergey Makeev // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6f25ce65dSSergey Makeev // 	of this software and associated documentation files (the "Software"), to deal
7f25ce65dSSergey Makeev // 	in the Software without restriction, including without limitation the rights
8f25ce65dSSergey Makeev // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9f25ce65dSSergey Makeev // 	copies of the Software, and to permit persons to whom the Software is
10f25ce65dSSergey Makeev // 	furnished to do so, subject to the following conditions:
11f25ce65dSSergey Makeev //
12f25ce65dSSergey Makeev //  The above copyright notice and this permission notice shall be included in
13f25ce65dSSergey Makeev // 	all copies or substantial portions of the Software.
14f25ce65dSSergey Makeev //
15f25ce65dSSergey Makeev // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16f25ce65dSSergey Makeev // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17f25ce65dSSergey Makeev // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18f25ce65dSSergey Makeev // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19f25ce65dSSergey Makeev // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20f25ce65dSSergey Makeev // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21f25ce65dSSergey Makeev // 	THE SOFTWARE.
22f25ce65dSSergey Makeev 
2358964d0bSSergey Makeev #include <MTScheduler.h>
2458964d0bSSergey Makeev 
252b4df162SSergey Makeev 
2658964d0bSSergey Makeev namespace MT
2758964d0bSSergey Makeev {
2858964d0bSSergey Makeev 	namespace internal
2958964d0bSSergey Makeev 	{
302b4df162SSergey Makeev 		// Prime numbers for linear congruential generator seed
312b4df162SSergey Makeev 		static const uint32 primeNumbers[] = {
322b4df162SSergey Makeev 			128473, 135349, 159499, 173839, 209213, 241603, 292709, 314723,
332b4df162SSergey Makeev 			343943, 389299, 419473, 465169, 518327, 649921, 748271, 851087,
342b4df162SSergey Makeev 			862171, 974551, 1002973, 1034639, 1096289, 1153123, 1251037, 1299269,
352b4df162SSergey Makeev 			1272941, 1252151, 1231091, 1206761, 1185469, 1169933, 1141351, 1011583 };
362b4df162SSergey Makeev 
372b4df162SSergey Makeev 		uint32 GetPrimeNumber(uint32 index)
382b4df162SSergey Makeev 		{
3934a394c3SSergey Makeev 			return primeNumbers[index % MT_ARRAY_SIZE(primeNumbers)];
402b4df162SSergey Makeev 		}
412b4df162SSergey Makeev 
422b4df162SSergey Makeev 
432b4df162SSergey Makeev 
4458964d0bSSergey Makeev 		ThreadContext::ThreadContext()
4558964d0bSSergey Makeev 			: lastActiveFiberContext(nullptr)
4658964d0bSSergey Makeev 			, taskScheduler(nullptr)
4758964d0bSSergey Makeev 			, hasNewTasksEvent(EventReset::AUTOMATIC, true)
4858964d0bSSergey Makeev 			, state(ThreadState::ALIVE)
492b4df162SSergey Makeev 			, workerIndex(0)
5058964d0bSSergey Makeev 		{
51d6661c78SSergey Makeev 			 descBuffer = Memory::Alloc( sizeof(internal::GroupedTask) * TASK_BUFFER_CAPACITY );
5258964d0bSSergey Makeev 		}
5358964d0bSSergey Makeev 
5458964d0bSSergey Makeev 		ThreadContext::~ThreadContext()
5558964d0bSSergey Makeev 		{
56d6661c78SSergey Makeev 			Memory::Free(descBuffer);
57d6661c78SSergey Makeev 			descBuffer = nullptr;
5858964d0bSSergey Makeev 		}
5958964d0bSSergey Makeev 
602b4df162SSergey Makeev 		void ThreadContext::SetThreadIndex(uint32 threadIndex)
612b4df162SSergey Makeev 		{
622b4df162SSergey Makeev 			workerIndex = threadIndex;
632b4df162SSergey Makeev 			random.SetSeed( GetPrimeNumber(threadIndex) );
642b4df162SSergey Makeev 		}
652b4df162SSergey Makeev 
66806ef292SSergey Makeev 		void ThreadContext::RestoreAwaitingTasks(TaskGroup taskGroup)
6758964d0bSSergey Makeev 		{
6834a394c3SSergey Makeev 			MT_ASSERT(taskScheduler, "Invalid Task Scheduler");
6934a394c3SSergey Makeev 			MT_ASSERT(taskScheduler->IsWorkerThread(), "Can't use RunAsync outside Task. Use TaskScheduler.RunAsync() instead.");
7058964d0bSSergey Makeev 
71806ef292SSergey Makeev 			TaskScheduler::TaskGroupDescription  & groupDesc = taskScheduler->GetGroupDesc(taskGroup);
72806ef292SSergey Makeev 			ConcurrentQueueLIFO<FiberContext*> & groupQueue = groupDesc.GetWaitQueue();
7358964d0bSSergey Makeev 
7458964d0bSSergey Makeev 			if (groupQueue.IsEmpty())
7558964d0bSSergey Makeev 			{
7658964d0bSSergey Makeev 				return;
7758964d0bSSergey Makeev 			}
7858964d0bSSergey Makeev 
7958964d0bSSergey Makeev 			//copy awaiting tasks list to stack
80a101e543SSergey Makeev 			StackArray<FiberContext*, MT_MAX_FIBERS_COUNT> groupQueueCopy(MT_MAX_FIBERS_COUNT, nullptr);
81a101e543SSergey Makeev 			size_t taskCount = groupQueue.PopAll(groupQueueCopy.Begin(), groupQueueCopy.Size());
8258964d0bSSergey Makeev 
83d6661c78SSergey Makeev 			ArrayView<internal::GroupedTask> buffer(descBuffer, taskCount);
8458964d0bSSergey Makeev 
8558964d0bSSergey Makeev 			TaskScheduler & scheduler = *(taskScheduler);
861e8563ffSSergey Makeev 			size_t bucketCount = MT::Min((size_t)scheduler.GetWorkerCount(), taskCount);
8756aa031bSSergey Makeev 			ArrayView<internal::TaskBucket>	buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);
8858964d0bSSergey Makeev 
89754cb997SSergey Makeev 			internal::DistibuteDescriptions( TaskGroup(TaskGroup::ASSIGN_FROM_CONTEXT), groupQueueCopy.Begin(), buffer, buckets);
9058964d0bSSergey Makeev 			scheduler.RunTasksImpl(buckets, nullptr, true);
9158964d0bSSergey Makeev 		}
9258964d0bSSergey Makeev 
938112dedfSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD
948112dedfSSergey Makeev 
958112dedfSSergey Makeev 		void ThreadContext::NotifyTaskFinished(const internal::TaskDesc & desc)
968112dedfSSergey Makeev 		{
970727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
980727c1f9SSergey Makeev 			{
99*4a90b4a6SSergey Makeev 				eventListener->OnTaskFinished(desc.debugColor, desc.debugID);
1000727c1f9SSergey Makeev 			}
1018112dedfSSergey Makeev 		}
1028112dedfSSergey Makeev 
1038112dedfSSergey Makeev 		void ThreadContext::NotifyTaskResumed(const internal::TaskDesc & desc)
1048112dedfSSergey Makeev 		{
1050727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
1060727c1f9SSergey Makeev 			{
107*4a90b4a6SSergey Makeev 				eventListener->OnTaskResumed(desc.debugColor, desc.debugID);
1080727c1f9SSergey Makeev 			}
1090727c1f9SSergey Makeev 
1108112dedfSSergey Makeev 		}
1118112dedfSSergey Makeev 
1128112dedfSSergey Makeev 		void ThreadContext::NotifyTaskYielded(const internal::TaskDesc & desc)
1138112dedfSSergey Makeev 		{
1140727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
1150727c1f9SSergey Makeev 			{
116*4a90b4a6SSergey Makeev 				eventListener->OnTaskYielded(desc.debugColor, desc.debugID);
1170727c1f9SSergey Makeev 			}
1188112dedfSSergey Makeev 		}
1198112dedfSSergey Makeev 
1200727c1f9SSergey Makeev 		void ThreadContext::NotifyThreadCreate(uint32 threadIndex)
121a1626843SSergey Makeev 		{
1220727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
123a1626843SSergey Makeev 			{
124*4a90b4a6SSergey Makeev 				eventListener->OnThreadCreated(threadIndex);
125a1626843SSergey Makeev 			}
1260727c1f9SSergey Makeev 		}
1270727c1f9SSergey Makeev 
1280727c1f9SSergey Makeev 		void ThreadContext::NotifyThreadStart(uint32 threadIndex)
1290727c1f9SSergey Makeev 		{
1300727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
1310727c1f9SSergey Makeev 			{
132*4a90b4a6SSergey Makeev 				eventListener->OnThreadStarted(threadIndex);
1330727c1f9SSergey Makeev 			}
1340727c1f9SSergey Makeev 		}
1350727c1f9SSergey Makeev 
1360727c1f9SSergey Makeev 		void ThreadContext::NotifyThreadStop(uint32 threadIndex)
1370727c1f9SSergey Makeev 		{
1380727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
1390727c1f9SSergey Makeev 			{
140*4a90b4a6SSergey Makeev 				eventListener->OnThreadStoped(threadIndex);
1410727c1f9SSergey Makeev 			}
1420727c1f9SSergey Makeev 		}
1430727c1f9SSergey Makeev 
144*4a90b4a6SSergey Makeev 
145*4a90b4a6SSergey Makeev 		void ThreadContext::NotifyThreadIdleBegin(uint32 threadIndex)
1460727c1f9SSergey Makeev 		{
1470727c1f9SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
1480727c1f9SSergey Makeev 			{
149*4a90b4a6SSergey Makeev 				eventListener->OnThreadIdleBegin(threadIndex);
150*4a90b4a6SSergey Makeev 			}
1510727c1f9SSergey Makeev 		}
152a1626843SSergey Makeev 
153*4a90b4a6SSergey Makeev 		void ThreadContext::NotifyThreadIdleEnd(uint32 threadIndex)
154*4a90b4a6SSergey Makeev 		{
155*4a90b4a6SSergey Makeev 			if (IProfilerEventListener* eventListener = taskScheduler->GetProfilerEventListener())
156*4a90b4a6SSergey Makeev 			{
157*4a90b4a6SSergey Makeev 				eventListener->OnThreadIdleEnd(threadIndex);
158a1626843SSergey Makeev 			}
159*4a90b4a6SSergey Makeev 		}
160*4a90b4a6SSergey Makeev 
161a1626843SSergey Makeev 
162a1626843SSergey Makeev 
1638112dedfSSergey Makeev 
1648112dedfSSergey Makeev #endif
1658112dedfSSergey Makeev 
16658964d0bSSergey Makeev 	}
16758964d0bSSergey Makeev 
16858964d0bSSergey Makeev }
169