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