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.
22b7b54a39SSergey Makeev
23b7b54a39SSergey Makeevnamespace MT
24b7b54a39SSergey Makeev{
25b7b54a39SSergey Makeev
26b7b54a39SSergey Makeev	namespace internal
27b7b54a39SSergey Makeev	{
28f4db079dSs.makeev		//generic template
29b7b54a39SSergey Makeev		template<class T>
30f4db079dSs.makeev		inline internal::GroupedTask GetGroupedTask(TaskGroup group, const T * src)
31b7b54a39SSergey Makeev		{
32b23bdf5aSs.makeev_local			internal::TaskDesc desc(T::TaskEntryPoint, src, T::GetStackRequirements(), T::GetTaskPriority() );
33a1626843SSergey Makeev#ifdef MT_INSTRUMENTED_BUILD
34a1626843SSergey Makeev			desc.debugID = T::GetDebugID();
354a90b4a6SSergey Makeev			desc.debugColor = T::GetDebugColor();
36a1626843SSergey Makeev#endif
37b7b54a39SSergey Makeev			return internal::GroupedTask( desc, group );
38b7b54a39SSergey Makeev		}
39b7b54a39SSergey Makeev
40b7b54a39SSergey Makeev		//template specialization for FiberContext*
41b7b54a39SSergey Makeev		template<>
42f4db079dSs.makeev		inline internal::GroupedTask GetGroupedTask(TaskGroup group, FiberContext* const * src)
43b7b54a39SSergey Makeev		{
442e846c40SSergey Makeev			MT_USED_IN_ASSERT(group);
45754cb997SSergey Makeev			MT_ASSERT(group == TaskGroup::ASSIGN_FROM_CONTEXT, "Group must be assigned from context");
46b7b54a39SSergey Makeev			FiberContext* fiberContext = *src;
47f4db079dSs.makeev			MT_ASSERT(fiberContext->currentTask.stackRequirements == fiberContext->stackRequirements, "Sanity check failed");
48b7b54a39SSergey Makeev			internal::GroupedTask groupedTask( fiberContext->currentTask, fiberContext->currentGroup );
49b7b54a39SSergey Makeev			groupedTask.awaitingFiber = fiberContext;
50b7b54a39SSergey Makeev			return groupedTask;
51b7b54a39SSergey Makeev		}
52b7b54a39SSergey Makeev
53f4db079dSs.makeev		//template specialization for TaskHandle
5458d12dadSSergey Makeev		template<>
55f4db079dSs.makeev		inline internal::GroupedTask GetGroupedTask(TaskGroup group, const MT::TaskHandle * src)
5658d12dadSSergey Makeev		{
57e455330fSSergey Makeev			MT_ASSERT(src->IsValid(), "Invalid task handle!");
5858d12dadSSergey Makeev			const internal::TaskDesc & desc = src->GetDesc();
5958d12dadSSergey Makeev			return internal::GroupedTask( desc, group );
6058d12dadSSergey Makeev		}
6158d12dadSSergey Makeev
6258d12dadSSergey Makeev
63b7b54a39SSergey Makeev
64b7b54a39SSergey Makeev		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
65b7b54a39SSergey Makeev		// Distributes task to threads:
66b7b54a39SSergey Makeev		// | Task1 | Task2 | Task3 | Task4 | Task5 | Task6 |
67b7b54a39SSergey Makeev		// ThreadCount = 4
68b7b54a39SSergey Makeev		// Thread0: Task1, Task5
69b7b54a39SSergey Makeev		// Thread1: Task2, Task6
70b7b54a39SSergey Makeev		// Thread2: Task3
71b7b54a39SSergey Makeev		// Thread3: Task4
72b7b54a39SSergey Makeev		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
73b7b54a39SSergey Makeev		template<class TTask>
74806ef292SSergey Makeev		inline bool DistibuteDescriptions(TaskGroup group, TTask* taskArray, ArrayView<internal::GroupedTask>& descriptions, ArrayView<internal::TaskBucket>& buckets)
75b7b54a39SSergey Makeev		{
76b7b54a39SSergey Makeev			size_t index = 0;
77b7b54a39SSergey Makeev
78a101e543SSergey Makeev			for (size_t bucketIndex = 0; (bucketIndex < buckets.Size()) && (index < descriptions.Size()); ++bucketIndex)
79b7b54a39SSergey Makeev			{
80b7b54a39SSergey Makeev				size_t bucketStartIndex = index;
81b7b54a39SSergey Makeev
82a101e543SSergey Makeev				for (size_t i = bucketIndex; i < descriptions.Size(); i += buckets.Size())
83b7b54a39SSergey Makeev				{
84a1626843SSergey Makeev					descriptions[index] = GetGroupedTask(group, &taskArray[i]);
85a1626843SSergey Makeev					index++;
86b7b54a39SSergey Makeev				}
87b7b54a39SSergey Makeev
88b7b54a39SSergey Makeev				buckets[bucketIndex] = internal::TaskBucket(&descriptions[bucketStartIndex], index - bucketStartIndex);
89b7b54a39SSergey Makeev			}
90b7b54a39SSergey Makeev
9134a394c3SSergey Makeev			MT_ASSERT(index == descriptions.Size(), "Sanity check");
92b7b54a39SSergey Makeev			return index > 0;
93b7b54a39SSergey Makeev		}
94b7b54a39SSergey Makeev
95b7b54a39SSergey Makeev	}
96b7b54a39SSergey Makeev
97b7b54a39SSergey Makeev
98b7b54a39SSergey Makeev
99b7b54a39SSergey Makeev
100b7b54a39SSergey Makeev
101b7b54a39SSergey Makeev	template<class TTask>
102f4db079dSs.makeev	void TaskScheduler::RunAsync(TaskGroup group, const TTask* taskArray, uint32 taskCount)
103b7b54a39SSergey Makeev	{
104*4dcd71e3Ss.makeev_local		MT_ASSERT(taskCount < (internal::TASK_BUFFER_CAPACITY - 1), "Too many tasks per one Run.");
10534a394c3SSergey Makeev		MT_ASSERT(!IsWorkerThread(), "Can't use RunAsync inside Task. Use FiberContext.RunAsync() instead.");
106b7b54a39SSergey Makeev
1073d930776Ss.makeev_local		uint32 bytesCountForGroupedTasks = sizeof(internal::GroupedTask) * taskCount;
1083d930776Ss.makeev_local		ArrayView<internal::GroupedTask> buffer( MT_ALLOCATE_ON_STACK( bytesCountForGroupedTasks ), taskCount );
109b7b54a39SSergey Makeev
110a23fd933SSergey Makeev		uint32 bucketCount = MT::Min((uint32)GetWorkersCount(), taskCount);
1113d930776Ss.makeev_local		uint32 bytesCountForTaskBuckets = sizeof(internal::TaskBucket) * bucketCount;
1123d930776Ss.makeev_local		ArrayView<internal::TaskBucket> buckets( MT_ALLOCATE_ON_STACK( bytesCountForTaskBuckets ), bucketCount );
113b7b54a39SSergey Makeev
114b7b54a39SSergey Makeev		internal::DistibuteDescriptions(group, taskArray, buffer, buckets);
115b7b54a39SSergey Makeev		RunTasksImpl(buckets, nullptr, false);
116b7b54a39SSergey Makeev	}
117b7b54a39SSergey Makeev
118b7b54a39SSergey Makeev}
119