-
-
Notifications
You must be signed in to change notification settings - Fork 146
/
CompletionAction_c.c
204 lines (169 loc) · 9.34 KB
/
CompletionAction_c.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright (c) 2020 Doug Binks
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#include "TaskScheduler_c.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enkiTaskScheduler* pETS;
struct CompletionArgs_ModifyTask
{
enkiTaskSet* pTaskB;
uint32_t run;
};
struct CompletionArgs_DeleteTask
{
enkiTaskSet* pTask;
enkiDependency* pDependency; // in this example only 1 or 0 dependencies, but generally could be an array
enkiCompletionAction* pCompletionAction;
uint32_t run; // only required for example output, not needed for a general purpose delete task
};
// In this example all our TaskSet functions share the same args struct, but we could use different one
struct TaskSetArgs
{
enkiTaskSet* pTask;
const char* name;
uint32_t run;
};
void CompletionFunctionPreComplete_ModifyDependentTask( void* pArgs_, uint32_t threadNum_ )
{
struct CompletionArgs_ModifyTask* pCompletionArgs_ModifyTask = pArgs_;
struct enkiParamsTaskSet paramsTaskNext = enkiGetParamsTaskSet( pCompletionArgs_ModifyTask->pTaskB );
printf("CompletionFunctionPreComplete_ModifyDependentTask for run %u running on thread %u\n",
pCompletionArgs_ModifyTask->run, threadNum_ );
// in this function we can modify the parameters of any task which depends on this CompletionFunction
// pre complete functions should not be used to delete the current CompletionAction, for that use PostComplete functions
paramsTaskNext.setSize = 10; // modify the set size of the next task - for example this could be based on output from previous task
enkiSetParamsTaskSet( pCompletionArgs_ModifyTask->pTaskB, paramsTaskNext );
free( pCompletionArgs_ModifyTask );
}
void CompletionFunctionPostComplete_DeleteTask( void* pArgs_, uint32_t threadNum_ )
{
struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTask = pArgs_;
printf("CompletionFunctionPostComplete_DeleteTask for run %u running on thread %u\n",
pCompletionArgs_DeleteTask->run, threadNum_ );
// can free memory in post complete
// note must delete a dependency before you delete the dependency task and the task to run on completion
if( pCompletionArgs_DeleteTask->pDependency )
{
enkiDeleteDependency( pETS, pCompletionArgs_DeleteTask->pDependency );
}
free( enkiGetParamsTaskSet( pCompletionArgs_DeleteTask->pTask ).pArgs );
enkiDeleteTaskSet( pETS, pCompletionArgs_DeleteTask->pTask );
enkiDeleteCompletionAction( pETS, pCompletionArgs_DeleteTask->pCompletionAction );
// safe to free our own args in this example as no other function dereferences them
free( pCompletionArgs_DeleteTask );
}
void TaskSetFunc( uint32_t start_, uint32_t end_, uint32_t threadnum_, void* pArgs_ )
{
(void)start_; (void)end_;
struct TaskSetArgs* pTaskSetArgs = pArgs_;
struct enkiParamsTaskSet paramsTaskNext = enkiGetParamsTaskSet( pTaskSetArgs->pTask );
if( 0 == start_ )
{
// for clarity in this example we only output one printf per taskset func called, but would normally loop from start_ to end_ doing work
printf("Task %s for run %u running on thread %u has set size %u\n", pTaskSetArgs->name, pTaskSetArgs->run, threadnum_, paramsTaskNext.setSize);
}
// A TastSetFunction is not a safe place to free it's own pArgs_ as when the setSize > 1 there may be multiple
// calls to this function with the same pArgs_
}
int main(int argc, const char * argv[])
{
// This examples shows CompletionActions used to modify a following tasks parameters and free allocations
// Task Graph for this example (with names shortened to fit on screen):
//
// pTaskSetA
// ->pCompletionActionA-PreFunc-PostFunc
// ->pTaskSetB
// ->pCompletionActionB-(no PreFunc)-PostFunc
//
// Note that pTaskSetB must depend on pCompletionActionA NOT pTaskSetA or it could run at the same time as pCompletionActionA
// so cannot be modified.
struct enkiTaskSet* pTaskSetA;
struct enkiCompletionAction* pCompletionActionA;
struct enkiTaskSet* pTaskSetB;
struct enkiCompletionAction* pCompletionActionB;
struct TaskSetArgs* pTaskSetArgsA;
struct CompletionArgs_ModifyTask* pCompletionArgsA;
struct enkiParamsCompletionAction paramsCompletionActionA;
struct TaskSetArgs* pTaskSetArgsB;
struct enkiDependency* pDependencyOfTaskSetBOnCompletionActionA;
struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTaskA;
struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTaskB;
struct enkiParamsCompletionAction paramsCompletionActionB;
int run;
pETS = enkiNewTaskScheduler();
enkiInitTaskScheduler( pETS );
for( run=0; run<10; ++run )
{
// Create all this runs tasks and completion actions
pTaskSetA = enkiCreateTaskSet( pETS, TaskSetFunc );
pCompletionActionA = enkiCreateCompletionAction( pETS,
CompletionFunctionPreComplete_ModifyDependentTask,
CompletionFunctionPostComplete_DeleteTask );
pTaskSetB = enkiCreateTaskSet( pETS, TaskSetFunc );
pCompletionActionB = enkiCreateCompletionAction( pETS,
NULL,
CompletionFunctionPostComplete_DeleteTask );
// Set args for TaskSetA
pTaskSetArgsA = malloc(sizeof(struct TaskSetArgs));
pTaskSetArgsA->run = run;
pTaskSetArgsA->pTask = pTaskSetA;
pTaskSetArgsA->name = "A";
enkiSetArgsTaskSet( pTaskSetA, pTaskSetArgsA );
// Set args for CompletionActionA, and make dependent on TaskSetA through pDependency
pCompletionArgsA = malloc(sizeof(struct CompletionArgs_ModifyTask));
pCompletionArgsA->pTaskB = pTaskSetB;
pCompletionArgsA->run = run;
pCompletionArgs_DeleteTaskA = malloc(sizeof(struct CompletionArgs_DeleteTask));
pCompletionArgs_DeleteTaskA->pTask = pTaskSetA;
pCompletionArgs_DeleteTaskA->pCompletionAction = pCompletionActionA;
pCompletionArgs_DeleteTaskA->pDependency = NULL;
pCompletionArgs_DeleteTaskA->run = run;
paramsCompletionActionA = enkiGetParamsCompletionAction( pCompletionActionA );
paramsCompletionActionA.pArgsPreComplete = pCompletionArgsA;
paramsCompletionActionA.pArgsPostComplete = pCompletionArgs_DeleteTaskA;
paramsCompletionActionA.pDependency = enkiGetCompletableFromTaskSet( pTaskSetA );
enkiSetParamsCompletionAction( pCompletionActionA, paramsCompletionActionA );
// Set args for TaskSetB
pTaskSetArgsB = malloc(sizeof(struct TaskSetArgs));
pTaskSetArgsB->run = run;
pTaskSetArgsB->pTask = pTaskSetB;
pTaskSetArgsB->name = "B";
enkiSetArgsTaskSet( pTaskSetB, pTaskSetArgsB );
// TaskSetB depends on pCompletionActionA
pDependencyOfTaskSetBOnCompletionActionA = enkiCreateDependency( pETS );
enkiSetDependency( pDependencyOfTaskSetBOnCompletionActionA,
enkiGetCompletableFromCompletionAction( pCompletionActionA ),
enkiGetCompletableFromTaskSet( pTaskSetB ) );
// Set args for CompletionActionB, and make dependent on TaskSetB through pDependency
pCompletionArgs_DeleteTaskB = malloc(sizeof(struct CompletionArgs_DeleteTask));
pCompletionArgs_DeleteTaskB->pTask = pTaskSetB;
pCompletionArgs_DeleteTaskB->pDependency = pDependencyOfTaskSetBOnCompletionActionA;
pCompletionArgs_DeleteTaskB->pCompletionAction = pCompletionActionB;
pCompletionArgs_DeleteTaskB->run = run;
paramsCompletionActionB = enkiGetParamsCompletionAction( pCompletionActionB );
paramsCompletionActionB.pArgsPreComplete = NULL; // pCompletionActionB does not have a PreComplete function
paramsCompletionActionB.pArgsPostComplete = pCompletionArgs_DeleteTaskB;
paramsCompletionActionB.pDependency = enkiGetCompletableFromTaskSet( pTaskSetB );
enkiSetParamsCompletionAction( pCompletionActionB, paramsCompletionActionB );
// To launch all, we only add the first TaskSet
enkiAddTaskSet( pETS, pTaskSetA );
}
enkiWaitForAll( pETS );
enkiDeleteTaskScheduler( pETS );
}