マメにマメを積む

とあるプログラマの技術日誌的なやつ

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;
}