1*2f083884Ss.makeev_local // The MIT License (MIT)
2*2f083884Ss.makeev_local //
3*2f083884Ss.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4*2f083884Ss.makeev_local //
5*2f083884Ss.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6*2f083884Ss.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
7*2f083884Ss.makeev_local // 	in the Software without restriction, including without limitation the rights
8*2f083884Ss.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9*2f083884Ss.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
10*2f083884Ss.makeev_local // 	furnished to do so, subject to the following conditions:
11*2f083884Ss.makeev_local //
12*2f083884Ss.makeev_local //  The above copyright notice and this permission notice shall be included in
13*2f083884Ss.makeev_local // 	all copies or substantial portions of the Software.
14*2f083884Ss.makeev_local //
15*2f083884Ss.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2f083884Ss.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2f083884Ss.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*2f083884Ss.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2f083884Ss.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*2f083884Ss.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21*2f083884Ss.makeev_local // 	THE SOFTWARE.
22*2f083884Ss.makeev_local 
23*2f083884Ss.makeev_local #include "Tests.h"
24*2f083884Ss.makeev_local #include <UnitTest++.h>
25*2f083884Ss.makeev_local #include <MTScheduler.h>
26*2f083884Ss.makeev_local 
27*2f083884Ss.makeev_local 
28*2f083884Ss.makeev_local 
29*2f083884Ss.makeev_local SUITE(FireAndForget)
30*2f083884Ss.makeev_local {
31*2f083884Ss.makeev_local 
32*2f083884Ss.makeev_local struct SimpleTask;
33*2f083884Ss.makeev_local 
34*2f083884Ss.makeev_local typedef MT::TaskPool<SimpleTask, 512> TestPoolType;
35*2f083884Ss.makeev_local 
36*2f083884Ss.makeev_local struct SimpleTask
37*2f083884Ss.makeev_local {
38*2f083884Ss.makeev_local 	MT_DECLARE_TASK(SimpleTask, MT::StackRequirements::STANDARD, MT::Color::Blue);
39*2f083884Ss.makeev_local 
40*2f083884Ss.makeev_local 	MT::Atomic32<int32>* doCounter;
41*2f083884Ss.makeev_local 	MT::Atomic32<int32>* dtorCounter;
42*2f083884Ss.makeev_local 	TestPoolType* taskPool;
43*2f083884Ss.makeev_local 
44*2f083884Ss.makeev_local 	SimpleTask()
45*2f083884Ss.makeev_local 		: doCounter(nullptr)
46*2f083884Ss.makeev_local 		, dtorCounter(nullptr)
47*2f083884Ss.makeev_local 		, taskPool(nullptr)
48*2f083884Ss.makeev_local 	{
49*2f083884Ss.makeev_local 	}
50*2f083884Ss.makeev_local 
51*2f083884Ss.makeev_local 	SimpleTask(MT::Atomic32<int32>* _doCounter, MT::Atomic32<int32>* _dtorCounter, TestPoolType * _taskPool)
52*2f083884Ss.makeev_local 		: doCounter(_doCounter)
53*2f083884Ss.makeev_local 		, dtorCounter(_dtorCounter)
54*2f083884Ss.makeev_local 		, taskPool(_taskPool)
55*2f083884Ss.makeev_local 	{
56*2f083884Ss.makeev_local 	}
57*2f083884Ss.makeev_local 
58*2f083884Ss.makeev_local 	SimpleTask(SimpleTask&& other)
59*2f083884Ss.makeev_local 		: doCounter(other.doCounter)
60*2f083884Ss.makeev_local 		, dtorCounter(other.dtorCounter)
61*2f083884Ss.makeev_local 		, taskPool(other.taskPool)
62*2f083884Ss.makeev_local 	{
63*2f083884Ss.makeev_local 		other.doCounter = nullptr;
64*2f083884Ss.makeev_local 		other.dtorCounter = nullptr;
65*2f083884Ss.makeev_local 		other.taskPool = nullptr;
66*2f083884Ss.makeev_local 	}
67*2f083884Ss.makeev_local 
68*2f083884Ss.makeev_local 	~SimpleTask()
69*2f083884Ss.makeev_local 	{
70*2f083884Ss.makeev_local 		if (dtorCounter)
71*2f083884Ss.makeev_local 		{
72*2f083884Ss.makeev_local 			dtorCounter->IncFetch();
73*2f083884Ss.makeev_local 		}
74*2f083884Ss.makeev_local 	}
75*2f083884Ss.makeev_local 
76*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
77*2f083884Ss.makeev_local 	{
78*2f083884Ss.makeev_local 		if (doCounter)
79*2f083884Ss.makeev_local 		{
80*2f083884Ss.makeev_local 			doCounter->IncFetch();
81*2f083884Ss.makeev_local 		}
82*2f083884Ss.makeev_local 
83*2f083884Ss.makeev_local 		if (taskPool)
84*2f083884Ss.makeev_local 		{
85*2f083884Ss.makeev_local 			MT::TaskHandle handle = taskPool->Alloc(SimpleTask(doCounter, dtorCounter, nullptr));
86*2f083884Ss.makeev_local 
87*2f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &handle, 1);
88*2f083884Ss.makeev_local 		}
89*2f083884Ss.makeev_local 	}
90*2f083884Ss.makeev_local };
91*2f083884Ss.makeev_local 
92*2f083884Ss.makeev_local 
93*2f083884Ss.makeev_local 
94*2f083884Ss.makeev_local TEST(SingleThreadPoolTest)
95*2f083884Ss.makeev_local {
96*2f083884Ss.makeev_local 	MT::TaskPool<SimpleTask, 4> taskPool;
97*2f083884Ss.makeev_local 
98*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle0 = taskPool.Alloc(SimpleTask());
99*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
100*2f083884Ss.makeev_local 
101*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle1 = taskPool.Alloc(SimpleTask());
102*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
103*2f083884Ss.makeev_local 
104*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle2 = taskPool.Alloc(SimpleTask());
105*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
106*2f083884Ss.makeev_local 
107*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle3 = taskPool.Alloc(SimpleTask());
108*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
109*2f083884Ss.makeev_local 
110*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
111*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
112*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
113*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
114*2f083884Ss.makeev_local 
115*2f083884Ss.makeev_local 
116*2f083884Ss.makeev_local 	// check for allocation fail
117*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle4 = taskPool.TryAlloc(SimpleTask());
118*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
119*2f083884Ss.makeev_local 
120*2f083884Ss.makeev_local 
121*2f083884Ss.makeev_local 	// check state
122*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle0.IsValid());
123*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle1.IsValid());
124*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle2.IsValid());
125*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle3.IsValid());
126*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
127*2f083884Ss.makeev_local 
128*2f083884Ss.makeev_local 	// destroy pool task by handle
129*2f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle0));
130*2f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle1));
131*2f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle2));
132*2f083884Ss.makeev_local 	CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle3));
133*2f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle4));
134*2f083884Ss.makeev_local 
135*2f083884Ss.makeev_local 	// check for double destroy
136*2f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle0));
137*2f083884Ss.makeev_local 	CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle3));
138*2f083884Ss.makeev_local 
139*2f083884Ss.makeev_local 	MT::TaskHandle taskHandle5 = taskPool.Alloc(SimpleTask());
140*2f083884Ss.makeev_local 
141*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle0.IsValid());
142*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle1.IsValid());
143*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle2.IsValid());
144*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle3.IsValid());
145*2f083884Ss.makeev_local 	CHECK_EQUAL(false, taskHandle4.IsValid());
146*2f083884Ss.makeev_local 	CHECK_EQUAL(true, taskHandle5.IsValid());
147*2f083884Ss.makeev_local }
148*2f083884Ss.makeev_local 
149*2f083884Ss.makeev_local 
150*2f083884Ss.makeev_local struct ThreadTest
151*2f083884Ss.makeev_local {
152*2f083884Ss.makeev_local 	MT_DECLARE_TASK(ThreadTest, MT::StackRequirements::STANDARD, MT::Color::Blue);
153*2f083884Ss.makeev_local 
154*2f083884Ss.makeev_local 	TestPoolType * taskPool;
155*2f083884Ss.makeev_local 
156*2f083884Ss.makeev_local 	void Do(MT::FiberContext&)
157*2f083884Ss.makeev_local 	{
158*2f083884Ss.makeev_local 		for (int i = 0; i < 20000; i++)
159*2f083884Ss.makeev_local 		{
160*2f083884Ss.makeev_local 			MT::TaskHandle handle = taskPool->TryAlloc(SimpleTask());
161*2f083884Ss.makeev_local 			if (handle.IsValid())
162*2f083884Ss.makeev_local 			{
163*2f083884Ss.makeev_local 				CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(handle));
164*2f083884Ss.makeev_local 			} else
165*2f083884Ss.makeev_local 			{
166*2f083884Ss.makeev_local 				CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(handle));
167*2f083884Ss.makeev_local 			}
168*2f083884Ss.makeev_local 		}
169*2f083884Ss.makeev_local 	}
170*2f083884Ss.makeev_local };
171*2f083884Ss.makeev_local 
172*2f083884Ss.makeev_local 
173*2f083884Ss.makeev_local TEST(MultiThreadPoolTest)
174*2f083884Ss.makeev_local {
175*2f083884Ss.makeev_local 	TestPoolType taskPool;
176*2f083884Ss.makeev_local 
177*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
178*2f083884Ss.makeev_local 
179*2f083884Ss.makeev_local 	ThreadTest tasks[8];
180*2f083884Ss.makeev_local 	for (size_t i = 0; i < MT_ARRAY_SIZE(tasks); ++i)
181*2f083884Ss.makeev_local 	{
182*2f083884Ss.makeev_local 		tasks[i].taskPool = &taskPool;
183*2f083884Ss.makeev_local 	}
184*2f083884Ss.makeev_local 
185*2f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
186*2f083884Ss.makeev_local 
187*2f083884Ss.makeev_local 	int timeout = 20000;
188*2f083884Ss.makeev_local 	CHECK(scheduler.WaitGroup(MT::TaskGroup::Default(), timeout));
189*2f083884Ss.makeev_local }
190*2f083884Ss.makeev_local 
191*2f083884Ss.makeev_local 
192*2f083884Ss.makeev_local //
193*2f083884Ss.makeev_local TEST(FireAndForgetSimple)
194*2f083884Ss.makeev_local {
195*2f083884Ss.makeev_local 	MT::Atomic32<int32> doCounter(0);
196*2f083884Ss.makeev_local 	MT::Atomic32<int32> dtorCounter(0);
197*2f083884Ss.makeev_local 
198*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
199*2f083884Ss.makeev_local 	TestPoolType taskPool;
200*2f083884Ss.makeev_local 
201*2f083884Ss.makeev_local 	for(int pass = 0; pass < 4; pass++)
202*2f083884Ss.makeev_local 	{
203*2f083884Ss.makeev_local 		printf("--- step %d ---\n", pass);
204*2f083884Ss.makeev_local 
205*2f083884Ss.makeev_local 		doCounter.Store(0);
206*2f083884Ss.makeev_local 		dtorCounter.Store(0);
207*2f083884Ss.makeev_local 
208*2f083884Ss.makeev_local 		MT::TaskHandle taskHandles[250];
209*2f083884Ss.makeev_local 		for (size_t i = 0; i < MT_ARRAY_SIZE(taskHandles); ++i)
210*2f083884Ss.makeev_local 		{
211*2f083884Ss.makeev_local 			taskHandles[i] = taskPool.Alloc(SimpleTask(&doCounter, &dtorCounter, &taskPool));
212*2f083884Ss.makeev_local 			CHECK_EQUAL(true, taskHandles[i].IsValid());
213*2f083884Ss.makeev_local 		}
214*2f083884Ss.makeev_local 
215*2f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &taskHandles[0], MT_ARRAY_SIZE(taskHandles));
216*2f083884Ss.makeev_local 
217*2f083884Ss.makeev_local 		int timeout = 20000;
218*2f083884Ss.makeev_local 		CHECK(scheduler.WaitAll(timeout));
219*2f083884Ss.makeev_local 
220*2f083884Ss.makeev_local 		CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)doCounter.Load());
221*2f083884Ss.makeev_local 		CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)dtorCounter.Load());
222*2f083884Ss.makeev_local 	}
223*2f083884Ss.makeev_local 
224*2f083884Ss.makeev_local }
225*2f083884Ss.makeev_local 
226*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
227*2f083884Ss.makeev_local }
228