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