kthread_runマクロ
Rev.3を表示中。最新版はこちら。
kthread_runマクロはカーネルスレッドを作成し、起動(アクティブキューに接続)に繋ぐ。カーネルスレッドはユーザプロセスのマルチスレッドと同じような感じ。異なるのは、ユーザプロセスの親もプロセスとして動作するが、カーネルスレッドの親は、カーネル本体で、このカーネルはプロセスとして動作しているわけでない。lkmで/procのコールバック処理を実装した場合、この関数はカーネル上の1パスの関数にしか過ぎない。当然カーネルスレッドからコールされる事もありうる。従ってその処理が終了しても(return)、イメージとしての実態はカーネル内に存在し続ける。しかしカーネルスレッドだと、カーネルパスの延長上で動作するのでなく、カーネルからスケジュールされるプロセスとして動作する。従って、その処理が終了したらプロセスとして存在しなくなる。ただしrmmodしない限り、イメージとしてメモリ上に存在する。なお、再度必要に応じてkthread_runすることも可能。
従って、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;
}
実装は後日に・・・





