This is a port of the mruby/c tutorial Chapter 03 to the mbed environment.
For details, refer to the following.
http://www.s-itoc.jp/activity/research/mrubyc/mrubyc_tutorial/436
Note:There is a change in rtt0.h from the original source in the mruby/c. It was necessary for inclusion in C ++ source.
mrubyc/rrt0.c@0:33feccbba3ff, 2017-02-15 (annotated)
- Committer:
- tk_takateku
- Date:
- Wed Feb 15 01:03:35 2017 +0000
- Revision:
- 0:33feccbba3ff
Commit before publishing
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tk_takateku | 0:33feccbba3ff | 1 | /*! @file |
tk_takateku | 0:33feccbba3ff | 2 | @brief |
tk_takateku | 0:33feccbba3ff | 3 | Realtime multitask monitor for mruby/c |
tk_takateku | 0:33feccbba3ff | 4 | |
tk_takateku | 0:33feccbba3ff | 5 | <pre> |
tk_takateku | 0:33feccbba3ff | 6 | Copyright (C) 2016 Kyushu Institute of Technology. |
tk_takateku | 0:33feccbba3ff | 7 | Copyright (C) 2016 Shimane IT Open-Innovation Center. |
tk_takateku | 0:33feccbba3ff | 8 | |
tk_takateku | 0:33feccbba3ff | 9 | This file is distributed under BSD 3-Clause License. |
tk_takateku | 0:33feccbba3ff | 10 | </pre> |
tk_takateku | 0:33feccbba3ff | 11 | */ |
tk_takateku | 0:33feccbba3ff | 12 | |
tk_takateku | 0:33feccbba3ff | 13 | /***** Feature test switches ************************************************/ |
tk_takateku | 0:33feccbba3ff | 14 | /***** System headers *******************************************************/ |
tk_takateku | 0:33feccbba3ff | 15 | #include <stdint.h> |
tk_takateku | 0:33feccbba3ff | 16 | #include <string.h> |
tk_takateku | 0:33feccbba3ff | 17 | #include <assert.h> |
tk_takateku | 0:33feccbba3ff | 18 | |
tk_takateku | 0:33feccbba3ff | 19 | |
tk_takateku | 0:33feccbba3ff | 20 | /***** Local headers ********************************************************/ |
tk_takateku | 0:33feccbba3ff | 21 | #include "alloc.h" |
tk_takateku | 0:33feccbba3ff | 22 | #include "static.h" |
tk_takateku | 0:33feccbba3ff | 23 | #include "load.h" |
tk_takateku | 0:33feccbba3ff | 24 | #include "class.h" |
tk_takateku | 0:33feccbba3ff | 25 | #include "vm.h" |
tk_takateku | 0:33feccbba3ff | 26 | #include "rrt0.h" |
tk_takateku | 0:33feccbba3ff | 27 | #include "hal/hal.h" |
tk_takateku | 0:33feccbba3ff | 28 | |
tk_takateku | 0:33feccbba3ff | 29 | |
tk_takateku | 0:33feccbba3ff | 30 | /***** Constat values *******************************************************/ |
tk_takateku | 0:33feccbba3ff | 31 | const int TIMESLICE_TICK = 10; // 10 * 1ms(HardwareTimer) 255 max |
tk_takateku | 0:33feccbba3ff | 32 | |
tk_takateku | 0:33feccbba3ff | 33 | |
tk_takateku | 0:33feccbba3ff | 34 | /***** Macros ***************************************************************/ |
tk_takateku | 0:33feccbba3ff | 35 | /***** Typedefs *************************************************************/ |
tk_takateku | 0:33feccbba3ff | 36 | /***** Function prototypes **************************************************/ |
tk_takateku | 0:33feccbba3ff | 37 | /***** Local variables ******************************************************/ |
tk_takateku | 0:33feccbba3ff | 38 | static MrbcTcb *q_domant_; |
tk_takateku | 0:33feccbba3ff | 39 | static MrbcTcb *q_ready_; |
tk_takateku | 0:33feccbba3ff | 40 | static MrbcTcb *q_waiting_; |
tk_takateku | 0:33feccbba3ff | 41 | static MrbcTcb *q_suspended_; |
tk_takateku | 0:33feccbba3ff | 42 | static volatile uint32_t tick_; |
tk_takateku | 0:33feccbba3ff | 43 | |
tk_takateku | 0:33feccbba3ff | 44 | |
tk_takateku | 0:33feccbba3ff | 45 | /***** Global variables *****************************************************/ |
tk_takateku | 0:33feccbba3ff | 46 | /***** Signal catching functions ********************************************/ |
tk_takateku | 0:33feccbba3ff | 47 | /***** Local functions ******************************************************/ |
tk_takateku | 0:33feccbba3ff | 48 | |
tk_takateku | 0:33feccbba3ff | 49 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 50 | /*! Insert to task queue |
tk_takateku | 0:33feccbba3ff | 51 | |
tk_takateku | 0:33feccbba3ff | 52 | @param Pointer of target TCB |
tk_takateku | 0:33feccbba3ff | 53 | |
tk_takateku | 0:33feccbba3ff | 54 | 引数で指定されたタスク(TCB)を、状態別Queueに入れる。 |
tk_takateku | 0:33feccbba3ff | 55 | TCBはフリーの状態でなければならない。(別なQueueに入っていてはならない) |
tk_takateku | 0:33feccbba3ff | 56 | Queueはpriority_preemption順にソート済みとなる。 |
tk_takateku | 0:33feccbba3ff | 57 | 挿入するTCBとQueueに同じpriority_preemption値がある場合は、同値の最後に挿入される。 |
tk_takateku | 0:33feccbba3ff | 58 | |
tk_takateku | 0:33feccbba3ff | 59 | */ |
tk_takateku | 0:33feccbba3ff | 60 | static void q_insert_task(MrbcTcb *p_tcb) |
tk_takateku | 0:33feccbba3ff | 61 | { |
tk_takateku | 0:33feccbba3ff | 62 | MrbcTcb **pp_q; |
tk_takateku | 0:33feccbba3ff | 63 | |
tk_takateku | 0:33feccbba3ff | 64 | switch( p_tcb->state ) { |
tk_takateku | 0:33feccbba3ff | 65 | case TASKSTATE_DOMANT: pp_q = &q_domant_; break; |
tk_takateku | 0:33feccbba3ff | 66 | case TASKSTATE_READY: |
tk_takateku | 0:33feccbba3ff | 67 | case TASKSTATE_RUNNING: pp_q = &q_ready_; break; |
tk_takateku | 0:33feccbba3ff | 68 | case TASKSTATE_WAITING: pp_q = &q_waiting_; break; |
tk_takateku | 0:33feccbba3ff | 69 | case TASKSTATE_SUSPENDED: pp_q = &q_suspended_; break; |
tk_takateku | 0:33feccbba3ff | 70 | default: |
tk_takateku | 0:33feccbba3ff | 71 | assert(!"Wrong task state."); |
tk_takateku | 0:33feccbba3ff | 72 | return; |
tk_takateku | 0:33feccbba3ff | 73 | } |
tk_takateku | 0:33feccbba3ff | 74 | |
tk_takateku | 0:33feccbba3ff | 75 | // case insert on top. |
tk_takateku | 0:33feccbba3ff | 76 | if((*pp_q == NULL) || |
tk_takateku | 0:33feccbba3ff | 77 | (p_tcb->priority_preemption < (*pp_q)->priority_preemption)) { |
tk_takateku | 0:33feccbba3ff | 78 | p_tcb->next = *pp_q; |
tk_takateku | 0:33feccbba3ff | 79 | *pp_q = p_tcb; |
tk_takateku | 0:33feccbba3ff | 80 | assert(p_tcb->next != p_tcb); |
tk_takateku | 0:33feccbba3ff | 81 | return; |
tk_takateku | 0:33feccbba3ff | 82 | } |
tk_takateku | 0:33feccbba3ff | 83 | |
tk_takateku | 0:33feccbba3ff | 84 | // find insert point in sorted linked list. |
tk_takateku | 0:33feccbba3ff | 85 | MrbcTcb *p = *pp_q; |
tk_takateku | 0:33feccbba3ff | 86 | while( 1 ) { |
tk_takateku | 0:33feccbba3ff | 87 | if((p->next == NULL) || |
tk_takateku | 0:33feccbba3ff | 88 | (p_tcb->priority_preemption < p->next->priority_preemption)) { |
tk_takateku | 0:33feccbba3ff | 89 | p_tcb->next = p->next; |
tk_takateku | 0:33feccbba3ff | 90 | p->next = p_tcb; |
tk_takateku | 0:33feccbba3ff | 91 | assert(p->next != p); |
tk_takateku | 0:33feccbba3ff | 92 | return; |
tk_takateku | 0:33feccbba3ff | 93 | } |
tk_takateku | 0:33feccbba3ff | 94 | |
tk_takateku | 0:33feccbba3ff | 95 | p = p->next; |
tk_takateku | 0:33feccbba3ff | 96 | } |
tk_takateku | 0:33feccbba3ff | 97 | } |
tk_takateku | 0:33feccbba3ff | 98 | |
tk_takateku | 0:33feccbba3ff | 99 | |
tk_takateku | 0:33feccbba3ff | 100 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 101 | /*! Delete from task queue |
tk_takateku | 0:33feccbba3ff | 102 | |
tk_takateku | 0:33feccbba3ff | 103 | @param Pointer of target TCB |
tk_takateku | 0:33feccbba3ff | 104 | |
tk_takateku | 0:33feccbba3ff | 105 | Queueからタスク(TCB)を取り除く。 |
tk_takateku | 0:33feccbba3ff | 106 | |
tk_takateku | 0:33feccbba3ff | 107 | */ |
tk_takateku | 0:33feccbba3ff | 108 | static void q_delete_task(MrbcTcb *p_tcb) |
tk_takateku | 0:33feccbba3ff | 109 | { |
tk_takateku | 0:33feccbba3ff | 110 | MrbcTcb **pp_q; |
tk_takateku | 0:33feccbba3ff | 111 | |
tk_takateku | 0:33feccbba3ff | 112 | switch( p_tcb->state ) { |
tk_takateku | 0:33feccbba3ff | 113 | case TASKSTATE_DOMANT: pp_q = &q_domant_; break; |
tk_takateku | 0:33feccbba3ff | 114 | case TASKSTATE_READY: |
tk_takateku | 0:33feccbba3ff | 115 | case TASKSTATE_RUNNING: pp_q = &q_ready_; break; |
tk_takateku | 0:33feccbba3ff | 116 | case TASKSTATE_WAITING: pp_q = &q_waiting_; break; |
tk_takateku | 0:33feccbba3ff | 117 | case TASKSTATE_SUSPENDED: pp_q = &q_suspended_; break; |
tk_takateku | 0:33feccbba3ff | 118 | default: |
tk_takateku | 0:33feccbba3ff | 119 | assert(!"Wrong task state."); |
tk_takateku | 0:33feccbba3ff | 120 | return; |
tk_takateku | 0:33feccbba3ff | 121 | } |
tk_takateku | 0:33feccbba3ff | 122 | |
tk_takateku | 0:33feccbba3ff | 123 | if( *pp_q == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 124 | if( *pp_q == p_tcb ) { |
tk_takateku | 0:33feccbba3ff | 125 | *pp_q = p_tcb->next; |
tk_takateku | 0:33feccbba3ff | 126 | p_tcb->next = NULL; |
tk_takateku | 0:33feccbba3ff | 127 | return; |
tk_takateku | 0:33feccbba3ff | 128 | } |
tk_takateku | 0:33feccbba3ff | 129 | |
tk_takateku | 0:33feccbba3ff | 130 | MrbcTcb *p = *pp_q; |
tk_takateku | 0:33feccbba3ff | 131 | while( p ) { |
tk_takateku | 0:33feccbba3ff | 132 | if( p->next == p_tcb ) { |
tk_takateku | 0:33feccbba3ff | 133 | p->next = p_tcb->next; |
tk_takateku | 0:33feccbba3ff | 134 | p_tcb->next = NULL; |
tk_takateku | 0:33feccbba3ff | 135 | return; |
tk_takateku | 0:33feccbba3ff | 136 | } |
tk_takateku | 0:33feccbba3ff | 137 | |
tk_takateku | 0:33feccbba3ff | 138 | p = p->next; |
tk_takateku | 0:33feccbba3ff | 139 | } |
tk_takateku | 0:33feccbba3ff | 140 | } |
tk_takateku | 0:33feccbba3ff | 141 | |
tk_takateku | 0:33feccbba3ff | 142 | |
tk_takateku | 0:33feccbba3ff | 143 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 144 | /*! Find requested task |
tk_takateku | 0:33feccbba3ff | 145 | |
tk_takateku | 0:33feccbba3ff | 146 | @param Pointer of vm |
tk_takateku | 0:33feccbba3ff | 147 | @return Pointer of MrbcTcb. zero is not found. |
tk_takateku | 0:33feccbba3ff | 148 | */ |
tk_takateku | 0:33feccbba3ff | 149 | static inline MrbcTcb* find_requested_task(mrb_vm *vm) |
tk_takateku | 0:33feccbba3ff | 150 | { |
tk_takateku | 0:33feccbba3ff | 151 | MrbcTcb *tcb; |
tk_takateku | 0:33feccbba3ff | 152 | |
tk_takateku | 0:33feccbba3ff | 153 | for( tcb = q_ready_; tcb != NULL; tcb = tcb->next ) { |
tk_takateku | 0:33feccbba3ff | 154 | if( tcb->vm == vm ) break; |
tk_takateku | 0:33feccbba3ff | 155 | } |
tk_takateku | 0:33feccbba3ff | 156 | |
tk_takateku | 0:33feccbba3ff | 157 | return tcb; |
tk_takateku | 0:33feccbba3ff | 158 | } |
tk_takateku | 0:33feccbba3ff | 159 | |
tk_takateku | 0:33feccbba3ff | 160 | |
tk_takateku | 0:33feccbba3ff | 161 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 162 | /*! 一定時間停止(cruby互換) |
tk_takateku | 0:33feccbba3ff | 163 | |
tk_takateku | 0:33feccbba3ff | 164 | */ |
tk_takateku | 0:33feccbba3ff | 165 | static void c_sleep(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 166 | { |
tk_takateku | 0:33feccbba3ff | 167 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 168 | |
tk_takateku | 0:33feccbba3ff | 169 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 170 | |
tk_takateku | 0:33feccbba3ff | 171 | switch( v[1].tt ) { |
tk_takateku | 0:33feccbba3ff | 172 | case MRB_TT_FIXNUM: |
tk_takateku | 0:33feccbba3ff | 173 | mrbc_sleep_ms(tcb, GET_INT_ARG(0) * 1000); |
tk_takateku | 0:33feccbba3ff | 174 | break; |
tk_takateku | 0:33feccbba3ff | 175 | |
tk_takateku | 0:33feccbba3ff | 176 | case MRB_TT_FLOAT: |
tk_takateku | 0:33feccbba3ff | 177 | mrbc_sleep_ms(tcb, (uint32_t)(GET_FLOAT_ARG(0) * 1000)); |
tk_takateku | 0:33feccbba3ff | 178 | break; |
tk_takateku | 0:33feccbba3ff | 179 | |
tk_takateku | 0:33feccbba3ff | 180 | default: |
tk_takateku | 0:33feccbba3ff | 181 | |
tk_takateku | 0:33feccbba3ff | 182 | // TODO 引数なしの場合は永久停止 |
tk_takateku | 0:33feccbba3ff | 183 | break; |
tk_takateku | 0:33feccbba3ff | 184 | } |
tk_takateku | 0:33feccbba3ff | 185 | } |
tk_takateku | 0:33feccbba3ff | 186 | |
tk_takateku | 0:33feccbba3ff | 187 | |
tk_takateku | 0:33feccbba3ff | 188 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 189 | /*! 一定時間停止(ms単位) |
tk_takateku | 0:33feccbba3ff | 190 | |
tk_takateku | 0:33feccbba3ff | 191 | */ |
tk_takateku | 0:33feccbba3ff | 192 | static void c_sleep_ms(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 193 | { |
tk_takateku | 0:33feccbba3ff | 194 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 195 | |
tk_takateku | 0:33feccbba3ff | 196 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 197 | |
tk_takateku | 0:33feccbba3ff | 198 | mrbc_sleep_ms(tcb, GET_INT_ARG(0)); |
tk_takateku | 0:33feccbba3ff | 199 | } |
tk_takateku | 0:33feccbba3ff | 200 | |
tk_takateku | 0:33feccbba3ff | 201 | |
tk_takateku | 0:33feccbba3ff | 202 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 203 | /*! 実行権を手放す |
tk_takateku | 0:33feccbba3ff | 204 | |
tk_takateku | 0:33feccbba3ff | 205 | */ |
tk_takateku | 0:33feccbba3ff | 206 | static void c_relinquish(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 207 | { |
tk_takateku | 0:33feccbba3ff | 208 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 209 | |
tk_takateku | 0:33feccbba3ff | 210 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 211 | |
tk_takateku | 0:33feccbba3ff | 212 | mrbc_relinquish(tcb); |
tk_takateku | 0:33feccbba3ff | 213 | } |
tk_takateku | 0:33feccbba3ff | 214 | |
tk_takateku | 0:33feccbba3ff | 215 | |
tk_takateku | 0:33feccbba3ff | 216 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 217 | /*! プライオリティー変更 |
tk_takateku | 0:33feccbba3ff | 218 | |
tk_takateku | 0:33feccbba3ff | 219 | */ |
tk_takateku | 0:33feccbba3ff | 220 | static void c_change_priority(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 221 | { |
tk_takateku | 0:33feccbba3ff | 222 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 223 | |
tk_takateku | 0:33feccbba3ff | 224 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 225 | |
tk_takateku | 0:33feccbba3ff | 226 | mrbc_change_priority(tcb, GET_INT_ARG(0)); |
tk_takateku | 0:33feccbba3ff | 227 | } |
tk_takateku | 0:33feccbba3ff | 228 | |
tk_takateku | 0:33feccbba3ff | 229 | |
tk_takateku | 0:33feccbba3ff | 230 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 231 | /*! 実行停止 |
tk_takateku | 0:33feccbba3ff | 232 | |
tk_takateku | 0:33feccbba3ff | 233 | */ |
tk_takateku | 0:33feccbba3ff | 234 | static void c_suspend_task(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 235 | { |
tk_takateku | 0:33feccbba3ff | 236 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 237 | |
tk_takateku | 0:33feccbba3ff | 238 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 239 | |
tk_takateku | 0:33feccbba3ff | 240 | mrbc_suspend_task(tcb); |
tk_takateku | 0:33feccbba3ff | 241 | } |
tk_takateku | 0:33feccbba3ff | 242 | |
tk_takateku | 0:33feccbba3ff | 243 | |
tk_takateku | 0:33feccbba3ff | 244 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 245 | /*! 実行再開 |
tk_takateku | 0:33feccbba3ff | 246 | |
tk_takateku | 0:33feccbba3ff | 247 | */ |
tk_takateku | 0:33feccbba3ff | 248 | static void c_resume_task(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 249 | { |
tk_takateku | 0:33feccbba3ff | 250 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 251 | |
tk_takateku | 0:33feccbba3ff | 252 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 253 | |
tk_takateku | 0:33feccbba3ff | 254 | // TODO: 未デバグ。引数で与えられたTCBのタスクを実行再開する。 |
tk_takateku | 0:33feccbba3ff | 255 | mrbc_resume_task(tcb); |
tk_takateku | 0:33feccbba3ff | 256 | } |
tk_takateku | 0:33feccbba3ff | 257 | |
tk_takateku | 0:33feccbba3ff | 258 | |
tk_takateku | 0:33feccbba3ff | 259 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 260 | /*! TCBを得る |
tk_takateku | 0:33feccbba3ff | 261 | |
tk_takateku | 0:33feccbba3ff | 262 | */ |
tk_takateku | 0:33feccbba3ff | 263 | static void c_get_tcb(mrb_vm *vm, mrb_value *v) |
tk_takateku | 0:33feccbba3ff | 264 | { |
tk_takateku | 0:33feccbba3ff | 265 | MrbcTcb *tcb = find_requested_task(vm); |
tk_takateku | 0:33feccbba3ff | 266 | |
tk_takateku | 0:33feccbba3ff | 267 | if( tcb == NULL ) return; |
tk_takateku | 0:33feccbba3ff | 268 | |
tk_takateku | 0:33feccbba3ff | 269 | // TODO: 未実装。TCBポインタをオブジェクトとして返す。 |
tk_takateku | 0:33feccbba3ff | 270 | } |
tk_takateku | 0:33feccbba3ff | 271 | |
tk_takateku | 0:33feccbba3ff | 272 | |
tk_takateku | 0:33feccbba3ff | 273 | /***** Global functions *****************************************************/ |
tk_takateku | 0:33feccbba3ff | 274 | |
tk_takateku | 0:33feccbba3ff | 275 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 276 | /*! Tick timer interrupt handler. |
tk_takateku | 0:33feccbba3ff | 277 | |
tk_takateku | 0:33feccbba3ff | 278 | */ |
tk_takateku | 0:33feccbba3ff | 279 | void mrbc_tick(void) |
tk_takateku | 0:33feccbba3ff | 280 | { |
tk_takateku | 0:33feccbba3ff | 281 | MrbcTcb *tcb; |
tk_takateku | 0:33feccbba3ff | 282 | int flag_preemption = 0; |
tk_takateku | 0:33feccbba3ff | 283 | |
tk_takateku | 0:33feccbba3ff | 284 | tick_++; |
tk_takateku | 0:33feccbba3ff | 285 | |
tk_takateku | 0:33feccbba3ff | 286 | // 実行中タスクのタイムスライス値を減らす |
tk_takateku | 0:33feccbba3ff | 287 | tcb = q_ready_; |
tk_takateku | 0:33feccbba3ff | 288 | if((tcb != NULL) && |
tk_takateku | 0:33feccbba3ff | 289 | (tcb->state == TASKSTATE_RUNNING) && |
tk_takateku | 0:33feccbba3ff | 290 | (tcb->timeslice > 0)) { |
tk_takateku | 0:33feccbba3ff | 291 | tcb->timeslice--; |
tk_takateku | 0:33feccbba3ff | 292 | if( tcb->timeslice == 0 ) tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 293 | } |
tk_takateku | 0:33feccbba3ff | 294 | |
tk_takateku | 0:33feccbba3ff | 295 | // 待ちタスクキューから、ウェイクアップすべきタスクを探す |
tk_takateku | 0:33feccbba3ff | 296 | tcb = q_waiting_; |
tk_takateku | 0:33feccbba3ff | 297 | while( tcb != NULL ) { |
tk_takateku | 0:33feccbba3ff | 298 | MrbcTcb *t = tcb; |
tk_takateku | 0:33feccbba3ff | 299 | tcb = tcb->next; |
tk_takateku | 0:33feccbba3ff | 300 | |
tk_takateku | 0:33feccbba3ff | 301 | if( t->wakeup_tick == tick_ ) { |
tk_takateku | 0:33feccbba3ff | 302 | q_delete_task(t); |
tk_takateku | 0:33feccbba3ff | 303 | t->state = TASKSTATE_READY; |
tk_takateku | 0:33feccbba3ff | 304 | t->timeslice = TIMESLICE_TICK; |
tk_takateku | 0:33feccbba3ff | 305 | q_insert_task(t); |
tk_takateku | 0:33feccbba3ff | 306 | flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 307 | } |
tk_takateku | 0:33feccbba3ff | 308 | } |
tk_takateku | 0:33feccbba3ff | 309 | |
tk_takateku | 0:33feccbba3ff | 310 | if( flag_preemption ) { |
tk_takateku | 0:33feccbba3ff | 311 | tcb = q_ready_; |
tk_takateku | 0:33feccbba3ff | 312 | while( tcb != NULL ) { |
tk_takateku | 0:33feccbba3ff | 313 | if( tcb->state == TASKSTATE_RUNNING ) tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 314 | tcb = tcb->next; |
tk_takateku | 0:33feccbba3ff | 315 | } |
tk_takateku | 0:33feccbba3ff | 316 | } |
tk_takateku | 0:33feccbba3ff | 317 | } |
tk_takateku | 0:33feccbba3ff | 318 | |
tk_takateku | 0:33feccbba3ff | 319 | |
tk_takateku | 0:33feccbba3ff | 320 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 321 | /*! initialize |
tk_takateku | 0:33feccbba3ff | 322 | |
tk_takateku | 0:33feccbba3ff | 323 | */ |
tk_takateku | 0:33feccbba3ff | 324 | void mrbc_init(void) |
tk_takateku | 0:33feccbba3ff | 325 | { |
tk_takateku | 0:33feccbba3ff | 326 | mrbc_init_alloc(); |
tk_takateku | 0:33feccbba3ff | 327 | init_static(); |
tk_takateku | 0:33feccbba3ff | 328 | hal_init(); |
tk_takateku | 0:33feccbba3ff | 329 | |
tk_takateku | 0:33feccbba3ff | 330 | |
tk_takateku | 0:33feccbba3ff | 331 | // TODO 関数呼び出しが、c_XXX => mrbc_XXX の daisy chain になっている。 |
tk_takateku | 0:33feccbba3ff | 332 | // 不要な複雑さかもしれない。要リファクタリング。 |
tk_takateku | 0:33feccbba3ff | 333 | mrbc_define_method(0, mrbc_class_object, "sleep", c_sleep); |
tk_takateku | 0:33feccbba3ff | 334 | mrbc_define_method(0, mrbc_class_object, "sleep_ms", c_sleep_ms); |
tk_takateku | 0:33feccbba3ff | 335 | mrbc_define_method(0, mrbc_class_object, "relinquish", c_relinquish); |
tk_takateku | 0:33feccbba3ff | 336 | mrbc_define_method(0, mrbc_class_object, "change_priority", c_change_priority); |
tk_takateku | 0:33feccbba3ff | 337 | mrbc_define_method(0, mrbc_class_object, "suspend_task", c_suspend_task); |
tk_takateku | 0:33feccbba3ff | 338 | mrbc_define_method(0, mrbc_class_object, "resume_task", c_resume_task); |
tk_takateku | 0:33feccbba3ff | 339 | } |
tk_takateku | 0:33feccbba3ff | 340 | |
tk_takateku | 0:33feccbba3ff | 341 | |
tk_takateku | 0:33feccbba3ff | 342 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 343 | /*! specify running VM code. |
tk_takateku | 0:33feccbba3ff | 344 | |
tk_takateku | 0:33feccbba3ff | 345 | @param vm_code pointer of VM byte code. |
tk_takateku | 0:33feccbba3ff | 346 | @param tcb Task control block with parameter, or NULL. |
tk_takateku | 0:33feccbba3ff | 347 | @retval Pointer of MrbcTcb. |
tk_takateku | 0:33feccbba3ff | 348 | @retval NULL is error. |
tk_takateku | 0:33feccbba3ff | 349 | |
tk_takateku | 0:33feccbba3ff | 350 | */ |
tk_takateku | 0:33feccbba3ff | 351 | MrbcTcb* mrbc_create_task(const uint8_t *vm_code, MrbcTcb *tcb) |
tk_takateku | 0:33feccbba3ff | 352 | { |
tk_takateku | 0:33feccbba3ff | 353 | // allocate Task Control Block |
tk_takateku | 0:33feccbba3ff | 354 | if( tcb == NULL ) { |
tk_takateku | 0:33feccbba3ff | 355 | tcb = (MrbcTcb*)mrbc_raw_alloc( sizeof(MrbcTcb) ); |
tk_takateku | 0:33feccbba3ff | 356 | if( tcb == NULL ) return NULL; // ENOMEM |
tk_takateku | 0:33feccbba3ff | 357 | |
tk_takateku | 0:33feccbba3ff | 358 | static const MrbcTcb init_val = MRBC_TCB_INITIALIZER; |
tk_takateku | 0:33feccbba3ff | 359 | *tcb = init_val; |
tk_takateku | 0:33feccbba3ff | 360 | } |
tk_takateku | 0:33feccbba3ff | 361 | tcb->timeslice = TIMESLICE_TICK; |
tk_takateku | 0:33feccbba3ff | 362 | tcb->priority_preemption = tcb->priority; |
tk_takateku | 0:33feccbba3ff | 363 | |
tk_takateku | 0:33feccbba3ff | 364 | // assign VM on TCB |
tk_takateku | 0:33feccbba3ff | 365 | if( tcb->state != TASKSTATE_DOMANT ) { |
tk_takateku | 0:33feccbba3ff | 366 | tcb->vm = vm_open(); |
tk_takateku | 0:33feccbba3ff | 367 | if( !tcb->vm ) return 0; // error. can't open VM. |
tk_takateku | 0:33feccbba3ff | 368 | // NOTE: memory leak MrbcTcb. but ignore. |
tk_takateku | 0:33feccbba3ff | 369 | |
tk_takateku | 0:33feccbba3ff | 370 | loca_mrb_array(tcb->vm, vm_code); |
tk_takateku | 0:33feccbba3ff | 371 | vm_boot(tcb->vm); |
tk_takateku | 0:33feccbba3ff | 372 | } |
tk_takateku | 0:33feccbba3ff | 373 | |
tk_takateku | 0:33feccbba3ff | 374 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 375 | q_insert_task(tcb); |
tk_takateku | 0:33feccbba3ff | 376 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 377 | |
tk_takateku | 0:33feccbba3ff | 378 | return tcb; |
tk_takateku | 0:33feccbba3ff | 379 | } |
tk_takateku | 0:33feccbba3ff | 380 | |
tk_takateku | 0:33feccbba3ff | 381 | |
tk_takateku | 0:33feccbba3ff | 382 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 383 | /*! execute |
tk_takateku | 0:33feccbba3ff | 384 | |
tk_takateku | 0:33feccbba3ff | 385 | */ |
tk_takateku | 0:33feccbba3ff | 386 | int mrbc_run(void) |
tk_takateku | 0:33feccbba3ff | 387 | { |
tk_takateku | 0:33feccbba3ff | 388 | while( 1 ) { |
tk_takateku | 0:33feccbba3ff | 389 | MrbcTcb *tcb = q_ready_; |
tk_takateku | 0:33feccbba3ff | 390 | if( tcb == NULL ) { |
tk_takateku | 0:33feccbba3ff | 391 | // 実行すべきタスクなし |
tk_takateku | 0:33feccbba3ff | 392 | hal_idle_cpu(); |
tk_takateku | 0:33feccbba3ff | 393 | continue; |
tk_takateku | 0:33feccbba3ff | 394 | } |
tk_takateku | 0:33feccbba3ff | 395 | |
tk_takateku | 0:33feccbba3ff | 396 | // 実行開始 |
tk_takateku | 0:33feccbba3ff | 397 | tcb->state = TASKSTATE_RUNNING; |
tk_takateku | 0:33feccbba3ff | 398 | int res = 0; |
tk_takateku | 0:33feccbba3ff | 399 | |
tk_takateku | 0:33feccbba3ff | 400 | #ifndef MRBC_NO_TIMER |
tk_takateku | 0:33feccbba3ff | 401 | tcb->vm->flag_preemption = 0; |
tk_takateku | 0:33feccbba3ff | 402 | res = vm_run(tcb->vm); |
tk_takateku | 0:33feccbba3ff | 403 | |
tk_takateku | 0:33feccbba3ff | 404 | #else |
tk_takateku | 0:33feccbba3ff | 405 | while( tcb->timeslice > 0 ) { |
tk_takateku | 0:33feccbba3ff | 406 | tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 407 | res = vm_run(tcb->vm); |
tk_takateku | 0:33feccbba3ff | 408 | tcb->timeslice--; |
tk_takateku | 0:33feccbba3ff | 409 | if( res < 0 ) break; |
tk_takateku | 0:33feccbba3ff | 410 | if( tcb->state != TASKSTATE_RUNNING ) break; |
tk_takateku | 0:33feccbba3ff | 411 | } |
tk_takateku | 0:33feccbba3ff | 412 | mrbc_tick(); |
tk_takateku | 0:33feccbba3ff | 413 | #endif /* ifndef MRBC_NO_TIMER */ |
tk_takateku | 0:33feccbba3ff | 414 | |
tk_takateku | 0:33feccbba3ff | 415 | // タスク終了? |
tk_takateku | 0:33feccbba3ff | 416 | if( res < 0 ) { |
tk_takateku | 0:33feccbba3ff | 417 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 418 | q_delete_task(tcb); |
tk_takateku | 0:33feccbba3ff | 419 | tcb->state = TASKSTATE_DOMANT; |
tk_takateku | 0:33feccbba3ff | 420 | q_insert_task(tcb); |
tk_takateku | 0:33feccbba3ff | 421 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 422 | vm_close(tcb->vm); |
tk_takateku | 0:33feccbba3ff | 423 | tcb->vm = 0; |
tk_takateku | 0:33feccbba3ff | 424 | |
tk_takateku | 0:33feccbba3ff | 425 | if( q_ready_ == NULL && q_waiting_ == NULL && |
tk_takateku | 0:33feccbba3ff | 426 | q_suspended_ == NULL ) break; |
tk_takateku | 0:33feccbba3ff | 427 | continue; |
tk_takateku | 0:33feccbba3ff | 428 | } |
tk_takateku | 0:33feccbba3ff | 429 | |
tk_takateku | 0:33feccbba3ff | 430 | // タスク切り替え |
tk_takateku | 0:33feccbba3ff | 431 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 432 | if( tcb->state == TASKSTATE_RUNNING ) { |
tk_takateku | 0:33feccbba3ff | 433 | tcb->state = TASKSTATE_READY; |
tk_takateku | 0:33feccbba3ff | 434 | |
tk_takateku | 0:33feccbba3ff | 435 | // タイムスライス終了? |
tk_takateku | 0:33feccbba3ff | 436 | if( tcb->timeslice == 0 ) { |
tk_takateku | 0:33feccbba3ff | 437 | q_delete_task(tcb); |
tk_takateku | 0:33feccbba3ff | 438 | tcb->timeslice = TIMESLICE_TICK; |
tk_takateku | 0:33feccbba3ff | 439 | q_insert_task(tcb); // insert task on queue last. |
tk_takateku | 0:33feccbba3ff | 440 | } |
tk_takateku | 0:33feccbba3ff | 441 | } |
tk_takateku | 0:33feccbba3ff | 442 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 443 | } |
tk_takateku | 0:33feccbba3ff | 444 | |
tk_takateku | 0:33feccbba3ff | 445 | return 0; |
tk_takateku | 0:33feccbba3ff | 446 | } |
tk_takateku | 0:33feccbba3ff | 447 | |
tk_takateku | 0:33feccbba3ff | 448 | |
tk_takateku | 0:33feccbba3ff | 449 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 450 | /*! 実行一時停止 |
tk_takateku | 0:33feccbba3ff | 451 | |
tk_takateku | 0:33feccbba3ff | 452 | */ |
tk_takateku | 0:33feccbba3ff | 453 | void mrbc_sleep_ms(MrbcTcb *tcb, uint32_t ms) |
tk_takateku | 0:33feccbba3ff | 454 | { |
tk_takateku | 0:33feccbba3ff | 455 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 456 | q_delete_task(tcb); |
tk_takateku | 0:33feccbba3ff | 457 | tcb->timeslice = 0; |
tk_takateku | 0:33feccbba3ff | 458 | tcb->state = TASKSTATE_WAITING; |
tk_takateku | 0:33feccbba3ff | 459 | tcb->wakeup_tick = tick_ + ms; |
tk_takateku | 0:33feccbba3ff | 460 | q_insert_task(tcb); |
tk_takateku | 0:33feccbba3ff | 461 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 462 | |
tk_takateku | 0:33feccbba3ff | 463 | tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 464 | } |
tk_takateku | 0:33feccbba3ff | 465 | |
tk_takateku | 0:33feccbba3ff | 466 | |
tk_takateku | 0:33feccbba3ff | 467 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 468 | /*! 実行権を手放す |
tk_takateku | 0:33feccbba3ff | 469 | |
tk_takateku | 0:33feccbba3ff | 470 | */ |
tk_takateku | 0:33feccbba3ff | 471 | void mrbc_relinquish(MrbcTcb *tcb) |
tk_takateku | 0:33feccbba3ff | 472 | { |
tk_takateku | 0:33feccbba3ff | 473 | tcb->timeslice = 0; |
tk_takateku | 0:33feccbba3ff | 474 | tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 475 | } |
tk_takateku | 0:33feccbba3ff | 476 | |
tk_takateku | 0:33feccbba3ff | 477 | |
tk_takateku | 0:33feccbba3ff | 478 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 479 | /*! プライオリティーの変更 |
tk_takateku | 0:33feccbba3ff | 480 | TODO: No check, yet. |
tk_takateku | 0:33feccbba3ff | 481 | */ |
tk_takateku | 0:33feccbba3ff | 482 | void mrbc_change_priority(MrbcTcb *tcb, int priority) |
tk_takateku | 0:33feccbba3ff | 483 | { |
tk_takateku | 0:33feccbba3ff | 484 | tcb->priority = (uint8_t)priority; |
tk_takateku | 0:33feccbba3ff | 485 | tcb->priority_preemption = (uint8_t)priority; |
tk_takateku | 0:33feccbba3ff | 486 | tcb->timeslice = 0; |
tk_takateku | 0:33feccbba3ff | 487 | tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 488 | } |
tk_takateku | 0:33feccbba3ff | 489 | |
tk_takateku | 0:33feccbba3ff | 490 | |
tk_takateku | 0:33feccbba3ff | 491 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 492 | /*! 実行停止 |
tk_takateku | 0:33feccbba3ff | 493 | |
tk_takateku | 0:33feccbba3ff | 494 | */ |
tk_takateku | 0:33feccbba3ff | 495 | void mrbc_suspend_task(MrbcTcb *tcb) |
tk_takateku | 0:33feccbba3ff | 496 | { |
tk_takateku | 0:33feccbba3ff | 497 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 498 | q_delete_task(tcb); |
tk_takateku | 0:33feccbba3ff | 499 | tcb->state = TASKSTATE_SUSPENDED; |
tk_takateku | 0:33feccbba3ff | 500 | q_insert_task(tcb); |
tk_takateku | 0:33feccbba3ff | 501 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 502 | |
tk_takateku | 0:33feccbba3ff | 503 | tcb->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 504 | } |
tk_takateku | 0:33feccbba3ff | 505 | |
tk_takateku | 0:33feccbba3ff | 506 | |
tk_takateku | 0:33feccbba3ff | 507 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 508 | /*! 実行再開 |
tk_takateku | 0:33feccbba3ff | 509 | |
tk_takateku | 0:33feccbba3ff | 510 | */ |
tk_takateku | 0:33feccbba3ff | 511 | void mrbc_resume_task(MrbcTcb *tcb) |
tk_takateku | 0:33feccbba3ff | 512 | { |
tk_takateku | 0:33feccbba3ff | 513 | hal_disable_irq(); |
tk_takateku | 0:33feccbba3ff | 514 | |
tk_takateku | 0:33feccbba3ff | 515 | MrbcTcb *t = q_ready_; |
tk_takateku | 0:33feccbba3ff | 516 | while( t != NULL ) { |
tk_takateku | 0:33feccbba3ff | 517 | if( t->state == TASKSTATE_RUNNING ) t->vm->flag_preemption = 1; |
tk_takateku | 0:33feccbba3ff | 518 | t = t->next; |
tk_takateku | 0:33feccbba3ff | 519 | } |
tk_takateku | 0:33feccbba3ff | 520 | |
tk_takateku | 0:33feccbba3ff | 521 | q_delete_task(tcb); |
tk_takateku | 0:33feccbba3ff | 522 | tcb->state = TASKSTATE_READY; |
tk_takateku | 0:33feccbba3ff | 523 | q_insert_task(tcb); |
tk_takateku | 0:33feccbba3ff | 524 | hal_enable_irq(); |
tk_takateku | 0:33feccbba3ff | 525 | } |
tk_takateku | 0:33feccbba3ff | 526 | |
tk_takateku | 0:33feccbba3ff | 527 | |
tk_takateku | 0:33feccbba3ff | 528 | #ifdef MRBC_DEBUG |
tk_takateku | 0:33feccbba3ff | 529 | #include "console.h" |
tk_takateku | 0:33feccbba3ff | 530 | |
tk_takateku | 0:33feccbba3ff | 531 | //================================================================ |
tk_takateku | 0:33feccbba3ff | 532 | /*! DEBUG print queue |
tk_takateku | 0:33feccbba3ff | 533 | |
tk_takateku | 0:33feccbba3ff | 534 | */ |
tk_takateku | 0:33feccbba3ff | 535 | void pq(MrbcTcb *p_tcb) |
tk_takateku | 0:33feccbba3ff | 536 | { |
tk_takateku | 0:33feccbba3ff | 537 | MrbcTcb *p; |
tk_takateku | 0:33feccbba3ff | 538 | |
tk_takateku | 0:33feccbba3ff | 539 | p = p_tcb; |
tk_takateku | 0:33feccbba3ff | 540 | while( p != NULL ) { |
tk_takateku | 0:33feccbba3ff | 541 | console_printf("%08x ", (int)((uint64_t)p & 0xffffffff)); |
tk_takateku | 0:33feccbba3ff | 542 | p = p->next; |
tk_takateku | 0:33feccbba3ff | 543 | } |
tk_takateku | 0:33feccbba3ff | 544 | console_printf("\n"); |
tk_takateku | 0:33feccbba3ff | 545 | |
tk_takateku | 0:33feccbba3ff | 546 | p = p_tcb; |
tk_takateku | 0:33feccbba3ff | 547 | while( p != NULL ) { |
tk_takateku | 0:33feccbba3ff | 548 | console_printf(" pri: %2d ", p->priority_preemption); |
tk_takateku | 0:33feccbba3ff | 549 | p = p->next; |
tk_takateku | 0:33feccbba3ff | 550 | } |
tk_takateku | 0:33feccbba3ff | 551 | console_printf("\n"); |
tk_takateku | 0:33feccbba3ff | 552 | |
tk_takateku | 0:33feccbba3ff | 553 | p = p_tcb; |
tk_takateku | 0:33feccbba3ff | 554 | while( p != NULL ) { |
tk_takateku | 0:33feccbba3ff | 555 | console_printf(" nx:%04x ", (int)((uint64_t)p->next & 0xffff)); |
tk_takateku | 0:33feccbba3ff | 556 | p = p->next; |
tk_takateku | 0:33feccbba3ff | 557 | } |
tk_takateku | 0:33feccbba3ff | 558 | console_printf("\n"); |
tk_takateku | 0:33feccbba3ff | 559 | } |
tk_takateku | 0:33feccbba3ff | 560 | |
tk_takateku | 0:33feccbba3ff | 561 | |
tk_takateku | 0:33feccbba3ff | 562 | void pqall(void) |
tk_takateku | 0:33feccbba3ff | 563 | { |
tk_takateku | 0:33feccbba3ff | 564 | // console_printf("<<<<< DOMANT >>>>>\n"); |
tk_takateku | 0:33feccbba3ff | 565 | // pq(q_domant_); |
tk_takateku | 0:33feccbba3ff | 566 | console_printf("<<<<< READY >>>>>\n"); |
tk_takateku | 0:33feccbba3ff | 567 | pq(q_ready_); |
tk_takateku | 0:33feccbba3ff | 568 | console_printf("<<<<< WAITING >>>>>\n"); |
tk_takateku | 0:33feccbba3ff | 569 | pq(q_waiting_); |
tk_takateku | 0:33feccbba3ff | 570 | console_printf("<<<<< SUSPENDED >>>>>\n"); |
tk_takateku | 0:33feccbba3ff | 571 | pq(q_suspended_); |
tk_takateku | 0:33feccbba3ff | 572 | } |
tk_takateku | 0:33feccbba3ff | 573 | #endif |
tk_takateku | 0:33feccbba3ff | 574 |