OSDN Git Service

Change the directry name to hirado
[trx-305dsp/dsp.git] / hirado / kernel / kernel / task.c
1 /*
2  *  TOPPERS/JSP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Just Standard Profile Kernel
5  * 
6  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7  *                              Toyohashi Univ. of Technology, JAPAN
8  *  Copyright (C) 2005,2006 by Embedded and Real-Time Systems Laboratory
9  *              Graduate School of Information Science, Nagoya Univ., JAPAN
10  * 
11  *  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
12  *  によって公表されている GNU General Public License の Version 2 に記
13  *  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
14  *  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
15  *  利用と呼ぶ)することを無償で許諾する.
16  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
17  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
18  *      スコード中に含まれていること.
19  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
20  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
21  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
22  *      の無保証規定を掲載すること.
23  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
24  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
25  *      と.
26  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
27  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
28  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
29  *        報告すること.
30  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
31  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
32  * 
33  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
34  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
35  *  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
36  *  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
37  * 
38  *  @(#) $Id: task.c,v 1.1 2009/01/31 05:27:37 suikan Exp $
39  */
40
41 /*
42  *  タスク管理モジュール
43  */
44
45 #include "jsp_kernel.h"
46 #include "task.h"
47 #include <cpu_context.h>
48
49 #ifdef __tskini
50
51 /*
52  *  実行状態のタスク
53  */
54 TCB *runtsk;
55
56 /*
57  *  最高優先順位のタスク
58  */
59 TCB *schedtsk;
60
61 /*
62  *  タスクディスパッチ/タスク例外処理ルーチン起動要求フラグ
63  */
64 BOOL    reqflg;
65
66 /*
67  *  タスクディスパッチ許可状態
68  */
69 BOOL    enadsp;
70
71 /*
72  *  レディキュー
73  */
74 QUEUE   ready_queue[TNUM_TPRI];
75
76 /*
77  *  レディキューサーチのためのビットマップ
78  *
79  *  ビットマップを UINT で定義しているが,ビットマップサーチ関数で優先
80  *  度が16段階以下であることを仮定している.
81  */
82 UINT    ready_primap;
83
84 /*
85  *  タスク管理モジュールの初期化
86  */
87 void
88 task_initialize()
89 {
90     UINT    i, j;
91     TCB *tcb;
92
93     runtsk = schedtsk = NULL;
94     reqflg = FALSE;
95     enadsp = TRUE;
96
97     for (i = 0; i < TNUM_TPRI; i++) {
98         queue_initialize(&(ready_queue[i]));
99     }
100     ready_primap = 0;
101
102     for (i = 0; i < TNUM_TSK; i++) {
103         j = INDEX_TSK(torder_table[i]);
104         tcb = &(tcb_table[j]);
105         tcb->tinib = &(tinib_table[j]);
106         tcb->actcnt = FALSE;
107         make_dormant(tcb);
108         if ((tcb->tinib->tskatr & TA_ACT) != 0) {
109             make_active(tcb);
110         }
111     }
112 }
113
114 #endif /* __tskini */
115
116 /*
117  *  ビットマップサーチ関数
118  *
119  *  bitmap 内の 1 のビットの内,最も下位(右)のものをサーチし,そのビ
120  *  ット番号を返す.ビット番号は,最下位ビットを 0 とする.bitmap に 0
121  *  を指定してはならない.この関数では,優先度が16段階以下であることを
122  *  仮定し,bitmap の下位16ビットのみをサーチする.
123  *  ビットサーチ命令を持つプロセッサでは,ビットサーチ命令を使うように
124  *  書き直した方が効率が良いだろう.このような場合には,cpu_insn.h で
125  *  ビットサーチ命令を使った bitmap_search を定義し,CPU_BITMAP_SEARCH 
126  *  をマクロ定義すればよい.また,ビットサーチ命令のサーチ方向が逆など
127  *  の理由で優先度とビットとの対応を変更したい場合には,PRIMAP_BIT を
128  *  マクロ定義すればよい.
129  *  また,標準ライブラリに ffs があるなら,次のように定義して標準ライ
130  *  ブラリを使った方が効率が良い可能性もある.
131  *  #define bitmap_search(bitmap) (ffs(bitmap) - 1)
132  */
133 #ifndef PRIMAP_BIT
134 #define PRIMAP_BIT(pri)     (1u << (pri))
135 #endif /* PRIMAP_BIT */
136
137 #ifndef CPU_BITMAP_SEARCH
138
139 Inline UINT
140 bitmap_search(UINT bitmap)
141 {
142     static const unsigned char search_table[] = { 0, 1, 0, 2, 0, 1, 0,
143                         3, 0, 1, 0, 2, 0, 1, 0 };
144     UINT    n = 0;
145
146     assert((bitmap & 0xffff) != 0);
147     if ((bitmap & 0x00ff) == 0) {
148         bitmap >>= 8;
149         n += 8;
150     }
151     if ((bitmap & 0x0f) == 0) {
152         bitmap >>= 4;
153         n += 4;
154     }
155     return(n + search_table[(bitmap & 0x0f) - 1]);
156 }
157
158 #endif /* CPU_BITMAP_SEARCH */
159
160 /*
161  *  最高優先順位タスクのサーチ
162  */
163 #ifdef __tsksched
164
165 TCB *
166 search_schedtsk()
167 {
168     UINT    schedpri;
169
170     schedpri = bitmap_search(ready_primap);
171     return((TCB *)(ready_queue[schedpri].next));
172 }
173
174 #endif /* __tsksched */
175
176 /*
177  *  実行できる状態への移行
178  *
179  *  最高優先順位のタスクを更新するのは,実行できるタスクがなかった場合
180  *  と,tcb の優先度が最高優先順位のタスクの優先度よりも高い場合である.
181  */
182 #ifdef __tskrun
183
184 BOOL
185 make_runnable(TCB *tcb)
186 {
187     UINT    pri = tcb->priority;
188
189     tcb->tstat = TS_RUNNABLE;
190     LOG_TSKSTAT(tcb);
191     queue_insert_prev(&(ready_queue[pri]), &(tcb->task_queue));
192     ready_primap |= PRIMAP_BIT(pri);
193
194     if (schedtsk == (TCB *) NULL || pri < schedtsk->priority) {
195         schedtsk = tcb;
196         return(enadsp);
197     }
198     return(FALSE);
199 }
200
201 #endif /* __tskrun */
202
203 /*
204  *  実行できる状態から他の状態への移行
205  *
206  *  最高優先順位のタスクを更新するのは,tcb が最高優先順位のタスクであっ
207  *  た場合である.tcb と同じ優先度のタスクが他にある場合は,tcb の次の
208  *  タスクが最高優先順位になる.そうでない場合は,レディキューをサーチ
209  *  する必要がある.
210  */
211 #ifdef __tsknrun
212
213 BOOL
214 make_non_runnable(TCB *tcb)
215 {
216     UINT    pri = tcb->priority;
217     QUEUE   *queue = &(ready_queue[pri]);
218
219     queue_delete(&(tcb->task_queue));
220     if (queue_empty(queue)) {
221         ready_primap &= ~PRIMAP_BIT(pri);
222         if (schedtsk == tcb) {
223             schedtsk = (ready_primap == 0) ? (TCB * ) NULL
224                         : search_schedtsk();
225             return(enadsp);
226         }
227     }
228     else {
229         if (schedtsk == tcb) {
230             schedtsk = (TCB *)(queue->next);
231             return(enadsp);
232         }
233     }
234     return(FALSE);
235 }
236
237 #endif /* __tsknrun */
238
239 /*
240  *  休止状態への移行
241  */
242 #ifdef __tskdmt
243
244 void
245 make_dormant(TCB *tcb)
246 {
247     tcb->priority = tcb->tinib->ipriority;
248     tcb->tstat = TS_DORMANT;
249     tcb->wupcnt = FALSE;
250     tcb->enatex = FALSE;
251     tcb->texptn = 0;
252     create_context(tcb);
253     LOG_TSKSTAT(tcb);
254 }
255
256 #endif /* __tskdmt */
257
258 /*
259  *  休止状態から実行できる状態への移行
260  */
261 #ifdef __tskact
262
263 BOOL
264 make_active(TCB *tcb)
265 {
266     activate_context(tcb);
267     return(make_runnable(tcb));
268 }
269
270 #endif /* __tskact */
271
272 /*
273  *  実行状態のタスクの終了
274  */
275 #ifdef __tskext
276
277 void
278 exit_task()
279 {
280     make_non_runnable(runtsk);
281     make_dormant(runtsk);
282     if (runtsk->actcnt) {
283         runtsk->actcnt = FALSE;
284         make_active(runtsk);
285     }
286     exit_and_dispatch();
287 }
288
289 #endif /* __tskext */
290
291 /*
292  *  レディキュー中のタスクの優先度の変更
293  *
294  *  最高優先順位のタスクを更新するのは,(1) tcb が最高優先順位のタスク
295  *  であって,その優先度を下げた場合,(2) tcb が最高優先順位のタスクで
296  *  はなく,変更後の優先度が最高優先順位のタスクの優先度よりも高い場合
297  *  である.(1) の場合には,レディキューをサーチする必要がある.
298  */
299 #ifdef __tskpri
300
301 BOOL
302 change_priority(TCB *tcb, UINT newpri)
303 {
304     UINT    oldpri = tcb->priority;
305
306     tcb->priority = newpri;
307     queue_delete(&(tcb->task_queue));
308     if (queue_empty(&(ready_queue[oldpri]))) {
309         ready_primap &= ~PRIMAP_BIT(oldpri);
310     }
311     queue_insert_prev(&(ready_queue[newpri]), &(tcb->task_queue));
312     ready_primap |= PRIMAP_BIT(newpri);
313
314     if (schedtsk == tcb) {
315         if (newpri >= oldpri) {
316             schedtsk = search_schedtsk();
317             return(schedtsk != tcb && enadsp);
318         }
319     }
320     else {
321         if (newpri < schedtsk->priority) {
322             schedtsk = tcb;
323             return(enadsp);
324         }
325     }
326     return(FALSE);
327 }
328
329 #endif /* __tskpri */
330
331 /*
332  *  レディキューの回転
333  *
334  *  最高優先順位のタスクを更新するのは,最高優先順位のタスクがタスクキ
335  *  ューの末尾に移動した場合である.
336  */
337 #ifdef __tskrot
338
339 BOOL
340 rotate_ready_queue(UINT pri)
341 {
342     QUEUE   *queue = &(ready_queue[pri]);
343     QUEUE   *entry;
344
345     if (!(queue_empty(queue)) && queue->next->next != queue) {
346         entry = queue_delete_next(queue);
347         queue_insert_prev(queue, entry);
348         if (schedtsk == (TCB *) entry) {
349             schedtsk = (TCB *)(queue->next);
350             return(enadsp);
351         }
352     }
353     return(FALSE);
354 }
355
356 #endif /* __tskrot */
357
358 /*
359  *  引数まで定義したタスク例外処理ルーチンの型
360  */
361 typedef void    (*TEXRTN)(TEXPTN texptn, VP_INT exinf);
362
363 /*
364  *  タスク例外処理ルーチンの呼出し
365  */
366 #ifdef __tsktex
367
368 void
369 call_texrtn()
370 {
371     TEXPTN  texptn;
372
373     do {
374         texptn = runtsk->texptn;
375         runtsk->enatex = FALSE;
376         runtsk->texptn = 0;
377         t_unlock_cpu();
378         LOG_TEX_ENTER(texptn);
379         (*((TEXRTN)(runtsk->tinib->texrtn)))(texptn,
380                         runtsk->tinib->exinf);
381         LOG_TEX_LEAVE(texptn);
382         if (!t_sense_lock()) {
383             t_lock_cpu();
384         }
385     } while (runtsk->texptn != 0);
386     runtsk->enatex = TRUE;
387 }
388
389 /*
390  *  タスク例外処理ルーチンの起動
391  */
392 #ifndef OMIT_CALLTEX
393
394 void
395 calltex()
396 {
397     if (runtsk->enatex && runtsk->texptn != 0) {
398         call_texrtn();
399     }
400 }
401
402 #endif /* OMIT_CALLTEX */
403 #endif /* __tsktex */