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 
262b4df162SSergey Makeev 
272b4df162SSergey Makeev 
282b4df162SSergey Makeev 
292b4df162SSergey Makeev 
302b4df162SSergey Makeev 
3158964d0bSSergey Makeev namespace MT
3258964d0bSSergey Makeev {
3358964d0bSSergey Makeev 	namespace internal
3458964d0bSSergey Makeev 	{
3558964d0bSSergey Makeev 		static const size_t TASK_BUFFER_CAPACITY = 4096;
3658964d0bSSergey Makeev 
372b4df162SSergey Makeev 		// Prime numbers for linear congruential generator seed
382b4df162SSergey Makeev 		static const uint32 primeNumbers[] = {
392b4df162SSergey Makeev 			128473, 135349, 159499, 173839, 209213, 241603, 292709, 314723,
402b4df162SSergey Makeev 			343943, 389299, 419473, 465169, 518327, 649921, 748271, 851087,
412b4df162SSergey Makeev 			862171, 974551, 1002973, 1034639, 1096289, 1153123, 1251037, 1299269,
422b4df162SSergey Makeev 			1272941, 1252151, 1231091, 1206761, 1185469, 1169933, 1141351, 1011583 };
432b4df162SSergey Makeev 
442b4df162SSergey Makeev 		uint32 GetPrimeNumber(uint32 index)
452b4df162SSergey Makeev 		{
462b4df162SSergey Makeev 			return primeNumbers[index % ARRAY_SIZE(primeNumbers)];
472b4df162SSergey Makeev 		}
482b4df162SSergey Makeev 
492b4df162SSergey Makeev 
502b4df162SSergey Makeev 
5158964d0bSSergey Makeev 		ThreadContext::ThreadContext()
5258964d0bSSergey Makeev 			: lastActiveFiberContext(nullptr)
5358964d0bSSergey Makeev 			, taskScheduler(nullptr)
5458964d0bSSergey Makeev 			, hasNewTasksEvent(EventReset::AUTOMATIC, true)
5558964d0bSSergey Makeev 			, state(ThreadState::ALIVE)
5658964d0bSSergey Makeev 			, descBuffer(TASK_BUFFER_CAPACITY)
572b4df162SSergey Makeev 			, workerIndex(0)
5858964d0bSSergey Makeev 		{
5958964d0bSSergey Makeev 		}
6058964d0bSSergey Makeev 
6158964d0bSSergey Makeev 		ThreadContext::~ThreadContext()
6258964d0bSSergey Makeev 		{
6358964d0bSSergey Makeev 		}
6458964d0bSSergey Makeev 
652b4df162SSergey Makeev 		void ThreadContext::SetThreadIndex(uint32 threadIndex)
662b4df162SSergey Makeev 		{
672b4df162SSergey Makeev 			workerIndex = threadIndex;
682b4df162SSergey Makeev 			random.SetSeed( GetPrimeNumber(threadIndex) );
692b4df162SSergey Makeev 		}
702b4df162SSergey Makeev 
7158964d0bSSergey Makeev 		void ThreadContext::RestoreAwaitingTasks(TaskGroup::Type taskGroup)
7258964d0bSSergey Makeev 		{
7358964d0bSSergey Makeev 			ASSERT(taskScheduler, "Invalid Task Scheduler");
7458964d0bSSergey Makeev 			ASSERT(taskScheduler->IsWorkerThread(), "Can't use RunAsync outside Task. Use TaskScheduler.RunAsync() instead.");
7558964d0bSSergey Makeev 
7658964d0bSSergey Makeev 			ConcurrentQueueLIFO<FiberContext*> & groupQueue = taskScheduler->waitTaskQueues[taskGroup];
7758964d0bSSergey Makeev 
7858964d0bSSergey Makeev 			if (groupQueue.IsEmpty())
7958964d0bSSergey Makeev 			{
8058964d0bSSergey Makeev 				return;
8158964d0bSSergey Makeev 			}
8258964d0bSSergey Makeev 
8358964d0bSSergey Makeev 			//copy awaiting tasks list to stack
84a101e543SSergey Makeev 			StackArray<FiberContext*, MT_MAX_FIBERS_COUNT> groupQueueCopy(MT_MAX_FIBERS_COUNT, nullptr);
85a101e543SSergey Makeev 			size_t taskCount = groupQueue.PopAll(groupQueueCopy.Begin(), groupQueueCopy.Size());
8658964d0bSSergey Makeev 
87a101e543SSergey Makeev 			WrapperArray<internal::GroupedTask> buffer(&descBuffer.front(), taskCount);
8858964d0bSSergey Makeev 
8958964d0bSSergey Makeev 			TaskScheduler & scheduler = *(taskScheduler);
9058964d0bSSergey Makeev 			size_t bucketCount = Min((size_t)scheduler.GetWorkerCount(), taskCount);
91a101e543SSergey Makeev 			WrapperArray<internal::TaskBucket>	buckets(ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);
9258964d0bSSergey Makeev 
93a101e543SSergey Makeev 			internal::DistibuteDescriptions(TaskGroup::GROUP_UNDEFINED, groupQueueCopy.Begin(), buffer, buckets);
9458964d0bSSergey Makeev 			scheduler.RunTasksImpl(buckets, nullptr, true);
9558964d0bSSergey Makeev 		}
9658964d0bSSergey Makeev 
97*8112dedfSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD
98*8112dedfSSergey Makeev 
99*8112dedfSSergey Makeev 		void ThreadContext::NotifyTaskFinished(const internal::TaskDesc & desc)
100*8112dedfSSergey Makeev 		{
101*8112dedfSSergey Makeev 			desc;
102*8112dedfSSergey Makeev 
103*8112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
104*8112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_DONE;
105*8112dedfSSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds();
106*8112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
107*8112dedfSSergey Makeev 		}
108*8112dedfSSergey Makeev 
109*8112dedfSSergey Makeev 		void ThreadContext::NotifyTaskResumed(const internal::TaskDesc & desc)
110*8112dedfSSergey Makeev 		{
111*8112dedfSSergey Makeev 			desc;
112*8112dedfSSergey Makeev 
113*8112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
114*8112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_RESUME;
115*8112dedfSSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds();
116*8112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
117*8112dedfSSergey Makeev 		}
118*8112dedfSSergey Makeev 
119*8112dedfSSergey Makeev 		void ThreadContext::NotifyTaskYielded(const internal::TaskDesc & desc)
120*8112dedfSSergey Makeev 		{
121*8112dedfSSergey Makeev 			desc;
122*8112dedfSSergey Makeev 
123*8112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
124*8112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_YIELD;
125*8112dedfSSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds();
126*8112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
127*8112dedfSSergey Makeev 		}
128*8112dedfSSergey Makeev 
129*8112dedfSSergey Makeev 
130*8112dedfSSergey Makeev #endif
131*8112dedfSSergey Makeev 
13258964d0bSSergey Makeev 	}
13358964d0bSSergey Makeev 
13458964d0bSSergey Makeev }
135