12f083884Ss.makeev_local // The MIT License (MIT)
22f083884Ss.makeev_local //
32f083884Ss.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
42f083884Ss.makeev_local //
52f083884Ss.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
62f083884Ss.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
72f083884Ss.makeev_local // 	in the Software without restriction, including without limitation the rights
82f083884Ss.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92f083884Ss.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
102f083884Ss.makeev_local // 	furnished to do so, subject to the following conditions:
112f083884Ss.makeev_local //
122f083884Ss.makeev_local //  The above copyright notice and this permission notice shall be included in
132f083884Ss.makeev_local // 	all copies or substantial portions of the Software.
142f083884Ss.makeev_local //
152f083884Ss.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162f083884Ss.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
172f083884Ss.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
182f083884Ss.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
192f083884Ss.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
202f083884Ss.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
212f083884Ss.makeev_local // 	THE SOFTWARE.
222f083884Ss.makeev_local 
232f083884Ss.makeev_local #include "Tests.h"
242f083884Ss.makeev_local #include <UnitTest++.h>
252f083884Ss.makeev_local #include <MTScheduler.h>
262f083884Ss.makeev_local 
272f083884Ss.makeev_local 
282f083884Ss.makeev_local 
SUITE(FireAndForget)292f083884Ss.makeev_local SUITE(FireAndForget)
302f083884Ss.makeev_local {
312f083884Ss.makeev_local 
322f083884Ss.makeev_local struct SimpleTask;
332f083884Ss.makeev_local 
342f083884Ss.makeev_local typedef MT::TaskPool<SimpleTask, 512> TestPoolType;
352f083884Ss.makeev_local 
362f083884Ss.makeev_local struct SimpleTask
372f083884Ss.makeev_local {
38*b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(SimpleTask, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
392f083884Ss.makeev_local 
402f083884Ss.makeev_local 	MT::Atomic32<int32>* doCounter;
412f083884Ss.makeev_local 	MT::Atomic32<int32>* dtorCounter;
422f083884Ss.makeev_local 	TestPoolType* taskPool;
432f083884Ss.makeev_local 
442f083884Ss.makeev_local 	SimpleTask()
452f083884Ss.makeev_local 		: doCounter(nullptr)
462f083884Ss.makeev_local 		, dtorCounter(nullptr)
472f083884Ss.makeev_local 		, taskPool(nullptr)
482f083884Ss.makeev_local 	{
492f083884Ss.makeev_local 	}
502f083884Ss.makeev_local 
512f083884Ss.makeev_local 	SimpleTask(MT::Atomic32<int32>* _doCounter, MT::Atomic32<int32>* _dtorCounter, TestPoolType * _taskPool)
522f083884Ss.makeev_local 		: doCounter(_doCounter)
532f083884Ss.makeev_local 		, dtorCounter(_dtorCounter)
542f083884Ss.makeev_local 		, taskPool(_taskPool)
552f083884Ss.makeev_local 	{
562f083884Ss.makeev_local 	}
572f083884Ss.makeev_local 
582f083884Ss.makeev_local 	SimpleTask(SimpleTask&& other)
592f083884Ss.makeev_local 		: doCounter(other.doCounter)
602f083884Ss.makeev_local 		, dtorCounter(other.dtorCounter)
612f083884Ss.makeev_local 		, taskPool(other.taskPool)
622f083884Ss.makeev_local 	{
632f083884Ss.makeev_local 		other.doCounter = nullptr;
642f083884Ss.makeev_local 		other.dtorCounter = nullptr;
652f083884Ss.makeev_local 		other.taskPool = nullptr;
662f083884Ss.makeev_local 	}
672f083884Ss.makeev_local 
682f083884Ss.makeev_local 	~SimpleTask()
692f083884Ss.makeev_local 	{
702f083884Ss.makeev_local 		if (dtorCounter)
712f083884Ss.makeev_local 		{
722f083884Ss.makeev_local 			dtorCounter->IncFetch();
732f083884Ss.makeev_local 		}
742f083884Ss.makeev_local 	}
752f083884Ss.makeev_local 
762f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
772f083884Ss.makeev_local 	{
782f083884Ss.makeev_local 		if (doCounter)
792f083884Ss.makeev_local 		{
802f083884Ss.makeev_local 			doCounter->IncFetch();
812f083884Ss.makeev_local 		}
822f083884Ss.makeev_local 
832f083884Ss.makeev_local 		if (taskPool)
842f083884Ss.makeev_local 		{
852f083884Ss.makeev_local 			MT::TaskHandle handle = taskPool->Alloc(SimpleTask(doCounter, dtorCounter, nullptr));
862f083884Ss.makeev_local 
872f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &handle, 1);
882f083884Ss.makeev_local 		}
892f083884Ss.makeev_local 	}
902f083884Ss.makeev_local };
912f083884Ss.makeev_local 
922f083884Ss.makeev_local 
932f083884Ss.makeev_local 
942f083884Ss.makeev_local TEST(SingleThreadPoolTest)
952f083884Ss.makeev_local {
962f083884Ss.makeev_local 	MT::TaskPool<SimpleTask, 4> taskPool;
972f083884Ss.makeev_local 
982f083884Ss.makeev_local 	MT::TaskHandle taskHandle0 = taskPool.Alloc(SimpleTask());
992f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
1002f083884Ss.makeev_local 
1012f083884Ss.makeev_local 	MT::TaskHandle taskHandle1 = taskPool.Alloc(SimpleTask());
1022f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
1032f083884Ss.makeev_local 
1042f083884Ss.makeev_local 	MT::TaskHandle taskHandle2 = taskPool.Alloc(SimpleTask());
1052f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
1062f083884Ss.makeev_local 
1072f083884Ss.makeev_local 	MT::TaskHandle taskHandle3 = taskPool.Alloc(SimpleTask());
1082f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
1092f083884Ss.makeev_local 
1102f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
1112f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
1122f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
1132f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
1142f083884Ss.makeev_local 
1152f083884Ss.makeev_local 
1162f083884Ss.makeev_local 	// check for allocation fail
1172f083884Ss.makeev_local 	MT::TaskHandle taskHandle4 = taskPool.TryAlloc(SimpleTask());
1182f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
1192f083884Ss.makeev_local 
1202f083884Ss.makeev_local 
1212f083884Ss.makeev_local 	// check state
1222f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
1232f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
1242f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
1252f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
1262f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
1272f083884Ss.makeev_local 
1282f083884Ss.makeev_local 	// destroy pool task by handle
1292f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle0));
1302f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle1));
1312f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle2));
1322f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle3));
1332f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle4));
1342f083884Ss.makeev_local 
1352f083884Ss.makeev_local 	// check for double destroy
1362f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle0));
1372f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle3));
1382f083884Ss.makeev_local 
1392f083884Ss.makeev_local 	MT::TaskHandle taskHandle5 = taskPool.Alloc(SimpleTask());
1402f083884Ss.makeev_local 
1412f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle0.IsValid());
1422f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle1.IsValid());
1432f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle2.IsValid());
1442f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle3.IsValid());
1452f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
1462f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle5.IsValid());
1472f083884Ss.makeev_local }
1482f083884Ss.makeev_local 
1492f083884Ss.makeev_local 
1502f083884Ss.makeev_local struct ThreadTest
1512f083884Ss.makeev_local {
152*b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(ThreadTest, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
1532f083884Ss.makeev_local 
1542f083884Ss.makeev_local 	TestPoolType * taskPool;
1552f083884Ss.makeev_local 
1562f083884Ss.makeev_local 	void Do(MT::FiberContext&)
1572f083884Ss.makeev_local 	{
1582f083884Ss.makeev_local 		for (int i = 0; i < 20000; i++)
1592f083884Ss.makeev_local 		{
1602f083884Ss.makeev_local 			MT::TaskHandle handle = taskPool->TryAlloc(SimpleTask());
1612f083884Ss.makeev_local 			if (handle.IsValid())
1622f083884Ss.makeev_local 			{
1632f083884Ss.makeev_local 				CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(handle));
1642f083884Ss.makeev_local 			} else
1652f083884Ss.makeev_local 			{
1662f083884Ss.makeev_local 				CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(handle));
1672f083884Ss.makeev_local 			}
1682f083884Ss.makeev_local 		}
1692f083884Ss.makeev_local 	}
1702f083884Ss.makeev_local };
1712f083884Ss.makeev_local 
1722f083884Ss.makeev_local 
1732f083884Ss.makeev_local TEST(MultiThreadPoolTest)
1742f083884Ss.makeev_local {
1752f083884Ss.makeev_local 	TestPoolType taskPool;
1762f083884Ss.makeev_local 
1772f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
1782f083884Ss.makeev_local 
1792f083884Ss.makeev_local 	ThreadTest tasks[8];
1802f083884Ss.makeev_local 	for (size_t i = 0; i < MT_ARRAY_SIZE(tasks); ++i)
1812f083884Ss.makeev_local 	{
1822f083884Ss.makeev_local 		tasks[i].taskPool = &taskPool;
1832f083884Ss.makeev_local 	}
1842f083884Ss.makeev_local 
1852f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
1862f083884Ss.makeev_local 
1872f083884Ss.makeev_local 	int timeout = 20000;
1882f083884Ss.makeev_local 	CHECK(scheduler.WaitGroup(MT::TaskGroup::Default(), timeout));
1892f083884Ss.makeev_local }
1902f083884Ss.makeev_local 
1912f083884Ss.makeev_local 
1922f083884Ss.makeev_local //
1932f083884Ss.makeev_local TEST(FireAndForgetSimple)
1942f083884Ss.makeev_local {
1952f083884Ss.makeev_local 	MT::Atomic32<int32> doCounter(0);
1962f083884Ss.makeev_local 	MT::Atomic32<int32> dtorCounter(0);
1972f083884Ss.makeev_local 
1982f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
1992f083884Ss.makeev_local 	TestPoolType taskPool;
2002f083884Ss.makeev_local 
2012f083884Ss.makeev_local 	for(int pass = 0; pass < 4; pass++)
2022f083884Ss.makeev_local 	{
2032f083884Ss.makeev_local 		printf("--- step %d ---\n", pass);
2042f083884Ss.makeev_local 
2052f083884Ss.makeev_local 		doCounter.Store(0);
2062f083884Ss.makeev_local 		dtorCounter.Store(0);
2072f083884Ss.makeev_local 
2082f083884Ss.makeev_local 		MT::TaskHandle taskHandles[250];
2092f083884Ss.makeev_local 		for (size_t i = 0; i < MT_ARRAY_SIZE(taskHandles); ++i)
2102f083884Ss.makeev_local 		{
2112f083884Ss.makeev_local 			taskHandles[i] = taskPool.Alloc(SimpleTask(&doCounter, &dtorCounter, &taskPool));
2122f083884Ss.makeev_local 			CHECK_EQUAL(true, taskHandles[i].IsValid());
2132f083884Ss.makeev_local 		}
2142f083884Ss.makeev_local 
2152f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &taskHandles[0], MT_ARRAY_SIZE(taskHandles));
2162f083884Ss.makeev_local 
2172f083884Ss.makeev_local 		int timeout = 20000;
2182f083884Ss.makeev_local 		CHECK(scheduler.WaitAll(timeout));
2192f083884Ss.makeev_local 
2202f083884Ss.makeev_local 		CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)doCounter.Load());
2212f083884Ss.makeev_local 		CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)dtorCounter.Load());
2222f083884Ss.makeev_local 	}
2232f083884Ss.makeev_local 
2242f083884Ss.makeev_local }
2252f083884Ss.makeev_local 
2262f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2272f083884Ss.makeev_local }
228