地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

カーネルスレッドの仕事

Linuxカーネルスレッド

Linuxでのカーネルスレッドのお仕事は以下のような感じ

  • keventd(ワークキュ)
  • kswapd(メモリー回収)
  • ksoftoirqd(ソフト割り込み

カーネルスレッドという名前はついているがLinuxからみたカーネルスレッドの一つ一つはスケージューリングにおいてユーザプロセスと同じ物。

ユーザプロセス作成と同じようにCLONE_VMなどから生成される。

static inline void
context_switch(struct rq *rq, struct task_struct *prev,
              struct task_struct *next)
{
       struct mm_struct *mm, *oldmm;

   :
   :
       mm = next->mm;
       oldmm = prev->active_mm;
   :
   :
       if (unlikely(!mm)) {
               next->active_mm = oldmm;
               atomic_inc(&oldmm->mm_count);
       } else
               switch_mm(oldmm, mm, next);

       if (unlikely(!prev->mm)) {
               prev->active_mm = NULL;
               rq->prev_mm = oldmm;
       }
       switch_to(prev, next, prev);
    :
       finish_task_switch(this_rq(), prev);
}

カーネルスレッドの生成はkernel_thread()を呼び出して行われる。

関数の定義はkernel/process.cあたりにある

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
    struct pt_regs regs;

    memset(&regs, 0, sizeof(regs));

    regs.ebx = (unsigned long) fn;
    regs.edx = (unsigned long) arg;

    regs.xds = __USER_DS;
    regs.xes = __USER_DS;
    regs.orig_eax = -1;
    regs.eip = (unsigned long) kernel_thread_helper;
    regs.xcs = __KERNEL_CS;
    regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;

    /* Ok, create the new process.. */
    return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}

この辺を追っていくことで見覚えのあるdo_forkが出てくる。

フラグによってカーネルスレッドであろうがユーザスレッドであろうがLinuxからは同一のものとしてスケジューリングされるのであろう。

全貌を追いたい方は是非

github.com

ちなみにカーネルスレッドをユーザランド側から殺そうとしても死なない。カーネルスレッドをカーネル側からのアクションが必要。