内核线程

linux 内核线程拥有独立堆栈和优先级运行机制,内核线程跟用户空间进程一样用结构体struct task_struct来描述,所以从运行机制看,实际上就是一个进程,并且共享父进程资源,但是没有自己独立的进程空间,而且还不能跟用户空间交互,即current->mm 为空。
创建内核线程
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,



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值