thread_run関数のソースコード【12ステップで作る組込みOS自作入門 8thステップ】
という謎現象が発生したので本記事にてソースコードを公開します。
※intをINT型に置きなおしているなど書籍を丸々コピーしているわけではないことにご注意ください。
目次
型の宣言
thread_run関数でわからないところがあれば参照してください。
typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned long UINT32; typedef signed char INT8; typedef signed short INT16; typedef signed long INT32; typedef int INT; typedef UINT32 kz_thread_id_t; typedef INT (*kz_func_t)(INT argc, INT8 *argv[]); /* システムコール番号の定義 */ typedef enum { KZ_SYSCALL_TYPE_RUN = 0, KZ_SYSCALL_TYPE_EXIT, } kz_syscall_type_t; /* システムコール呼び出し時のパラメータ格納域の定義 */ typedef struct { union { struct { kz_func_t func; INT8 *name; INT stacksize; INT argc; INT8 **argv; kz_thread_id_t ret; } run; struct { INT dummy; } exit; } un; } kz_syscall_param_t; #define THREAD_NUM (6) #define THREAD_NAME_SIZE (15) /* スレッドコンテキスト */ typedef struct { UINT32 sp; } kz_context_t; /* タスクコントロールブロック (TCB) */ typedef struct _kz_thread { struct _kz_thread *next; INT8 name[THREAD_NAME_SIZE + 1]; INT8 *stack; /* スレッドのスタートアップ (thread_init) に渡すパラメータ */ struct { kz_func_t func; INT argc; INT8 **argv; } init; /* システムコール用バッファ */ struct { kz_syscall_type_t type; kz_syscall_param_t *param; } syscall; kz_context_t context; } kz_thread_t; static kz_thread_t *current; /* カレントスレッド */ static kz_thread_t threads[THREAD_NUM]; /* タスクコントロールブロック */ static kz_handler_t handlers[SOFTVEC_TYPE_NUM]; /* 割込みハンドラ */ void dispatch(kz_context_t *context);
thread_run関数
/* システムコールの処理 (kz_run(): スレッドの起動) */ static kz_thread_id_t thread_run(kz_func_t func, INT8 *name, INT stacksize, INT argc, INT8 *argv[]) { INT i; kz_thread_t *thp; UINT32 *sp; extern INT8 userstack; /* リンカスクリプトで定義されるスタック領域 */ static INT8 *thread_stack = &userstack; /* 空いているタスクコントロールブロックを検索 */ for (i = 0; i < THREAD_NUM; i++) { thp = &threads[i]; /* 見つかった */ if (!thp->init.func) { break; } } /* 見つからなかった */ if (i == THREAD_NUM) { return -1; } memset(thp, 0, sizeof(*thp)); /* タスクコントロールブロックの設定 */ strcpy(thp->name, name); thp->next = NULL; thp->init.func = func; thp->init.argc = argc; thp->init.argv = argv; /* スタック領域の確保 */ memset(thread_stack, 0, stacksize); thread_stack += stacksize; thp->stack = thread_stack; /* スタックの初期化 */ sp = (UINT32 *)thp->stack; *(--sp) = (UINT32)thread_end; /* プログラムカウンタの設定 */ *(--sp) = (UINT32)thread_init; *(--sp) = 0; /* ER6 */ *(--sp) = 0; /* ER5 */ *(--sp) = 0; /* ER4 */ *(--sp) = 0; /* ER3 */ *(--sp) = 0; /* ER2 */ *(--sp) = 0; /* ER1 */ /* スレッドのスタートアップ (thread_init()) に渡す引数 */ *(--sp) = (UINT32)thp; /* ER0 */ /* スレッドのコンテキストを設定 */ thp->context.sp = (UINT32)sp; /* システムコールを呼び出したスレッドをレディーキューに戻す */ put_current(); /* 新規作成したスレッドをレディーキューに接続する */ current = thp; put_current(); return (kz_thread_id_t)current; }