GadgetSeed  0.9.6
task.c
[詳解]
1 /** @file
2  @brief タスク制御
3 
4  これらの関数は非タスク状態から実行されなければならない
5 
6  @date 2017.09.03
7  @date 2011.02.27
8  @author Takashi SHUDO
9 */
10 
11 #include "timer.h"
12 #include "asm.h"
13 #include "str.h"
14 #include "tkprintf.h"
15 #include "tcb.h"
16 #include "task.h"
17 #include "event.h"
18 #include "mutex.h"
19 #include "syscall.h"
20 #include "calltrace.h"
21 #include "interrupt.h"
22 
23 #include "task_opration.h"
24 #include "queue_opration.h"
25 #include "mutex_opration.h"
26 #include "event_opration.h"
27 #include "sleepqueue.h"
28 #include "waitqueue.h"
29 #include "syscall_param.h"
30 
31 //#define DEBUGKBITS 2
32 #include "dkprintf.h"
33 
34 
35 #ifndef GSC_KERNEL_IDLE_TASK_STACK_SIZE
36 #define GSC_KERNEL_IDLE_TASK_STACK_SIZE (1024) // $gsc カーネルアイドルタスクのスタックサイズ
37 #endif
38 
39 struct st_tcb *run_task; // 実行中タスク
40 struct st_tcb dummy_task; // タスクが起動される前のsyscall用タスクコンテキスト
41 
42 static int new_task_id;
43 static int enable_schedule;
44 static struct st_tcb *last_task; // ディスパッチ前の実行中タスク(DEBUG)
45 static struct tcb_queue task_list_head; // 全タスクキュー
46 static struct st_queue ready_queue_head[GSC_KERNEL_MAX_TASK_PRIORITY];// 実行タスクキュー
47 
48 
49 static struct st_tcb idle_tcb;
50 static unsigned int idle_stack[GSC_KERNEL_IDLE_TASK_STACK_SIZE/sizeof(unsigned int)];
51 
52 /* NOT API
53  @brief IDLE(何もしない)タスク
54 */
55 static int idle_task(char *arg)
56 {
57  DKFPRINTF(0x01, "idle_task start\n");
58 
59  while(1) {
60 #ifndef LINT
61  sleep_cpu(); // 何もせず終了しない
62 #endif
63  }
64 
65  return 0;
66 }
67 
68 /* NOT API
69  @brief タスク制御を初期化する
70 */
71 void init_task(void)
72 {
73  int i;
74 
76 
77  new_task_id = 0;
78  enable_schedule = 0;
79  run_task = &dummy_task;
80 
81  init_queue(&task_list_head.queue);
82 
83  for(i=0; i<GSC_KERNEL_MAX_TASK_PRIORITY; i++) {
84  init_queue(&ready_queue_head[i]);
85  }
86 
87  init_queue(&timeout_wait_queue_head.queue);
88  init_queue(&wait_queue_head);
89  init_eventqueue();
90  init_mutex();
91 
92  task_add_ISR(idle_task, "IDLE", GSC_KERNEL_MAX_TASK_PRIORITY-1, &idle_tcb,
93  idle_stack, GSC_KERNEL_IDLE_TASK_STACK_SIZE, 0);
94 }
95 
96 static void task_startup(void)
97 {
98  run_task->main_func(run_task->arg);
99 
100  task_exit();
101 
102  // 戻り値を親タスクに渡す(予定)
103 }
104 
105 /* NOT API
106  @brief 最高優先順位タスクのサーチ
107 */
108 static struct st_tcb * search_next_task(void)
109 {
110  int i;
111 
112  for(i=0; i<GSC_KERNEL_MAX_TASK_PRIORITY; i++) {
113  if(check_queue(&ready_queue_head[i])) {
114  DKPRINTF(2, "Run task id = %d \"%s\"\n",
115  ((struct st_tcb *)ready_queue_head[i].next)->id,
116  ((struct st_tcb *)ready_queue_head[i].next)->name);
117  return (struct st_tcb *)(ready_queue_head[i].next);
118  }
119  }
120 
121  DKFPRINTF(0x01, "Cannot find exec task\n");
122 
123  return (struct st_tcb *)0;
124 }
125 
126 static void print_queue(struct st_queue *queue)
127 {
128  struct st_queue *tmp = queue->next;
129 
130  if(check_queue(queue) != 0) {
131  while(tmp->next != queue->next) {
132  tkprintf("->(%d:%s)", ((struct st_tcb *)tmp)->id,
133  ((struct st_tcb *)tmp)->name);
134  tmp = tmp->next;
135  }
136  }
137  tkprintf("\n");
138 }
139 
140 static void print_tcb_queue(struct tcb_queue *queue)
141 {
142  struct st_queue *tmp = ((struct st_queue *)queue)->next;
143 
144  if(check_queue((struct st_queue *)queue) != 0) {
145  while(tmp->next != ((struct st_queue *)queue)->next) {
146  tkprintf("->(%d:%s[%d])", ((struct tcb_queue *)tmp)->tcb->id,
147  ((struct tcb_queue *)tmp)->tcb->name,
148  ((struct tcb_queue *)tmp)->tcb->status);
149  tmp = tmp->next;
150  }
151  }
152  tkprintf("\n");
153 }
154 
155 const char status_str[][8] = {
156  "READY",
157  "RUN",
158  "TIMER",
159  "EVENT",
160  "MUTEX",
161  "REQUEST",
162  "DRMNT"
163 };
164 
165 /**
166  @brief タスク情報を取得する
167 
168  @param[out] ti タスク情報
169  @param[in] count 取得する最大タスク数
170 
171  @return 取得したタスク数
172 
173  @attention tiのサイズはcount数分確保していなければならない
174 */
175 int get_tasks_info(struct st_task_info *ti, int count)
176 {
177  int rtn = 0;
178  struct tcb_queue *queue = (struct tcb_queue *)&task_list_head;
179  struct st_queue *tmp = ((struct st_queue *)queue)->next;
180 
181  if(check_queue((struct st_queue *)queue) != 0) {
182  while(tmp->next != ((struct st_queue *)queue)->next) {
183  if(rtn >= count) {
184  break;
185  }
186 
187  ti->id = ((struct tcb_queue *)tmp)->tcb->id;
188  (void)strncopy((uchar *)ti->name, (uchar *)((struct tcb_queue *)tmp)->tcb->name, TASK_NAME_LEN);
189  ti->priority = ((struct tcb_queue *)tmp)->tcb->priority;
190  ti->status = ((struct tcb_queue *)tmp)->tcb->status;
191  ti->run_time = ((struct tcb_queue *)tmp)->tcb->run_time;
192  tmp = tmp->next;
193  ti ++;
194  rtn ++;
195  }
196  }
197 
198  return rtn;
199 }
200 
201 
202 void print_task(void)
203 {
204  struct tcb_queue *queue = (struct tcb_queue *)&task_list_head;
205  struct st_queue *tmp = ((struct st_queue *)queue)->next;
206  unsigned int systime = get_kernel_time();
207 
208  tkprintf("PID Name Pri Status Entry PC Stack(size) SP SleepTime\n");
209 
210  if(check_queue((struct st_queue *)queue) != 0) {
211  while(tmp->next != ((struct st_queue *)queue)->next) {
212  tkprintf("%3d %10s %3d %6s %P %08X %P(%04X) %P %9d\n",
213  ((struct tcb_queue *)tmp)->tcb->id,
214  ((struct tcb_queue *)tmp)->tcb->name,
215  ((struct tcb_queue *)tmp)->tcb->priority,
216  status_str[((struct tcb_queue *)tmp)->tcb->status],
217  (((struct tcb_queue *)tmp)->tcb->main_func),
218 #ifndef GSC_TARGET_SYSTEM_EMU
219  ((union st_regs *)(((struct tcb_queue *)tmp)->tcb->sp))->name.pc,
220 #else
221  0,
222 #endif
223  (((struct tcb_queue *)tmp)->tcb->stack_addr),
224  (unsigned int)(((struct tcb_queue *)tmp)->tcb->stack_size),
225  (((struct tcb_queue *)tmp)->tcb->sp),
226  (((struct tcb_queue *)tmp)->tcb->wup_time == 0) ?
227  0 : (unsigned int)(((struct tcb_queue *)tmp)->tcb->wup_time - systime)
228  );
229  tmp = tmp->next;
230  }
231  }
232 }
233 
234 void print_queues(void)
235 {
236  int i;
237 
238  tkprintf("======== Task Queue ========\n");
239 
240  tkprintf("All ");
241  print_tcb_queue(&task_list_head);
242 
243  tkprintf("TimeoutWait ");
244  print_tcb_queue(&timeout_wait_queue_head);
245 
246  for(i=0; i<GSC_KERNEL_MAX_TASK_PRIORITY; i++) {
247  tkprintf("Ready [%d] ", i);
248  print_queue(&ready_queue_head[i]);
249  }
250 
251  tkprintf("Wait ");
252  print_queue(&wait_queue_head);
253 
254  if(check_queue(&event_queue_list.list) != 0) {
255  struct st_event *tmp = (struct st_event *)event_queue_list.list.next;
256 
257  while(tmp->list.next != event_queue_list.list.next) {
258  tkprintf("Event [%10s](%d) ", tmp->name, fifo_size(&tmp->event));
259  print_queue(&tmp->proc_head);
260  tmp = (struct st_event *)tmp->list.next;
261  }
262  }
263 
264  i = 0;
265  if(check_queue(&mutex_queue_list.list) != 0) {
266  struct st_mutex *tmp = (struct st_mutex *)mutex_queue_list.list.next;
267 
268  while(tmp->list.next != mutex_queue_list.list.next) {
269  tkprintf("MUTEX [%10s] ", tmp->name);
270  if(tmp->lock_ps != 0) {
271  tkprintf("Lock(%d:%s)",
272  tmp->lock_ps->id,
273  tmp->lock_ps->name);
274  }
275  print_queue(&tmp->wait_ps);
276  tmp = (struct st_mutex *)tmp->list.next;
277  }
278  }
279 
280  tkprintf("Run : PID=%d \"%s\"\n", run_task->id, run_task->name);
281 
282  //disp_regs(run_task->sp);
283 
284  tkprintf("===============================\n");
285 }
286 
287 static void print_task_stack(struct st_tcb *tcb)
288 {
289  kxdump(tcb->stack_addr, tcb->stack_size);
290 }
291 
292 void print_stack(void)
293 {
294  tkprintf("Stack dump(PID=%d \"%s\")\n", run_task->id, run_task->name);
295 
296  print_task_stack(run_task);
297 }
298 
299 static void dispatch_task(struct st_tcb *task, int status)
300 {
301  struct st_tcb *otcb = run_task;
302  unsigned int now_time = get_system_utime();
303 
304  if(task == 0) return;
305 
306 #ifdef GSC_TARGET_SYSTEM_EMU
307  record_calltrace(SYSCALL_DISPATCH, run_task->status, task, status, 0, 0);
308 #else
309  record_calltrace(SYSCALL_DISPATCH, run_task->status, task, status, 0, task->sp);
310 #endif
311 
312 // disable_interrupt();
313  run_task->status = status;
314 
315  run_task->run_time += (now_time - run_task->meas_time);
316  run_task = task;
317  run_task->meas_time = now_time;
318 
319  run_task->wup_time = 0;
320  enable_schedule = 1;
321 #ifdef DEBUG
322  print_queues();
323 #endif
324 // disp_regs(otcb);
325 // disp_regs(task);
326 
327  last_task = run_task;
328 
329  run_task->status = PSTAT_RUN;
330 
331 #ifndef GSC_TARGET_SYSTEM_EMU
332  if(run_task->sp < run_task->stack_addr) {
333  tkprintf("PID %d \"%s\" Stack OVER %p(%ld)\n",
334  run_task->id,
335  run_task->name,
336  run_task->stack_addr,
337  run_task->stack_size);
338  disp_regs(run_task->sp);
339  }
340 #endif
341 
342  dispatch(otcb, task);
343 
344  // ここにはこない
345 }
346 
347 static void wakeup_task(struct st_tcb *tcb)
348 {
349  DKFPRINTF(0x01, "Wakeup PID = %d \"%s\"\n", tcb->id, tcb->name);
350 
351  insert_queue(&ready_queue_head[tcb->priority], (struct st_queue *)tcb);
352 
353  DKPRINTF(0x02, "%s SLEEP PID = %d \"%s\"\n", __FUNCTION__,
354  run_task->id, run_task->name);
355 #ifdef DEBUG
356  disp_regs(run_task->sp);
357 #endif
358  DKPRINTF(0x02, "%s WAKEUP PID = %d \"%s\"\n", __FUNCTION__,
359  tcb->id, tcb->name);
360 #ifdef DEBUG
361  disp_regs(tcb->sp);
362 #endif
363  dispatch_task(tcb, PSTAT_READY);
364 }
365 
366 static void task_add_queue(struct st_tcb *tcb)
367 {
368  DKFPRINTF(0x01, "Add PID = %d \"%s\"\n", tcb->id, tcb->name);
369 
370  add_queue(&ready_queue_head[tcb->priority], (struct st_queue *)tcb);
371 }
372 
373 #ifdef GSC_TARGET_SYSTEM_EMU
374 extern volatile int flg_interrput_proc;
375 #endif
376 
377 /* NOT API
378  @brief タスクをスケジュールする
379 
380  タイマ割り込みで実行する
381 */
382 void task_schedule(void *sp, unsigned long long systime)
383 {
384  struct st_tcb *task;
385 
386  DKFPRINTF(3, "SYSTIME = %lu\n", systime);
387 
388  if(enable_schedule == 0) {
389  return;
390  }
391 
392  if(run_task == 0) {
393  return;
394  }
395 
396 #if 0
397  if(run_task == &dummy_task) {
398  return;
399  }
400 #endif
401 
402  run_task->sp = sp;
403 
404  task = sleepqueue_schedule(systime);
405 
406  if(task != 0) {
407  // イベント、MUTEX待ちであればそれらの待ちキューからも外す
408  switch(task->status) {
409  case PSTAT_TIMER_WAIT:
410  break;
411  case PSTAT_EVENT_WAIT:
412  case PSTAT_MUTEX_WAIT:
413  del_queue(&(task->queue.queue));
414  break;
415  default:
416  SYSERR_PRINT("Invalid timeout status(%d)", task->status);
417  break;
418  }
419 
420  record_calltrace(SYSCALL_TIMEOUT_WAKEUP, task->status, 0, 0, 0, sp);
421 #ifdef GSC_TARGET_SYSTEM_EMU
422  flg_interrput_proc = 0;
423 #endif
424  wakeup_task(task);
425  }
426 
427 #ifdef GSC_TARGET_SYSTEM_EMU
428  flg_interrput_proc = 0;
429 #endif
430 }
431 
432 
433 /* NOT API
434  @brief タスクコンテキストを初期化する
435 */
436 static struct st_tcb * task_init(task_func func,
437  char *name,
438  int priority,
439  struct st_tcb *tcb,
440  void *stack,
441  int stack_size,
442  char *arg)
443 {
444  struct st_tcb *task;
445  extern struct st_device *con_in_dev;
446  extern struct st_device *con_out_dev;
447  extern struct st_device *con_err_dev;
448 
449  DKFPRINTF(0x01, "%s", name);
450 
451  task = tcb;
452  if(task == 0) {
453  SYSERR_PRINT("Cannot init tcb %p\n", tcb);
454  return 0;
455  }
456 
457  task->status = PSTAT_DORMANT;
458 
459  init_queue(&(task->queue.queue));
460  task->queue.tcb = task;
461 
462  init_queue(&(task->timer_list.queue));
463  task->timer_list.tcb = task;
464 
465  init_queue(&(task->task_list.queue));
466  task->task_list.tcb = task;
467 
468  task->sp = (void *)(stack + stack_size); // (void *)ポインタへの加算は1バイトを期待
469  /*
470  暫定的に設定(task->sp は setup_task() で更新)
471  */
472 
473  task->stack_addr = stack;
474  task->stack_size = stack_size;
475  task->main_func = func;
476  task->id = new_task_id;
477  new_task_id ++;
478  (void)strncopy((unsigned char *)task->name, (unsigned char *)name, TASK_NAME_LEN);
479  task->priority = priority;
480  task->wup_time = 0;
481  task->arg = arg;
482  task->stdin_dev = con_in_dev;
483  task->stdout_dev = con_out_dev;
484  task->error_dev = con_err_dev;
485  task->meas_time = 0;
486  task->run_time = 0;
487 
488  setup_task(stack, stack_size, task_startup, task);
489 
490  add_queue(&task_list_head.queue, &task->task_list.queue);
491 
492  DKPRINTF(0x01, "name(id) \"%s\" (%d)\n", task->name, task->id);
493  DKPRINTF(0x01, "sp = %p\n", task->sp);
494  DKPRINTF(0x01, "start = %p\n", task->main_func);
495  DKPRINTF(0x01, "id = %d\n", task->id);
496  DKPRINTF(0x01, "priority = %d\n", task->priority);
497 
498  return task;
499 }
500 
501 
502 /**
503  @brief タスクを実行する
504 
505  @param[in] func タスク関数
506  @param[in] name タスク名文字列ポインタ
507  @param[in] priority タスク優先度
508  @param[in] tcb タスクコンテキストポインタ
509  @param[in] stack タスクスタックポインタ
510  @param[in] stack_size タスクスタックサイズ
511  @param[in] arg タスク実行時引数文字列ポインタ
512 
513  @remarks 割り込みハンドラからのみ実行可能
514 */
515 void task_exec_ISR(task_func func, char *name, int priority, struct st_tcb *tcb,
516  void *stack, int stack_size, char *arg)
517 {
518  struct st_tcb *task;
519 
520  task = task_init(func, name, priority, tcb, stack, stack_size, arg);
521 
522  if(task != 0) {
523  wakeup_task(task);
524  }
525 }
526 
527 
528 /**
529  @brief タスクを追加する
530 
531  @param[in] func タスク関数
532  @param[in] name タスク名文字列ポインタ
533  @param[in] priority タスク優先度
534  @param[in] tcb タスクコンテキストポインタ
535  @param[in] stack タスクスタックポインタ
536  @param[in] stack_size タスクスタックサイズ
537  @param[in] arg タスク実行時引数文字列ポインタ
538 
539  @remarks 割り込みハンドラからのみ実行可能
540 */
541 void task_add_ISR(task_func func, char *name, int priority, struct st_tcb *tcb,
542  void *stack, int stack_size, char *arg)
543 {
544  struct st_tcb *task;
545 
546  task = task_init(func, name, priority, tcb, stack, stack_size, arg);
547 
548  if(task != 0) {
549  task_add_queue(task);
550  }
551 }
552 
553 
554 /* NOT API
555  @brief 実行中タスクを終了する
556 
557  @param[in] sp スタックポインタ
558 
559  @remarks 割り込みハンドラからのみ実行可能
560 */
561 void task_exit_ISR(void *sp)
562 {
563  DKFPRINTF(0x01, "Exit PID = %d \"%s\"\n", run_task->id,
564  run_task->name);
565 
566  del_queue(&run_task->task_list.queue);
567 
568  (void)del_next_queue(&ready_queue_head[run_task->priority]);
569 
570  dispatch_task(search_next_task(), PSTAT_DORMANT);
571 }
572 
573 
574 static struct st_tcb *search_id(struct st_queue *queue, int id)
575 {
576  struct st_queue *tmp = queue->next;
577 
578  if(check_queue(queue) == 0) {
579  return (struct st_tcb *)0;
580  }
581 
582  while(tmp->next != queue->next) {
583  if(((struct st_tcb *)tmp)->id == id) {
584  return (struct st_tcb *)tmp;
585  }
586  tmp = tmp->next;
587  }
588 
589  return (struct st_tcb *)0;
590 }
591 
592 static struct st_tcb *search_task_id(int id)
593 {
594  struct st_tcb *tmp = 0;
595  struct st_queue *tq;
596  int i;
597 
598  for(i=0; i<GSC_KERNEL_MAX_TASK_PRIORITY; i++) {
599  tmp = search_id(&ready_queue_head[i], id);
600  if(tmp != 0) {
601  return tmp;
602  }
603  }
604 
605  tmp = search_id(&timeout_wait_queue_head.queue, id);
606  if(tmp != 0) {
607  return tmp;
608  }
609 
610  tmp = search_id(&wait_queue_head, id);
611  if(tmp != 0) {
612  return tmp;
613  }
614 
615  //
616  tq = event_queue_list.list.next;
617 
618  while(tq->next != event_queue_list.list.next) {
619  tmp = search_id(&((struct st_event *)tq)->proc_head, id);
620  if(tmp != 0) {
621  return tmp;
622  }
623  tq = tq->next;
624  }
625 
626  return (struct st_tcb *)0;
627 }
628 
629 /* NOT API
630  @brief idタスクを終了する
631 
632  @param[in] sp スタックポインタ
633  @param[in] id タスクID
634 
635  @remarks 割り込みハンドラからのみ実行可能
636 */
637 void task_kill_id_ISR(void *sp, int id)
638 {
639  struct st_tcb *task;
640 
641  task = search_task_id(id);
642 
643  if(task != 0) {
644  del_queue((struct st_queue *)task);
645  DKFPRINTF(0x01, "Kill PID = %d \"%s\"\n", task->id,
646  task->name);
647  dispatch_task(search_next_task(), PSTAT_DORMANT);
648  } else {
649  DKFPRINTF(0x01, "No task id %d\n", id);
650  }
651 }
652 
653 
654 /**
655  @brief idタスクを実行する
656 
657  @param[in] sp スタックポインタ
658  @param[in] id タスクID
659 
660  @remarks 割り込みハンドラからのみ実行可能
661 */
662 void task_wakeup_id_ISR(void *sp, int id)
663 {
664  struct st_tcb *task;
665 
666  task = search_id(&wait_queue_head, id);
667 
668  if(task != 0) {
669  run_task->sp = sp;
670  del_queue((struct st_queue *)task);
671  DKFPRINTF(0x01, "Wakeup PID = %d \"%s\"\n", task->id,
672  task->name);
673  wakeup_task(task);
674  } else {
675  DKFPRINTF(0x01, "No task id %d\n", id);
676  }
677 }
678 
679 
680 /* NOT API
681  @brief 実行中タスクを待ち状態にする
682 
683  @param[in] sp スタックポインタ
684 
685  @remarks 割り込みハンドラからのみ実行可能
686 */
687 void task_pause_ISR(void *sp)
688 {
689  DKFPRINTF(0x01, "Pause PID = %d \"%s\"\n", run_task->id,
690  run_task->name);
691 
692  record_calltrace(SYSCALL_TASK_PAUSE, run_task->status,
693  0, 0, 0, sp);
694 
695  run_task->sp = sp;
696 
697  (void)del_next_queue(&ready_queue_head[run_task->priority]);
698 
699  waitqueue_add(run_task);
700 
701  dispatch_task(search_next_task(), PSTAT_REQUEST_WAIT);
702 }
703 
704 
705 /* NOT API
706  @brief 実行中タスクをスリープする
707 
708  @param[in] sp スタックポインタ
709  @param[in] sleep_time スリープ時間(msec)
710 
711  @remarks 割り込みハンドラからのみ実行可能
712 */
713 void task_sleep_ISR(void *sp, unsigned int sleep_time)
714 {
715  unsigned int systime = get_kernel_time();
716 
717  DKFPRINTF(0x01, "Sleep PID = %d \"%s\" time = %ld\n",
718  run_task->id, run_task->name, sleep_time);
719 
720  run_task->sp = sp;
721 
722  record_calltrace(SYSCALL_TASK_SLEEP, run_task->status,
723  0, (int)sleep_time, 0, sp);
724 
725  (void)del_next_queue(&ready_queue_head[run_task->priority]);
726 
727  sleepqueue_add(run_task, sleep_time, systime);
728 
729  dispatch_task(search_next_task(), PSTAT_TIMER_WAIT);
730 }
731 
732 /* NOT API
733  @brief 実行中タスクをイベント待ち状態にする
734 
735  @param[in] sp スタックポインタ
736  @param[in] evtque イベントキューポインタ
737  @param[out] args イベント引数ポインタ
738  @param[in] timeout イベントタイムアウト待ち時間(msec)
739 
740  @remarks 割り込みハンドラからのみ実行可能
741 */
742 void event_wait_ISR(void *sp, struct st_event *evtque, void *arg, unsigned int timeout)
743 {
744  struct st_tcb *next_task;
745  int rtn;
746 
747  DKFPRINTF(0x01, "evtque = \"%s\" %p\n",
748  evtque->name, evtque);
749  DKPRINTF(0x01, "PID = %d \"%s\" arg = %p, timeout = %ld\n",
750  run_task->id, run_task->name, arg, timeout);
751  DKPRINTF(0x01, "evtque->size = %d\n", evtque->size);
752 
753  run_task->sp = sp;
754 
755  if(run_task == &dummy_task) {
756 #ifndef GSC_TARGET_SYSTEM_EMU
757  SYSERR_PRINT("No running task\n");
758  print_queues();
759 #endif
760  ((struct evtque_param *)run_task->syscall.param)->ret = -1;
761  return;
762  }
763 
764  record_calltrace(SYSCALL_EVTQUE_WAIT, run_task->status,
765  (void *)evtque, (int)timeout, fifo_size(&evtque->event), sp);
766 
767  if(arg != 0) {
768  rtn = read_fifo(&evtque->event, arg, evtque->size);
769  } else {
770  rtn = drop_fifo(&evtque->event, evtque->size);
771  }
772  if(rtn != 0) {
773  // 既にイベントが1回以上発生していた
774  ((struct evtque_param *)run_task->syscall.param)->ret = timeout;
775  // なのでイベント待ちはせず終了
776  return;
777  }
778 
779  // 自タスクをレディーキューから外し
780  (void)del_next_queue(&ready_queue_head[run_task->priority]);
781 
782  // イベント待ちキューに追加
783  _eventqueue_wait(evtque, run_task);
784 
785  // タイムアウト時間指定の場合はタイムアウト待ちキューに追加
786  if(timeout != 0) {
787  unsigned int systime = get_kernel_time();
788 
789  sleepqueue_add(run_task, timeout, systime);
790  }
791 
792  next_task = search_next_task();
793  DKPRINTF(0x02, "%s WAIT_EVENT PID = %d \"%s\"\n", __FUNCTION__,
794  run_task->id, run_task->name);
795 #ifdef DEBUG
796  disp_regs(run_task->sp);
797 #endif
798  DKPRINTF(0x02, "%s WAKEUP PID = %d \"%s\"\n", __FUNCTION__,
799  next_task->id, next_task->name);
800 #ifdef DEBUG
801  disp_regs(next_task->sp);
802 #endif
803  dispatch_task(next_task, PSTAT_EVENT_WAIT);
804 }
805 
806 /**
807  @brief イベントカウントを取得する
808 
809  @param[in] sp スタックポインタ
810  @param[in] evtque イベントキューポインタ
811 
812  @remarks 割り込みハンドラからのみ実行可能
813 */
814 int event_check_ISR(void *sp, struct st_event *evtque)
815 {
816  int count = 0;
817 
818  DKFPRINTF(0x01, "evtque = \"%s\" %p\n", evtque->name, evtque);
819 
820  record_calltrace(SYSCALL_EVTQUE_CHECK, run_task->status, evtque, evtque->size, fifo_size(&evtque->event), sp);
821 
822  count = fifo_size(&evtque->event) / evtque->size;
823 
824  DKFPRINTF(0x01, "count = %d\n", count);
825 
826  return count;
827 }
828 
829 /**
830  @brief イベントカウンタをクリアリセットする
831 
832  @param[in] sp スタックポインタ
833  @param[in] evtque イベントキューポインタ
834 
835  @remarks 割り込みハンドラからのみ実行可能
836  @remarks イベント待ちタスクは実行状態にはならない
837 */
838 void event_clear_ISR(void *sp, struct st_event *evtque)
839 {
840  DKFPRINTF(0x01, "evtque = \"%s\" %p\n", evtque->name, evtque);
841 
842  record_calltrace(SYSCALL_EVTQUE_CLEAR, run_task->status, evtque, 0, fifo_size(&evtque->event), sp);
843 
844  clear_fifo(&evtque->event);
845 }
846 
847 /**
848  @brief イベントFIFOにイベントを登録する
849 
850  @param[in] sp スタックポインタ
851  @param[in] evtque イベントキューポインタ
852  @param[in] arg イベント引数ポインタ
853 
854  @remarks 割り込みハンドラからのみ実行可能
855  @remarks イベント待ちタスクは実行状態にはならない
856 */
857 void event_push_ISR(void *sp, struct st_event *evtque, void *arg)
858 {
859  DKFPRINTF(0x01, "evtque = \"%s\" %p\n", evtque->name, evtque);
860 
861  record_calltrace(SYSCALL_EVTQUE_PUSH, run_task->status, evtque, 0, fifo_size(&evtque->event), sp);
862 
863  // イベントFIFOに追加
864  if(write_fifo(&evtque->event, arg, evtque->size) != evtque->size) {
865  DKFPRINTF(0x01, "event fifo full\n");
866  }
867 }
868 
869 /**
870  @brief イベント待ちタスクを起動する
871 
872  @param[in] sp スタックポインタ
873  @param[in] evtque イベントキューポインタ
874 
875  @remarks 割り込みハンドラからのみ実行可能
876  @attention event_push_ISR() をコールした割り込み処理内で実行する必要がある
877  @attention event_set_ISR() 実行以前に1回以上 event_push_ISR() が実行されている必要がある
878 */
879 void event_set_ISR(void *sp, struct st_event *evtque)
880 {
881  struct st_tcb *task;
882 
883  DKFPRINTF(0x01, "%s evtque = \"%s\" %p\n", evtque->name, evtque);
884 
885  // イベント待ちキューを取得
886  task = _eventqueue_wakeup(evtque);
887 
888  if(task != 0) {
889  // イベント待ちタスク有り
890  unsigned int systime = get_kernel_time();
891  run_task->sp = sp;
892  DKFPRINTF(0x01, "WAKEUP PID = %d \"%s\"\n", task->id, task->name);
893 
894  if(task->wup_time != 0) {
895  // タイムアウト時間指定有り
896  // タイムアウトを戻り値に設定
897  ((struct evtque_param *)task->syscall.param)->ret =
898  task->wup_time - systime;
899  // タイムアウト待ちキューから削除
900  del_queue(&(task->timer_list.queue));
901  } else {
902  // タイムアウト時間指定無しは戻り値0
903  ((struct evtque_param *)task->syscall.param)->ret = 0;
904  }
905  // イベント待ちタスクを起床
906  record_calltrace(SYSCALL_EVTQUE_WAKEUP, task->status, evtque, 0, fifo_size(&evtque->event), sp);
907  wakeup_task(task);
908  } else {
909  record_calltrace(SYSCALL_EVTQUE_WAKEUP, 0, evtque, 0, fifo_size(&evtque->event), sp);
910  }
911 }
912 
913 /**
914  @brief イベントキューにイベントを登録し、イベント待ちタスクを起動する
915 
916  @param[in] sp スタックポインタ
917  @param[in] evtque イベントキューポインタ
918  @param[in] arg イベント引数ポインタ
919 
920  @remarks 割り込みハンドラからのみコール可能
921  @remarks イベント待ちタスクがなければイベントカウンタをインクリメントする
922 */
923 void event_wakeup_ISR(void *sp, struct st_event *evtque, void *arg)
924 {
925  struct st_tcb *task;
926 
927  DKFPRINTF(0x01, "%s evtque = \"%s\" %p, arg = %p\n", evtque->name, evtque, arg);
928  DKPRINTF(0x01, "PID = %d \"%s\"\n", run_task->id, run_task->name);
929  DKPRINTF(0x01, "evtque->size = %d\n", evtque->size);
930 
931 #ifdef GSC_TARGET_SYSTEM_EMU
932  if(is_in_interrupt()) {
933  SYSERR_PRINT("EMU in SIGARM?\n");
934  }
935 #endif
936 
937  // イベント待ちキューを取得
938  task = _eventqueue_wakeup(evtque);
939 
940  if(task != 0) {
941  // イベント待ちタスク有り
942  unsigned int systime = get_kernel_time();
943  run_task->sp = sp;
944  DKFPRINTF(0x01, "WAKEUP PID = %d \"%s\"\n", task->id, task->name);
945 
946  // argを設定
947  if(arg != 0) {
948  int i;
949  unsigned char *asp, *adp;
950  asp = arg;
951  adp = ((struct evtque_param *)task->syscall.param)->arg;
952  for(i=0; i<evtque->size; i++) {
953  *adp = *asp;
954  adp ++;
955  asp ++;
956  }
957  }
958 
959  if(task->wup_time != 0) {
960  // タイムアウト時間指定有り
961  // タイムアウトを戻り値に設定
962  ((struct evtque_param *)task->syscall.param)->ret =
963  task->wup_time - systime;
964  // タイムアウト待ちキューから削除
965  del_queue(&(task->timer_list.queue));
966  } else {
967  // タイムアウト時間指定無しは戻り値0
968  ((struct evtque_param *)task->syscall.param)->ret = 0;
969  }
970  // イベント待ちタスクを起床
971  record_calltrace(SYSCALL_EVTQUE_WAKEUP, task->status, evtque, 0, fifo_size(&evtque->event), sp);
972  wakeup_task(task);
973  } else {
974  // イベントFIFOに追加
975  if(write_fifo(&evtque->event, arg, evtque->size) != evtque->size) {
976  DKFPRINTF(0x01, "event fifo full\n");
977  }
978  record_calltrace(SYSCALL_EVTQUE_WAKEUP, 0, evtque, 0, fifo_size(&evtque->event), sp);
979  }
980 }
981 
982 
983 /* NOT API
984  @brief MUTEXのロックを試みる
985 
986  ロックされていない場合はロックを行う
987  既にロックされていた場合はロック待ち状態となる
988 
989  @param[in] sp スタックポインタ
990  @param[in] evtque MUTEXポインタ
991  @param[in] timeout ロックタイムアウト時間(msec)
992 */
993 void mutex_lock_ISR(void *sp, struct st_mutex *mutex, unsigned int timeout)
994 {
995  int rtn = 0;
996 
997  DKFPRINTF(0x01, "%s mutex = \"%s\" %p\n", mutex->name, mutex);
998 
999  if(run_task == &dummy_task) {
1000 #ifndef GSC_TARGET_SYSTEM_EMU
1001  SYSERR_PRINT("No running task\n");
1002  print_queues();
1003 #endif
1004  ((struct mutex_param *)run_task->syscall.param)->ret = -1;
1005  return;
1006  }
1007 
1008  record_calltrace(SYSCALL_MUTEX_LOCK, run_task->status,
1009  (void *)mutex, (int)timeout, 0, sp);
1010 
1011  rtn = _mutex_lock(mutex, run_task);
1012  if(rtn > 0) {
1013  // 既にロック済みのMUTEX
1014  run_task->sp = sp;
1015 
1016  // 自タスクをREADYキューより外して
1017  (void)del_next_queue(&ready_queue_head[run_task->priority]);
1018  // MUTEXロック解除待ちとする
1019  DKPRINTF(0x01, "mutex locked wait %s\n", run_task->name);
1020  _mutex_wait(mutex, run_task);
1021 
1022  // タイムアウトした場合のために戻り値は 0 にしておく
1023  ((struct mutex_param *)run_task->syscall.param)->ret = 0;
1024 
1025  // タイムアウト時間指定の場合はタイムアウト待ちキューに追加
1026  if(timeout != 0) {
1027  unsigned int systime = get_kernel_time();
1028 
1029  sleepqueue_add(run_task, timeout, systime);
1030  }
1031 
1032  // 次のタスクにスイッチ
1033  dispatch_task(search_next_task(), PSTAT_MUTEX_WAIT);
1034  } else if(rtn < 0) {
1035  // 自タスクで既にロック済みだったMUTEX(エラー)
1036  //disp_regs(run_task->sp);// DEBUG
1037  ((struct mutex_param *)run_task->syscall.param)->ret = -1;
1038  } else {
1039  // ロックさせていないMUTEXだったので
1040  // MUTEXロック成功
1041  DKPRINTF(0x01, "mutex lock ok %s\n", run_task->name);
1042  ((struct mutex_param *)run_task->syscall.param)->ret = timeout;
1043  }
1044 }
1045 
1046 /* NOT API
1047  @brief MUTEXのロックを解除する
1048 
1049  ロック待ちタスクがいた場合、ロック解除したタスクがロックし、ロッ
1050  ク待ちタスクが実行状態になる
1051 
1052  @param[in] sp スタックポインタ
1053  @param[in] evtque MUTEXポインタ
1054 */
1055 void mutex_unlock_ISR(void *sp, struct st_mutex *mutex)
1056 {
1057  struct st_tcb *task;
1058  unsigned int systime;
1059 
1060  DKFPRINTF(0x01, "%s mutex = \"%s\" %p\n", mutex->name, mutex);
1061 
1062  run_task->sp = sp;
1063 
1064  if(run_task == &dummy_task) {
1065 #ifndef GSC_TARGET_SYSTEM_EMU
1066  SYSERR_PRINT("No running task\n");
1067  print_queues();
1068 #endif
1069  return;
1070  }
1071 
1072  record_calltrace(SYSCALL_MUTEX_UNLOCK, run_task->status,
1073  (void *)mutex, 0, 0, sp);
1074 
1075  // 次のMUTEXロック待ちタスクを取り出す
1076  task = _mutex_unlock(mutex, run_task);
1077 
1078  systime = get_kernel_time();
1079 
1080  if(task != 0) {
1081  // 次のMUTEXロック待ちタスクが有る
1082  if(task->wup_time != 0) {
1083  // タイムアウト指定の場合タウムアウトキューから外す
1084  ((struct mutex_param *)task->syscall.param)->ret =
1085  task->wup_time - systime;
1086  del_queue(&(task->timer_list.queue));
1087  } else {
1088  // タイムアウトの指定は無かった
1089  ((struct mutex_param *)task->syscall.param)->ret = 0;
1090  }
1091  DKPRINTF(0x01, "mutex unlock wakeup %s\n", task->name);
1092  // 次のタスクを実行
1093  wakeup_task(task);
1094  }
1095  // MUTEXロック待ちタスクが無かったのでそのまま終了
1096  //tkprintf("No wait & lock mutex ?\n");
1097 }
1098 
1099 /***
1100  *
1101  */
1102 
1103 void task_print_task_queue(void)
1104 {
1105  tkprintf("systime: %10ld\n", get_kernel_time());
1106  print_queues();
1107 }
1108 
1109 void disp_task_info(void)
1110 {
1111  tkprintf("Kernel Time = %ld\n", kernel_time_count);
1112 
1113  tkprintf("NOW PID = %d \"%s\"\n", run_task->id, run_task->name);
1114  tkprintf("LAST PID = %d \"%s\"\n", last_task->id, last_task->name);
1115  tkprintf("LAST SYSCALL = %s(%d)\n",
1116  syscall_name[last_syscall_type],
1117  last_syscall_type);
1118 }
unsigned char uchar
GadgetSeedの文字(列)は unsigned char 型となる
Definition: str.h:13
待ちタスク制御
タスク情報
Definition: task.h:36
struct st_device * con_err_dev
デフォルトエラー出力デバイス
Definition: console.c:91
タスクコンテキストブロック
int drop_fifo(struct st_fifo *fp, unsigned int length)
fifoからデータを捨てる
Definition: fifo.c:149
Cortex-M3 MCU レジスタ定義
Definition: asm-Cortex-M3.h:22
struct st_device * con_in_dev
デフォルト標準入力デバイス
Definition: console.c:89
char * arg
タスク実行時引数文字列
Definition: tcb.h:46
#define PSTAT_MUTEX_WAIT
タスク MUTEXロック解除待ち状態
Definition: tcb.h:21
task_func main_func
タスク関数
Definition: tcb.h:45
int status
タスク状態(PSTAT_*)
Definition: tcb.h:50
unsigned int run_time
タスク実行時間(msec)
Definition: tcb.h:57
int read_fifo(struct st_fifo *fp, unsigned char *data, unsigned int length)
fifoからデータを読み出す
Definition: fifo.c:74
struct st_tcb * _eventqueue_wakeup(struct st_event *evtque)
イベント待ちタスクを返す
Definition: event.c:85
タスクキュー
Definition: tcb.h:27
struct st_fifo event
イベントデータバッファ
Definition: event.h:18
int get_tasks_info(struct st_task_info *ti, int count)
タスク情報を取得する
Definition: task.c:175
struct tcb_queue timer_list
タイムアウト待ちキュー
Definition: tcb.h:35
int priority
タスクプライオリティ
Definition: task.h:39
文字列処理
struct st_queue queue
キュー
Definition: tcb.h:28
スリープタスク制御
#define TASK_NAME_LEN
最大タスク名長
Definition: tcb.h:15
MUTEX操作
unsigned long long get_system_utime(void)
システム時間を取得する
Definition: timer.c:202
int priority
タスクプライオリティ
Definition: tcb.h:48
struct st_queue list
MUTEXのキュー
Definition: mutex.h:14
カーネルタイマ
struct st_tcb * tcb
タスクコンテキストブロックポインタ
Definition: tcb.h:29
struct st_device * stdin_dev
タスク標準入力デバイス
Definition: tcb.h:52
#define init_calltrace(...)
< $gsc カーネルシステムコールトレースを有効にする
Definition: calltrace.h:30
#define PSTAT_READY
タスク 実行可能状態
Definition: tcb.h:17
int tkprintf(const char *fmt,...)
非タスクコンテキスト実行用メッセージ出力
Definition: tkprintf.c:100
struct st_device * stdout_dev
タスク標準出力デバイス
Definition: tcb.h:53
キュー構造
Definition: queue.h:13
#define PSTAT_REQUEST_WAIT
タスク 起床待ち状態
Definition: tcb.h:22
void _eventqueue_wait(struct st_event *evtque, struct st_tcb *tcb)
タスクをイベント待ちキューに登録する
Definition: event.c:73
カーネル用機能限定printf
unsigned int fifo_size(struct st_fifo *fp)
fifoに書き込まれているデータのサイズを返す
Definition: fifo.c:116
unsigned int meas_time
タスク実行時間計測開始システム時間(msec)
Definition: tcb.h:56
int status
タスク状態(PSTAT_*)
Definition: task.h:40
int(* task_func)(char *arg)
タスク関数
Definition: tcb.h:25
void task_exit(void)
タスクを終了する
Definition: syscall_api.c:264
void event_push_ISR(void *sp, struct st_event *evtque, void *arg)
イベントFIFOにイベントを登録する
Definition: task.c:857
char name[TASK_NAME_LEN+1]
タスク名
Definition: tcb.h:39
システムコールパラメータ定義
int write_fifo(struct st_fifo *fp, unsigned char *data, unsigned int length)
fifoにデータを書き込む
Definition: fifo.c:37
unsigned long long kernel_time_count
カーネル時間(ms)
Definition: timer.c:70
struct st_queue proc_head
イベント待ちタスクキュー
Definition: event.h:17
Cortex-M4
void clear_fifo(struct st_fifo *fp)
fifoに書き込まれているデータを全て消去する
Definition: fifo.c:103
void task_add_ISR(task_func func, char *name, int priority, struct st_tcb *tcb, void *stack, int stack_size, char *arg)
タスクを追加する
Definition: task.c:541
MUTEX
Definition: mutex.h:13
void kxdump(unsigned char *data, unsigned int len)
非タスクコンテキスト実行用メモリダンプメッセージ出力
Definition: tkprintf.c:118
void * sp
スタックポインタ
Definition: tcb.h:40
void * param
システムコール実行パラメータ
Definition: tcb.h:61
イベント
Definition: event.h:15
void task_wakeup_id_ISR(void *sp, int id)
idタスクを実行する
Definition: task.c:662
unsigned int wup_time
スリープタイムアウト時間
Definition: tcb.h:49
struct tcb_queue task_list
全タスクキュー
Definition: tcb.h:36
#define PSTAT_TIMER_WAIT
タスク タイマ待ち状態
Definition: tcb.h:19
システムコール
struct st_queue list
イベントキューのキュー
Definition: event.h:16
割り込みハンドラ
MUTEX制御
int id
タスクID
Definition: task.h:37
struct st_mutex mutex_queue_list
MUTEXキュー
Definition: mutex.c:20
void event_set_ISR(void *sp, struct st_event *evtque)
イベント待ちタスクを起動する
Definition: task.c:879
struct st_tcb * lock_ps
ロックしているタスク
Definition: mutex.h:15
キュー操作
unsigned int stack_size
スタックサイズ
Definition: tcb.h:42
デバッグ用システムコールトレース
struct st_queue wait_queue_head
待ちタスクキュー
Definition: waitqueue.c:17
void task_exec_ISR(task_func func, char *name, int priority, struct st_tcb *tcb, void *stack, int stack_size, char *arg)
タスクを実行する
Definition: task.c:515
struct st_device * con_out_dev
デフォルト標準出力デバイス
Definition: console.c:90
タスク制御
struct st_queue wait_ps
アンロック待ちタスクキュー
Definition: mutex.h:16
const char * name
イベント名文字列
Definition: event.h:20
struct st_device * error_dev
タスクエラー出力デバイス
Definition: tcb.h:54
イベント待ちタスクキューの操作
uchar * strncopy(uchar *dest, const uchar *src, unsigned int n)
文字列コピー
Definition: str.c:632
#define GSC_KERNEL_MAX_TASK_PRIORITY
$gsc カーネルタスクプライオリティ段階数
Definition: task.h:18
unsigned long long get_kernel_time(void)
カーネル時間を取得する
Definition: timer.c:192
#define PSTAT_EVENT_WAIT
タスク イベント待ち状態
Definition: tcb.h:20
#define PSTAT_DORMANT
タスク 休止状態
Definition: tcb.h:23
struct tcb_queue timeout_wait_queue_head
タイムアウト待ちタスクキュー
Definition: sleepqueue.c:24
void event_wakeup_ISR(void *sp, struct st_event *evtque, void *arg)
イベントキューにイベントを登録し、イベント待ちタスクを起動する
Definition: task.c:923
タスク操作
デバイスドライバ構造体
Definition: device.h:25
#define PSTAT_RUN
タスク 実行状態
Definition: tcb.h:18
イベントキュー操作
char name[TASK_NAME_LEN+1]
タスク名文字列
Definition: task.h:38
カーネル、ドライバ(非タスク)デバッグ用マクロ
イベント用システムコールパラメータ
Definition: syscall_param.h:55
int id
タスクID
Definition: tcb.h:38
void event_clear_ISR(void *sp, struct st_event *evtque)
イベントカウンタをクリアリセットする
Definition: task.c:838
struct tcb_queue queue
タスクキュー(st_tcb をst_queueにキャストするために必ず最初に定義する)
Definition: tcb.h:33
MUTEX用システムコールパラメータ
Definition: syscall_param.h:65
unsigned int size
1イベントのサイズ
Definition: event.h:19
int event_check_ISR(void *sp, struct st_event *evtque)
イベントカウントを取得する
Definition: task.c:814
タスクコンテキスト
Definition: tcb.h:32
void * stack_addr
スタック先頭アドレス
Definition: tcb.h:41
unsigned int run_time
タスク実行時間
Definition: task.h:41
const char * name
MUTEX名文字列
Definition: mutex.h:17