1 #include <MTScheduler.h>
2 
3 namespace MT
4 {
5 	FiberContext::FiberContext()
6 		: threadContext(nullptr)
7 		, taskStatus(FiberTaskStatus::UNKNOWN)
8 		, currentGroup(TaskGroup::GROUP_UNDEFINED)
9 		, childrenFibersCount(0)
10 		, parentFiber(nullptr)
11 	{
12 	}
13 
14 	void FiberContext::SetStatus(FiberTaskStatus::Type _taskStatus)
15 	{
16 		ASSERT(threadContext, "Sanity check failed");
17 		ASSERT(threadContext->thread.IsCurrentThread(), "You can change task status only from owner thread");
18 		taskStatus = _taskStatus;
19 	}
20 
21 	FiberTaskStatus::Type FiberContext::GetStatus() const
22 	{
23 		return taskStatus;
24 	}
25 
26 	void FiberContext::SetThreadContext(internal::ThreadContext * _threadContext)
27 	{
28 		if (_threadContext)
29 		{
30 			_threadContext->lastActiveFiberContext = this;
31 		}
32 
33 		threadContext = _threadContext;
34 	}
35 
36 	internal::ThreadContext* FiberContext::GetThreadContext()
37 	{
38 		return threadContext;
39 	}
40 
41 	void FiberContext::Reset()
42 	{
43 		ASSERT(childrenFibersCount.Get() == 0, "Can't release fiber with active children fibers");
44 
45 		currentGroup = TaskGroup::GROUP_UNDEFINED;
46 		currentTask = internal::TaskDesc();
47 		parentFiber = nullptr;
48 		threadContext = nullptr;
49 	}
50 
51 	void FiberContext::WaitGroupAndYield(TaskGroup::Type group)
52 	{
53 		ASSERT(threadContext, "Sanity check failed!");
54 		ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use WaitGroupAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
55 		ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");
56 
57 		VERIFY(group != currentGroup, "Can't wait the same group. Deadlock detected!", return);
58 		VERIFY(group < TaskGroup::COUNT, "Invalid group!", return);
59 
60 		ConcurrentQueueLIFO<FiberContext*> & groupQueue = threadContext->taskScheduler->waitTaskQueues[group];
61 
62 		// Change status
63 		taskStatus = FiberTaskStatus::AWAITING_GROUP;
64 
65 		// Add current fiber to awaiting queue
66 		groupQueue.Push(this);
67 
68 		Fiber & schedulerFiber = threadContext->schedulerFiber;
69 
70 		// Yielding, so reset thread context
71 		threadContext = nullptr;
72 
73 		//switch to scheduler
74 		Fiber::SwitchTo(fiber, schedulerFiber);
75 	}
76 
77 	void FiberContext::RunSubtasksAndYieldImpl(fixed_array<internal::TaskBucket>& buckets)
78 	{
79 		ASSERT(threadContext, "Sanity check failed!");
80 		ASSERT(threadContext->taskScheduler->IsWorkerThread(), "Can't use RunSubtasksAndYield outside Task. Use TaskScheduler.WaitGroup() instead.");
81 		ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");
82 
83 		// add to scheduler
84 		threadContext->taskScheduler->RunTasksImpl(buckets, this, false);
85 
86 		//
87 		ASSERT(threadContext->thread.IsCurrentThread(), "Thread context sanity check failed");
88 
89 		// Change status
90 		taskStatus = FiberTaskStatus::AWAITING_CHILD;
91 
92 		Fiber & schedulerFiber = threadContext->schedulerFiber;
93 
94 		// Yielding, so reset thread context
95 		threadContext = nullptr;
96 
97 		//switch to scheduler
98 		Fiber::SwitchTo(fiber, schedulerFiber);
99 	}
100 
101 
102 }
103