task.h

説明を見る。
00001 /*
00002  *  TOPPERS/ASP Kernel
00003  *      Toyohashi Open Platform for Embedded Real-Time Systems/
00004  *      Advanced Standard Profile Kernel
00005  * 
00006  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
00007  *                              Toyohashi Univ. of Technology, JAPAN
00008  *  Copyright (C) 2005-2008 by Embedded and Real-Time Systems Laboratory
00009  *              Graduate School of Information Science, Nagoya Univ., JAPAN
00010  * 
00011  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
00012  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
00013  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
00014  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
00015  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
00016  *      スコード中に含まれていること.
00017  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
00018  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
00019  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
00020  *      の無保証規定を掲載すること.
00021  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
00022  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
00023  *      と.
00024  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
00025  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
00026  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
00027  *        報告すること.
00028  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
00029  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
00030  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
00031  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
00032  *      免責すること.
00033  * 
00034  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
00035  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
00036  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
00037  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
00038  *  の責任を負わない.
00039  * 
00040  *  @(#) $Id: task.h 748 2008-03-07 17:18:06Z hiro $
00041  */
00042 
00043 /*
00044  *      タスク管理モジュール
00045  */
00046 
00047 #ifndef TOPPERS_TASK_H
00048 #define TOPPERS_TASK_H
00049 
00050 #include <queue.h>
00051 #include "time_event.h"
00052 
00053 /*
00054  *  トレースログマクロのデフォルト定義
00055  */
00056 #ifndef LOG_TSKSTAT
00057 #define LOG_TSKSTAT(p_tcb)
00058 #endif /* LOG_TSKSTAT */
00059 
00060 /*
00061  *  タスク優先度の内部表現・外部表現変換マクロ
00062  */
00063 #define INT_PRIORITY(x)     ((uint_t)((x) - TMIN_TPRI))
00064 #define EXT_TSKPRI(x)       ((PRI)(x) + TMIN_TPRI)
00065 
00066 /*
00067  *  タスク状態の内部表現
00068  *
00069  *  TCB中のタスク状態では,実行状態(RUNNING)と実行可能状態(READY)
00070  *  は区別しない.両状態を総称して,実行できる状態(RUNNABLE)と呼ぶ.
00071  *  二重待ち状態は,(TS_WAITING | TS_SUSPENDED)で表す.TS_WAIT_???は待
00072  *  ち要因を表し,待ち状態(二重待ち状態を含む)の場合にのみ設定する.
00073  */
00074 #define TS_DORMANT      0x00U           /* 休止状態 */
00075 #define TS_RUNNABLE     0x01U           /* 実行できる状態 */
00076 #define TS_WAITING      0x02U           /* 待ち状態 */
00077 #define TS_SUSPENDED    0x04U           /* 強制待ち状態 */
00078 
00079 #define TS_WAIT_DLY     (0x00U << 3)    /* 時間経過待ち */
00080 #define TS_WAIT_SLP     (0x01U << 3)    /* 起床待ち */
00081 #define TS_WAIT_RDTQ    (0x02U << 3)    /* データキューからの受信待ち */
00082 #define TS_WAIT_RPDQ    (0x03U << 3)    /* 優先度データキューからの受信待ち */
00083 #define TS_WAIT_SEM     (0x04U << 3)    /* セマフォ資源の獲得待ち */
00084 #define TS_WAIT_FLG     (0x05U << 3)    /* イベントフラグ待ち */
00085 #define TS_WAIT_SDTQ    (0x06U << 3)    /* データキューへの送信待ち */
00086 #define TS_WAIT_SPDQ    (0x07U << 3)    /* 優先度データキューへの送信待ち */
00087 #define TS_WAIT_MBX     (0x08U << 3)    /* メールボックスからの受信待ち */
00088 #define TS_WAIT_MPF     (0x09U << 3)    /* 固定長メモリブロックの獲得待ち */
00089 
00090 /*
00091  *  タスク状態判別マクロ
00092  *
00093  *  TSTAT_DORMANTはタスクが休止状態であるかどうかを,TSTAT_RUNNABLEは
00094  *  タスクが実行できる状態であるかどうかを判別する.TSTAT_WAITINGは待
00095  *  ち状態と二重待ち状態のいずれかであるかどうかを,TSTAT_SUSPENDEDは
00096  *  強制待ち状態と二重待ち状態のいずれかであるかどうかを判別する.
00097  */
00098 #define TSTAT_DORMANT(tstat)    ((tstat) == TS_DORMANT)
00099 #define TSTAT_RUNNABLE(tstat)   (((tstat) & TS_RUNNABLE) != 0U)
00100 #define TSTAT_WAITING(tstat)    (((tstat) & TS_WAITING) != 0U)
00101 #define TSTAT_SUSPENDED(tstat)  (((tstat) & TS_SUSPENDED) != 0U)
00102 
00103 /*
00104  *  タスク待ち要因判別マクロ
00105  *
00106  *  TSTAT_WAIT_SLPはタスクが起床待ちであるかどうかを,TSTAT_WAIT_WOBJ
00107  *  はタスクが同期・通信オブジェクトに対する待ちであるか(言い換えると,
00108  *  同期通信オブジェクトの待ちキューにつながれているか)どうかを判別す
00109  *  る.また,TSTAT_WAIT_WOBJCBはタスクが同期・通信オブジェクトの管理
00110  *  ブロックの共通部分(WOBJCB)の待ちキューにつながれているかどうかを
00111  *  判別する.
00112  *
00113  *  TSTAT_WAIT_SLPは,任意のタスク状態の中から,タスクが起床待ちである
00114  *  ことを判別できる.すなわち,TSTAT_WAITINGにより待ち状態であることを
00115  *  判別せずに,TSTAT_SLPだけを用いて起床待ち状態であることを判別できる.
00116  *  これを効率的に実現するために,TS_WAIT_SLPの値を,(0x00U << 3)ではな
00117  *  く(0x01U << 3)としている.そのため,タスクが時間経過待ち状態である
00118  *  ことを判別するためのTSTAT_WAIT_DLYを,TSTAT_WAIT_SLPと同様の方法で
00119  *  実現することはできない.
00120  */
00121 #define TS_WAIT_MASK    (0x0fU << 3)    /* 待ち要因の取出しマスク */
00122 
00123 #define TSTAT_WAIT_SLP(tstat)       (((tstat) & TS_WAIT_MASK) == TS_WAIT_SLP)
00124 #define TSTAT_WAIT_WOBJ(tstat)      (((tstat) & TS_WAIT_MASK) >= TS_WAIT_RDTQ)
00125 #define TSTAT_WAIT_WOBJCB(tstat)    (((tstat) & TS_WAIT_MASK) >= TS_WAIT_SEM)
00126 
00127 /*
00128  *  待ち情報ブロック(WINFO)の定義
00129  *
00130  *  タスクが待ち状態の間は,TCBおよびそのp_winfoで指されるWINFOを次の
00131  *  ように設定しなければならない.
00132  *
00133  *  (a) TCBのタスク状態を待ち状態(TS_WAITING)にする.その際に,待ち
00134  *  要因(TS_WAIT_???)も設定する.
00135  *
00136  *  (b) タイムアウトを監視するために,タイムイベントブロックを登録する.
00137  *  登録するタイムイベントブロックは,待ちに入るサービスコール処理関数
00138  *  のローカル変数として確保し,それへのポインタをWINFOのp_tmevtbに記
00139  *  憶する.タイムアウトの監視が必要ない場合(永久待ちの場合)には,
00140  *  p_tmevtbをNULLにする.
00141  *
00142  *  同期・通信オブジェクトに対する待ち状態の場合には,標準のWINFOに
00143  *  p_wobjcbフィールドを追加した構造体(WINFO_WOBJ,wait.hで定義)を使
00144  *  う.また,以下の(c)〜(e)の設定を行う必要がある.同期・通信オブジェ
00145  *  クトに関係しない待ち(起床待ち,時間経過待ち)の場合には,(c)〜(e)
00146  *  は必要ない.
00147  *
00148  *  (c) TCBを待ち対象の同期・通信オブジェクトの待ちキューにつなぐ.待
00149  *  ちキューにつなぐために,task_queueを使う.
00150  *
00151  *  (d) 待ち対象の同期・通信オブジェクトの管理ブロックへのポインタを,
00152  *  WINFO_WOBJのp_wobjcbに記憶する.
00153  *
00154  *  (e) 待ち対象の同期・通信オブジェクトに依存して記憶することが必要な
00155  *  情報がある場合には,WINFO_WOBJに必要な情報のためのフィールドを追加
00156  *  した構造体を定義し,WINFO_WOBJの代わりに用いる.
00157  *
00158  *  待ち状態を解除する際には,待ち解除したタスクに対する返値をWINFOの
00159  *  wercdに設定する.wercdが必要なのは待ち解除以降であるのに対して,
00160  *  p_tmevtbは待ち解除後は必要ないため,メモリ節約のために共用体を使っ
00161  *  ている.そのため,wercdへエラーコードを設定するのは,タイムイベント
00162  *  ブロックを登録解除した後にしなければならない.
00163  */
00164 typedef union waiting_information {
00165     ER      wercd;          /* 待ち解除時のエラーコード */
00166     TMEVTB  *p_tmevtb;      /* 待ち状態用のタイムイベントブロック */
00167 } WINFO;
00168 
00169 /*
00170  *  タスク初期化ブロック
00171  *
00172  *  タスクに関する情報を,値が変わらないためにROMに置ける部分(タスク
00173  *  初期化ブロック)と,値が変化するためにRAMに置かなければならない部
00174  *  分(タスク管理ブロック,TCB)に分離し,TCB内に対応するタスク初期化
00175  *  ブロックを指すポインタを入れる.タスク初期化ブロック内に対応する
00176  *  TCBを指すポインタを入れる方法の方が,RAMの節約の観点からは望ましい
00177  *  が,実行効率が悪くなるために採用していない.他のオブジェクトについ
00178  *  ても同様に扱う.
00179  *
00180  *  タスク初期化ブロックには,DEF_TEXで定義されるタスク例外処理ルーチ
00181  *  ンに関する情報も含む.
00182  */
00183 typedef struct task_initialization_block {
00184     ATR         tskatr;         /* タスク属性 */
00185     intptr_t    exinf;          /* タスクの拡張情報 */
00186     TASK        task;           /* タスクの起動番地 */
00187     uint_t      ipriority;      /* タスクの起動時優先度(内部表現) */
00188     SIZE        stksz;          /* スタック領域のサイズ(丸めた値) */
00189     void        *stk;           /* スタック領域の先頭番地 */
00190 
00191     ATR         texatr;         /* タスク例外処理ルーチン属性 */
00192     TEXRTN      texrtn;         /* タスク例外処理ルーチンの起動番地 */
00193 } TINIB;
00194 
00195 /*
00196  *  TCB中のフィールドのビット幅の定義
00197  *
00198  *  プロセッサによっては,TCB中のフィールドのビット幅でメモリ使用量と
00199  *  性能がトレードオフになるため,ターゲット依存にフィールドのビット幅
00200  *  を変更することを許している.
00201  */
00202 #ifndef TBIT_TCB_PRIORITY
00203 #define TBIT_TCB_PRIORITY       8       /* priorityフィールドのビット幅 */
00204 #endif /* TBIT_TCB_PRIORITY */
00205 
00206 /*
00207  *  タスク管理ブロック(TCB)
00208  *
00209  *  ASPカーネルでは,タスクの起動要求キューイング数の最大値(TMAX_ACTCNT)
00210  *  と起動要求キューイング数の最大値(TMAX_WUPCNT)は1に固定されている
00211  *  ため,キューイングされているかどうかの真偽値で表現することができる.
00212  *  また,強制待ち要求ネスト数の最大値(TMAX_SUSCNT)が1に固定されてい
00213  *  るので,強制待ち要求ネスト数(suscnt)は必要ない.
00214  *
00215  *  TCBのいくつかのフィールドは,特定のタスク状態でのみ有効な値を保持し,
00216  *  それ以外の場合は値が保証されない(よって,参照してはならない).各
00217  *  フィールドが有効な値を保持する条件は次の通り.
00218  *
00219  *  ・初期化後は常に有効:
00220  *          p_tinib,tstat,actque
00221  *  ・休止状態以外で有効(休止状態では初期値になっている):
00222  *          priority,wupque,enatex,texptn
00223  *  ・待ち状態(二重待ち状態を含む)で有効:
00224  *          p_winfo
00225  *  ・実行できる状態と同期・通信オブジェクトに対する待ち状態で有効:
00226  *          task_queue
00227  *  ・実行可能状態,待ち状態,強制待ち状態,二重待ち状態で有効:
00228  *          tskctxb
00229  */
00230 typedef struct task_control_block {
00231     QUEUE           task_queue;     /* タスクキュー */
00232     const TINIB     *p_tinib;       /* 初期化ブロックへのポインタ */
00233 
00234 #ifdef UINT8_MAX
00235     uint8_t         tstat;          /* タスク状態(内部表現)*/
00236 #else /* UINT8_MAX */
00237     BIT_FIELD_UINT  tstat : 8;      /* タスク状態(内部表現)*/
00238 #endif /* UINT8_MAX */
00239     BIT_FIELD_UINT  priority : TBIT_TCB_PRIORITY;
00240                                     /* 現在の優先度(内部表現)*/
00241     BIT_FIELD_BOOL  actque : 1;     /* 起動要求キューイング */
00242     BIT_FIELD_BOOL  wupque : 1;     /* 起床要求キューイング */
00243     BIT_FIELD_BOOL  enatex : 1;     /* タスク例外処理許可状態 */
00244 
00245     TEXPTN          texptn;         /* 保留例外要因 */
00246     WINFO           *p_winfo;       /* 待ち情報ブロックへのポインタ */
00247     CTXB            tskctxb;        /* タスクコンテキストブロック */
00248 } TCB;
00249 
00250 /*
00251  *  実行状態のタスク
00252  *
00253  *  実行状態のタスク(=プロセッサがコンテキストを持っているタスク)の
00254  *  TCBを指すポインタ.実行状態のタスクがない場合はNULLにする.
00255  *
00256  *  サービスコールの処理中で,自タスク(サービスコールを呼び出したタス
00257  *  ク)に関する情報を参照する場合はp_runtskを使う.p_runtskを書き換え
00258  *  るのは,ディスパッチャ(と初期化処理)のみである.
00259  */
00260 extern TCB  *p_runtsk;
00261 
00262 /*
00263  *  最高優先順位のタスク
00264  *
00265  *  実行できるタスクの中で最高優先順位のタスクのTCBを指すポインタ.実
00266  *  行できるタスクがない場合はNULLにする.
00267  *
00268  *  ディスパッチ禁止状態など,ディスパッチが保留されている間はp_runtsk
00269  *  と一致しているとは限らない.
00270  */
00271 extern TCB  *p_schedtsk;
00272 
00273 /*
00274  *  ディスパッチ/タスク例外処理ルーチン起動要求フラグ
00275  *
00276  *  割込みハンドラ/CPU例外ハンドラの出口処理に,ディスパッチまたは
00277  *  タスク例外処理ルーチンの起動を要求することを示すフラグ.
00278  */
00279 extern bool_t   reqflg;
00280 
00281 /*
00282  *  ディスパッチ禁止状態
00283  *
00284  *  ディスパッチ禁止状態であることを示すフラグ.
00285  */
00286 extern bool_t   disdsp;
00287 
00288 /*
00289  *  タスクディスパッチ可能状態
00290  *
00291  *  ディスパッチ禁止状態でなく,割込み優先度マスク(IPM)がTIPM_ENAALL
00292  *  であることを示すフラグ.
00293  */
00294 extern bool_t   dspflg;
00295 
00296 /*
00297  *  レディキュー
00298  *
00299  *  レディキューは,実行できる状態のタスクを管理するためのキューである.
00300  *  実行状態のタスクも管理しているため,レディ(実行可能)キューという
00301  *  名称は正確ではないが,レディキューという名称が定着しているため,こ
00302  *  の名称で呼ぶことにする.
00303  *
00304  *  レディキューは,優先度ごとのタスクキューで構成されている.タスクの
00305  *  TCBは,該当する優先度のキューに登録される.
00306  */
00307 extern QUEUE    ready_queue[TNUM_TPRI];
00308 
00309 /*
00310  *  レディキューサーチのためのビットマップ
00311  *
00312  *  レディキューのサーチを効率よく行うために,優先度ごとのタスクキュー
00313  *  にタスクが入っているかどうかを示すビットマップを用意している.ビッ
00314  *  トマップを使うことで,メモリアクセスの回数を減らすことができるが,
00315  *  ビット操作命令が充実していないプロセッサで,優先度の段階数が少ない
00316  *  場合には,ビットマップ操作のオーバーヘッドのために,逆に効率が落ち
00317  *  る可能性もある.
00318  */
00319 extern uint16_t ready_primap;
00320 
00321 /*
00322  *  タスクIDの最大値(kernel_cfg.c)
00323  */
00324 extern const ID tmax_tskid;
00325 
00326 /*
00327  *  タスク初期化ブロックのエリア(kernel_cfg.c)
00328  */
00329 extern const TINIB  tinib_table[];
00330 
00331 /*
00332  *  タスク生成順序テーブル(kernel_cfg.c)
00333  */
00334 extern const ID torder_table[];
00335 
00336 /*
00337  *  TCBのエリア(kernel_cfg.c)
00338  */
00339 extern TCB  tcb_table[];
00340 
00341 /*
00342  *  タスクの数
00343  */
00344 #define tnum_tsk    ((uint_t)(tmax_tskid - TMIN_TSKID + 1))
00345 
00346 /*
00347  *  タスクIDからTCBを取り出すためのマクロ
00348  */
00349 #define INDEX_TSK(tskid)    ((uint_t)((tskid) - TMIN_TSKID))
00350 #define get_tcb(tskid)      (&(tcb_table[INDEX_TSK(tskid)]))
00351 #define get_tcb_self(tskid) ((tskid) == TSK_SELF ? p_runtsk : get_tcb(tskid))
00352 
00353 /*
00354  *  TCBからタスクIDを取り出すためのマクロ
00355  */
00356 #define TSKID(p_tcb)    ((ID)(((p_tcb) - tcb_table) + TMIN_TSKID))
00357 
00358 /*
00359  *  タスク管理モジュールの初期化
00360  */
00361 extern void initialize_task(void);
00362 
00363 /*
00364  *  最高優先順位タスクのサーチ
00365  *
00366  *  レディキュー中の最高優先順位のタスクをサーチし,そのTCBへのポインタ
00367  *  を返す.レディキューが空の場合には,この関数を呼び出してはならない.
00368  */
00369 extern TCB  *search_schedtsk(void);
00370 
00371 /*
00372  *  実行できる状態への移行
00373  *
00374  *  p_tcbで指定されるタスクの状態を実行できる状態とし,レディキューに
00375  *  挿入する.実行できる状態になったタスクの優先度が,最高優先順位のタ
00376  *  スクの優先度よりも高い場合は,最高優先順位のタスクを更新し,ディス
00377  *  パッチ許可状態であればtrueを返す.そうでない場合はfalseを返す.
00378  */
00379 extern bool_t   make_runnable(TCB *p_tcb);
00380 
00381 /*
00382  *  実行できる状態から他の状態への移行
00383  *
00384  *  p_tcbで指定されるタスクをレディキューから削除する.p_tcbで指定した
00385  *  タスクが最高優先順位のタスクであった場合には,最高優先順位のタスク
00386  *  を設定しなおし,ディスパッチ許可状態であればtrueを返す.そうでない
00387  *  場合はfalseを返す.タスクの状態は更新しない.
00388  */
00389 extern bool_t   make_non_runnable(TCB *p_tcb);
00390 
00391 /*
00392  *  休止状態への移行
00393  *
00394  *  p_tcbで指定されるタスクの状態を休止状態とする.また,タスクの起動
00395  *  時に初期化すべき変数の初期化と,タスク起動のためのコンテキストを設
00396  *  定する.
00397  */
00398 extern void make_dormant(TCB *p_tcb);
00399 
00400 /*
00401  *  休止状態から実行できる状態への移行
00402  *
00403  *  p_tcbで指定されるタスクの状態を休止状態から実行できる状態とする.
00404  *  実行できる状態に移行したタスクへのディスパッチが必要な場合はtrue,
00405  *  そうでない場合はfalseを返す.
00406  */
00407 extern bool_t   make_active(TCB *p_tcb);
00408 
00409 /*
00410  *  タスクの優先度の変更
00411  *
00412  *  p_tcbで指定されるタスクの優先度をnewpri(内部表現)に変更する.また,
00413  *  必要な場合には最高優先順位のタスクを更新し,ディスパッチ許可状態で
00414  *  あればtrueを返す.そうでない場合はfalseを返す.
00415  */
00416 extern bool_t   change_priority(TCB *p_tcb, uint_t newpri);
00417 
00418 /*
00419  *  レディキューの回転
00420  *
00421  *  レディキュー中の,priで指定される優先度のタスクキューを回転させる.
00422  *  また,必要な場合には最高優先順位のタスクを変更し,ディスパッチが保
00423  *  留されていなければtrueを返す.そうでない場合はfalseを返す.
00424  */
00425 extern bool_t   rotate_ready_queue(uint_t pri);
00426 
00427 /*
00428  *  タスク例外処理ルーチンの呼出し
00429  *
00430  *  タスク例外処理ルーチンを呼び出す.呼び出す前に,実行状態のタスクの
00431  *  保留例外要因をクリアし,タスク例外処理禁止状態にし,CPUロックを解
00432  *  除する.
00433  *
00434  *  タスク例外処理ルーチンから戻ると,まずCPUロック状態に戻し,その間
00435  *  に保留例外要因が0でなくなっていれば,再びタスク例外処理ルーチンを
00436  *  呼び出す.保留例外要因が0の場合には,例外処理許可状態にして関数か
00437  *  らリターンする.
00438  *
00439  *  この関数は,実行状態のタスクが,タスク例外処理許可状態(enatexが
00440  *  true)で,保留例外要因が0でない(texptnが0でない)場合に呼び出すこ
00441  *  とを想定している.この関数は,CPUロック状態で呼び出さなければなら
00442  *  ない.
00443  *
00444  *  実行効率を上げるために,この関数をターゲット依存部で記述してもよい.
00445  *  その場合には,OMIT_CALL_TEXRTNをマクロ定義する.
00446  */
00447 extern void call_texrtn(void);
00448 
00449 /*
00450  *  タスク例外処理ルーチンの起動
00451  *
00452  *  実行状態のタスクがタスク例外処理ルーチンの起動条件を満たしていれば,
00453  *  タスク例外処理ルーチンを呼び出す.CPU例外処理ルーチンを呼び出す時
00454  *  は,一時的にCPUロックを解除する.
00455  *
00456  *  この関数は,ディスパッチャや割込みハンドラ/CPU例外ハンドラの出口
00457  *  処理から呼び出されることを想定している.この関数は,CPUロック状態
00458  *  で呼び出さなければならない.
00459  *
00460  *  実行効率を上げるために,この関数をターゲット依存部で記述してもよい.
00461  *  その場合には,OMIT_CALLTEXをマクロ定義する.
00462  */
00463 extern void calltex(void);
00464 
00465 #endif /* TOPPERS_TASK_H */

Copyright © 2008 by Kijineko Inc.

ホームページ制作