linux 内核线程拥有独立堆栈和优先级运行机制,内核线程跟用户空间进程一样用结构体struct task_struct来描述,所以从运行机制看,实际上就是一个进程,并且共享父进程资源,但是没有自己独立的进程空间,而且还不能跟用户空间交互,即current->mm 为空。
使用该接口创建的线程,必须在该线程中调用daemonize()函数,这是因为只有当线程的父进程指向"Kthreadd"时,该线程才算是内核线程, 而恰好daemonize()函数主要工作便是将该线程的父进程改成“kthreadd"内核线程;默认情况下,调用deamonize()后,会阻塞所有信号,如果想操作某个信号可以调用allow_signal()函数。
而kthread_create接口,则是标准的内核线程创建接口,只须调用该接口便可创建内核线程;默认创建的线程是存于不可运行的状态,所以需要在父进程中通过调用wake_up_process()函数来启动该线程。
创建内核线程
o 利用kernel_thread() 创建使用该接口创建的线程,必须在该线程中调用daemonize()函数,这是因为只有当线程的父进程指向"Kthreadd"时,该线程才算是内核线程, 而恰好daemonize()函数主要工作便是将该线程的父进程改成“kthreadd"内核线程;默认情况下,调用deamonize()后,会阻塞所有信号,如果想操作某个信号可以调用allow_signal()函数。
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
void daemonize(const char * name,...);
o 利用kthread_create() 创建
而kthread_create接口,则是标准的内核线程创建接口,只须调用该接口便可创建内核线程;默认创建的线程是存于不可运行的状态,所以需要在父进程中通过调用wake_up_process()函数来启动该线程。
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,
const char namefmt[], ...);
int wake_up_process(struct task_struct *p); // 唤醒线程开始运行
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,
const char namefmt[], ...); // 封装上述两个函数
以watchdog喂狗内核线程为例
static int __init start_watchdog_daemon(void)
{
int ret = 0;
struct task_struct *watchdog_task;
/* Register watchdog feed man */
pr_info("%s: Start watchdog feed thread\n", __func__);
watchdog_task = kthread_run(watchdog_thread, NULL, "s3c_wdt/daemon"); // 利用kthread_run创建内核 线程并且开始运行
if (IS_ERR(watchdog_task)) {
pr_err("%s: Failed to create watchdog_thread\n", __func__);
ret = -EFAULT;
}
return ret;
}
static int watchdog_thread(void *data) // threadfn
{
unsigned int keepalive_cycle = tmr_margin / 2;
pr_info("%s: Enter into watchdog_thread\n", __func__);
while (1) {
msleep_interruptible(keepalive_cycle * 1000); // 让出cpu, 延时keppalive_cycle * 1000 时间
pr_debug("%s: feed the watchdog\n", __func__);
s3c2410wdt_keepalive(&s3c2410_wdd); // 喂狗
}
return 0;
}
内核机制分析
kthread_run(threadfn, data, namefmt, ...)
-> kthread_create(threadfn, data, namefmt, arg...)
-> kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
-> struct kthread_create_info create; // 添加线程创建结构体
create.threadfn = threadfn;
create.data = data;
create.node = node;
init_completion(&create.done);
list_add_tail(&create.list, &kthread_create_list); // 加入kthread_create_list, threadd 会
wake_up_process(kthreadd_task); // wakeup init/main.c rese_init() 里创建的kthreadd内核线程
wait_for_completion(&create.done); // 线程创建同步控制
-> wake_up_process() // 唤醒线程开始执行
init/main.c rest_init()
-> pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); // 创建内核线程kthreaddd
-> kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); // 被 wake_up_process(kthreadd_task); 唤醒执行kthreadd
kthreadd()
-> struct task_struct *tsk = current; // 继承父进程,并且设置新环境
/* Setup a clean context for our children to inherit. */
set_task_comm(tsk, "kthreadd");
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk, cpu_all_mask);
set_mems_allowed(node_states[N_HIGH_MEMORY]);
current->flags |= PF_NOFREEZE
-> set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&kthread_create_list)) // 为空,让出cpu
schedule();
__set_current_state(TASK_RUNNING); // 设置running状态
-> for (;;) // for 循环遍历 kthread_create_list, 创建线程
create_kthread(create); // 创建线程
create_kthread(create)
-> pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
-> return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); // 创建内核线程
-> complete(&create->done); // 完成kthread_run() 中的同步控制, 至此线程创建完毕
kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
-> return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); // 创建内核线程
void daemonize(const char *name, ...)
-> reparent_to_kthreadd(); // 指定父进程为kthreadd,