kthread_runマクロ
Rev.2を表示中。最新版はこちら。
kthread_runマクロはカーネルスレッドを作成し、起動(アクティブキューに接続)に繋ぐ。カーネルスレッドはユーザプロセスのマルチスレッドと同じような感じ。異なるのは、ユーザプロセスの親もプロセスとして動作するが、カーネルスレッドの親は、カーネル本体で、このカーネルはプロセスとして動作しているわけでない。lkmで/procのコールバック処理を実装した場合、この関数はカーネル上の1パスの関数にしか過ぎない。従ってその処理が終了しても(return)、実態はカーネル内に存在し続ける。しかしカーネルスレッドだと、カーネルパスの延長上で動作するのでなく、カーネルからスケジュールされるプロセスとして動作することになる。従って、その処理が終了したらプロセスとして存在しなくなる。(ただしメモリ上に存在する)
従って、lkmから作成したカーネルスレッド、lkmをrmmmodする時に、その前にそのカーネルスレッドを削除する必要がある。この処理を忘れると、実在しないカーネルスレッドに起動がかかるって事になる。(たぶん)
カーネルスレッド内の処理は、サービスの間retできない。上記のごとくretするとプロセスが削除されてしまう。カーネルの実装的には、カーネルスレッドとなる関数の復帰後に、do_exit関数がコールされるようになっている。
以下はlkm下のカーネルスレッドでjiffiesを表示させるサンプル。
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
MODULE_AUTHOR("y.kitamura");
MODULE_DESCRIPTION("kthread test");
MODULE_LICENSE("GPL");
static struct task_struct *kthread_tsk;
static void my_kthread_main(void)
{
       set_current_state(TASK_INTERRUPTIBLE);
       schedule_timeout(HZ);
       printk("kthread:%ld\n", jiffies);
}
static int my_kthread(void *arg)
{
       printk("HZ:%d\n", HZ);
       while (!kthread_should_stop()) {
               my_kthread_main();
       }
       return 0;
}
static int __init kthread_test_init(void)
{
       kthread_tsk = kthread_run(my_kthread, NULL, "param %s&%d", "test", 123);
       if (IS_ERR(kthread_tsk))
               return -1;
       printk("pid->%d:prio->%d:comm->%s\n",
               kthread_tsk->pid,
               kthread_tsk->static_prio,
               kthread_tsk->comm);
       return 0;
}
static void __exit kthread_test_exit(void)
{
       kthread_stop(kthread_tsk);
}
module_init(kthread_test_init);
module_exit(kthread_test_exit);
実行結果[root@localhost lkm]# dmesg [ 3991.325662] pid->7712:prio->120:comm->param test&123 [ 3991.326134] HZ:1000 [ 3992.326479] kthread:3692326 [ 3993.326179] kthread:3693326 [ 3994.326339] kthread:3694326 [ 3995.328651] kthread:3695328rmmod時に、kthread_should_stopがコールされる様にする必要がある。kthread_should_stopはkthread->should_stop = 1として、カーネルスレッドを起床させ、wait_for_completionでスレッドが削除されるまでウエイトする。そして後、モジュールを削除する事が可能になる。
int kthread_should_stop(void)
{
       return to_kthread(current)->should_stop;
}
int kthread_stop(struct task_struct *k)
{
       struct kthread *kthread;
       int ret;
       trace_sched_kthread_stop(k);
       get_task_struct(k);
       kthread = to_kthread(k);
       barrier(); /* it might have exited */
       if (k->vfork_done != NULL) {
               kthread->should_stop = 1;
               wake_up_process(k);
               wait_for_completion(&kthread->exited);
       }
       ret = k->exit_code;
       put_task_struct(k);
       trace_sched_kthread_stop_ret(ret);
       return ret;
}
実装は後日に・・・






