0
|
1 #include <stdio.h>
|
|
2 #include "TaskManagerImpl.h"
|
|
3 #include "types.h"
|
|
4 #include "error.h"
|
|
5 #include "SchedTask.h"
|
|
6 #include "Scheduler.h"
|
|
7 #include "SysTask.h"
|
|
8 #include "SysFunc.h"
|
|
9 #include <string.h>
|
|
10
|
|
11 // singleton
|
|
12 QueueInfo<TaskQueue> *taskQueuePool = new QueueInfo<TaskQueue>() ;
|
|
13 QueueInfo<HTask> *htaskPool = new QueueInfo<HTask>() ;
|
|
14 QueueInfo<TaskList> *taskListPool = new QueueInfo<TaskList>() ;
|
|
15
|
|
16
|
|
17 static HTaskPtr systask_start;
|
|
18 static HTaskPtr systask_finish;
|
|
19
|
|
20 static void
|
|
21 noaction(SchedTask *s, void *read, void *write)
|
|
22 {
|
|
23 }
|
|
24
|
|
25 TaskManagerImpl::TaskManagerImpl(int num)
|
|
26 : machineNum(num){
|
|
27 // 実行可能なHTaskのリスト
|
|
28 activeTaskQueue = new QueueInfo<HTask>(htaskPool);
|
|
29 // wait_forで止まっているHTaskのリスト。必要ないが、Dead lock detection に使う
|
|
30 waitTaskQueue = new QueueInfo<HTask>(htaskPool);
|
|
31 // HTask の factory. QueueInfo<HTask> ならなんでもいい。
|
|
32 htaskImpl = waitTaskQueue ; // any QueueInfo<HTask>
|
|
33 // Task の dependency を表現する double linked list. QueueInfo<HTask> とは別に必要。
|
|
34 taskQueueImpl = new QueueInfo<TaskQueue>(taskQueuePool);
|
|
35 }
|
|
36
|
|
37 /**
|
|
38 * 一番最初に PPE で実行される systask_start
|
|
39 */
|
|
40 void
|
|
41 TaskManagerImpl::systask_init()
|
|
42 {
|
|
43 systask_register();
|
|
44 systask_start = create_task(StartTask,0,0,0,0,__builtin_return_address(0));
|
|
45 systask_finish = create_task(FinishTask,0,0,0,0,__builtin_return_address(0));
|
|
46
|
|
47 systask_start->spawn();
|
|
48
|
|
49 // すべての Task が FinishTask を wait_for すると、
|
|
50 // あらゆる Task が FinishTask の waiting task queue を操作する
|
|
51 // ことになる。それは、重すぎる。PPE/SPE Task が終了した時点で、
|
|
52 // TaskManager が実行する方が安い。
|
|
53 // append_waitTask(systask_finish);
|
|
54 }
|
|
55
|
|
56 /**
|
|
57 * Create Simple Task
|
|
58 */
|
|
59 HTaskPtr
|
|
60 TaskManagerImpl::create_task(int cmd,memaddr rbuf, long r_size, memaddr wbuf, long w_size, void *from) {
|
|
61 HTaskPtr new_task;
|
|
62
|
|
63 new_task = htaskImpl->create();
|
|
64 new_task->init(cmd, rbuf, r_size, wbuf, w_size);
|
|
65 new_task->post_func = noaction;
|
|
66 new_task->mimpl = this;
|
|
67 new_task->from = (memaddr)from;
|
|
68 #ifdef EARLY_TOUCH
|
|
69 if (rbuf) {
|
|
70 if ((unsigned long)rbuf&0xf) {
|
|
71 printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n",
|
|
72 cmd, (unsigned long)rbuf, r_size);
|
|
73 }
|
|
74 char *p = (char *)rbuf; char b = *p;
|
|
75 p = (char *)(rbuf+r_size-1); b += *p;
|
|
76 }
|
|
77 if (wbuf) {
|
|
78 if ((unsigned long)wbuf&0xf) {
|
|
79 printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n",
|
|
80 cmd, (unsigned long)wbuf, w_size);
|
|
81 }
|
|
82 char *p = (char *)wbuf; char b = *p;
|
|
83 p = (char *)(wbuf+w_size-1); b += *p;
|
|
84 }
|
|
85 #endif
|
|
86
|
|
87 return new_task;
|
|
88 }
|
|
89
|
|
90 /**
|
|
91 * Create Compatible Task (TaskArray1)
|
|
92 */
|
|
93 HTaskPtr
|
|
94 TaskManagerImpl::create_task(int cmd,void *from)
|
|
95 {
|
|
96 HTaskPtr new_task;
|
|
97
|
|
98 // for compatibility
|
|
99 new_task = htaskImpl->create(); new_task->init(TaskArray1);
|
|
100 new_task->post_func = noaction;
|
|
101 new_task->mimpl = this;
|
|
102 new_task->create_task_array(cmd,1,8,8,8);
|
|
103 // rbuf, r_size were set
|
|
104 new_task->command = TaskArray1;
|
|
105 new_task->from = (memaddr)from;
|
|
106
|
|
107 return new_task;
|
|
108 }
|
|
109
|
|
110 /**
|
|
111 * Create Task Array
|
|
112 */
|
|
113 HTaskPtr
|
|
114 TaskManagerImpl::create_task_array(int id, int num_task, int num_param, int num_inData, int num_outData, void *from)
|
|
115 {
|
|
116 HTaskPtr ta = create_task(TaskArray,0,0,0,0, from);
|
|
117 ta->create_task_array(id, num_task, num_param, num_inData, num_outData) ;
|
|
118 return ta;
|
|
119 }
|
|
120
|
|
121 /**
|
|
122 * task の依存関係を設定
|
|
123 * master task が終わってから、slave task を実行するように
|
|
124 * master->wait_for(slave);
|
|
125 */
|
|
126 void
|
|
127 TaskManagerImpl::set_task_depend(HTaskPtr master, HTaskPtr slave)
|
|
128 {
|
|
129 TaskQueuePtr m, s;
|
|
130 if (!master->self) return;
|
|
131
|
|
132 m = taskQueueImpl->create(); m->init(master);
|
|
133 s = taskQueueImpl->create(); s->init(slave);
|
|
134
|
|
135 master->wait_me->addLast(s);
|
|
136 slave->wait_i->addLast(m);
|
|
137 s->waiter = m;
|
|
138 }
|
|
139
|
|
140 /**
|
|
141 * タスクを実行可能キューまたは待機キューへ追加する。
|
|
142 * 依存関係が満たされていれば active, まだだったら wait へ。
|
|
143 * task->spawn();
|
|
144 */
|
|
145 void
|
|
146 TaskManagerImpl::spawn_task(HTaskPtr task)
|
|
147 {
|
|
148 // waiter // master
|
|
149 // waitee // slave
|
|
150 if (task->wait_i->empty()) {
|
|
151 append_activeTask(task);
|
|
152 } else {
|
|
153 append_waitTask(task);
|
|
154 }
|
|
155 }
|
|
156
|
|
157
|
|
158 /**
|
|
159 * Task を実行可能キューに追加する
|
|
160 */
|
|
161 void
|
|
162 TaskManagerImpl::append_activeTask(HTaskPtr q)
|
|
163 {
|
|
164 activeTaskQueue->addLast(q);
|
|
165 }
|
|
166
|
|
167 /**
|
|
168 * タスクが実行する CPU を選択する
|
|
169 *
|
|
170 * 現在は CPU_PPE, CPU_SPE, SPE_ANY, SPE_0, SPE_1, ..., SPE_5
|
|
171 * types.h に書いてます。
|
|
172 */
|
|
173 void
|
|
174 TaskManagerImpl::set_task_cpu(HTaskPtr task, CPU_TYPE type)
|
|
175 {
|
|
176 if (machineNum==0)
|
|
177 task->cpu_type = CPU_PPE ;
|
|
178 else
|
|
179 task->cpu_type = type;
|
|
180 }
|
|
181
|
|
182 #if 0
|
|
183 static void
|
|
184 check_wait(TaskManagerImpl *tm, QueueInfo<TaskQueue> *wait_i) {
|
|
185 for(TaskQueue *t = wait_i->getFirst(); t; t = wait_i->getNext(t)) {
|
|
186 if (!tm->waitTaskQueue->find(t->task)) {
|
|
187 printf("stray waiting task%d %lx\n",t->task->command, (long)t->task);
|
|
188 } else if (tm->activeTaskQueue->find(t->task)) {
|
|
189 printf(" active task%d in waiting queue %lx\n",t->task->command, (long)t->task);
|
|
190 } else
|
|
191 printf(".");
|
|
192 }
|
|
193 }
|
|
194 #endif
|
|
195
|
|
196 /**
|
|
197 * @brief 終了したタスクから依存の処理とか
|
|
198 * post_func() はこのタスクが終了したら実行する関数。
|
|
199 *
|
|
200 * @param [task] 終了したタスク
|
|
201 */
|
|
202 void
|
|
203 TaskManagerImpl::check_task_finish(HTaskPtr me, QueueInfo<HTask> *wait_queue)
|
|
204 {
|
|
205 while(TaskQueue *p = me->wait_me->poll()) {
|
|
206 HTaskPtr you = p->task;
|
|
207 QueueInfo<TaskQueue> *wait_i = you->wait_i;
|
|
208 // 相手の wait queue から自分(を指しているTaskQueue)を削除
|
|
209 wait_i->remove(p->waiter);
|
|
210 // queue を free する
|
|
211 wait_i->free_(p->waiter);
|
|
212
|
|
213 if (wait_i->empty()) {
|
|
214 wait_queue->remove(you);
|
|
215 append_activeTask(you);
|
|
216 }
|
|
217
|
|
218 wait_i->free_(p); // p->wait_i, p->wait_me は再利用される
|
|
219 }
|
|
220
|
|
221 // me を誰かが持っていて、me が finish した後に、
|
|
222 // me->wait_for(i) とか、やられると気まずい。
|
|
223 // 特に、me が他人に再利用されていると。そういう時には、
|
|
224 // このfreeをコメントアウトしてみる。
|
|
225
|
|
226 // id かななんかでチェックした方が良いが...
|
|
227
|
|
228 me->self = 0;
|
|
229 if (!me->flag.no_auto_free)
|
|
230 htaskImpl->free_(me);
|
|
231 }
|
|
232
|
|
233 /**
|
|
234 * @brief 終了したタスクリストの依存の処理
|
|
235 * @param [task] 終了したタスク
|
|
236 */
|
|
237 void
|
|
238 TaskManagerImpl::check_task_list_finish(SchedTask *s, TaskListPtr list, QueueInfo<HTask> *wait_queue)
|
|
239 {
|
|
240 for(int i = 0;i<list->length;i++) {
|
|
241 SimpleTaskPtr task = &list->tasks[i];
|
|
242 HTask *me = (HTask*)task->self;
|
|
243 me->post_func(s, me->post_arg1, me->post_arg2);
|
|
244 if (task->command==TaskArray1) {
|
|
245 int next = ((task->r_size)/sizeof(SimpleTask))+1;
|
|
246 // assert(next<list->length);
|
|
247 i+=next;
|
|
248 }
|
|
249 s->polling();
|
|
250 check_task_finish(me, wait_queue);
|
|
251 }
|
|
252 }
|
|
253
|
|
254 /**
|
|
255 * @brief waitTaskqueue への挿入 。必須ではない。
|
|
256 * 現状では、dead lock 検出にしか使ってない
|
|
257 *
|
|
258 * @param [task] 終了したタスク
|
|
259 */
|
|
260 void
|
|
261 TaskManagerImpl::append_waitTask(HTaskPtr q)
|
|
262 {
|
|
263 waitTaskQueue ->addLast(q);
|
|
264 }
|
|
265
|
|
266 /**
|
|
267 @brief htask を DMA でCPUに渡すための TaskList に入れる (copy)
|
|
268 @param htask
|
|
269 @param taskList
|
|
270 TaskList は自動的に延長される
|
|
271 */
|
|
272 void
|
|
273 TaskManagerImpl::set_taskList(HTaskPtr htask, QueueInfo<TaskList> * taskList) {
|
|
274 TaskListPtr list ;
|
|
275 if ( taskList->empty() ) {
|
|
276 list = taskList->create();
|
|
277 taskList->addLast(list);
|
|
278 } else
|
|
279 list = taskList->getLast();
|
|
280 SimpleTaskPtr task = &list->tasks[list->length++];
|
|
281 if (htask->command==TaskArray1) {
|
|
282 // compatibility
|
|
283 int next = ((htask->r_size)/sizeof(SimpleTask))+1;
|
|
284 if (list->length+next>=TASK_MAX_SIZE) {
|
|
285 list->length--;
|
|
286 TaskListPtr newList = taskList->create();
|
|
287 taskList->addLast(newList);
|
|
288 list = newList;
|
|
289 task = &list->tasks[list->length++];
|
|
290 }
|
|
291 Task *array = (Task*)&list->tasks[list->length];
|
|
292 list->length += next;
|
|
293 if (list->length>=TASK_MAX_SIZE) {
|
|
294 perror("task array1 overflow\n");
|
|
295 }
|
|
296 memcpy(array, htask->rbuf, htask->r_size);
|
|
297 free(htask->rbuf);
|
|
298 // htask->rbuf = 0; htask->r_size = 0; we need this...
|
|
299 *task = *(SimpleTask*)htask;
|
|
300 } else {
|
|
301 *task = *(SimpleTask*)htask;
|
|
302 }
|
|
303 if (list->length >= TASK_MAX_SIZE) {
|
|
304 TaskListPtr newList = taskList->create();
|
|
305 taskList->addLast(newList);
|
|
306 list = newList;
|
|
307 }
|
|
308 }
|
|
309
|
|
310
|
|
311
|
|
312 /* end */
|