内核线程的创建kthread_run

kthread_run是一个宏,用来创建一个进程,并且将其唤醒,其定义在头文件include/linux/kthread.h中.

#define kthread_run(threadfn, data, namefmt, ...)			   \
({									   \
	struct task_struct *__k						   \
		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
	if (!IS_ERR(__k))						   \
		wake_up_process(__k);					   \
	__k;								   \
})

wake_up_process: TTWU
参考https://blog.csdn.net/feifei_csdn/article/details/107486547
int wake_up_process(struct task_struct *p)
{
    /*wake_up_process直接调用try_to_wake_up函数,并添加三个限定参数*/
	return try_to_wake_up(p, TASK_NORMAL, 0, 1);
}
EXPORT_SYMBOL(wake_up_process);
 
/* Convenience macros for the sake of wake_up */  


#define TASK_NORMAL     (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) 

/*如果进程不是在:TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE下,则就不是normal
  task,直接退出wakeup流程.所以在内核里面看到的wake_up_process,可以看到起主函数都会
   将进程设置为TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE这两种状态之一*/

kthread_create调用kthread_create_on_node创建内核线程:

#define kthread_create(threadfn, data, namefmt, arg...) \
	kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg)

kthread_create_on_node函数在kernel/kthread.c:

struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
					   void *data, int node,
					   const char namefmt[],
					   ...)
{
	struct task_struct *task;
	va_list args;

	va_start(args, namefmt);
	task = __kthread_create_on_node(threadfn, data, node, namefmt, args);
	va_end(args);

	return task;
}


struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
						    void *data, int node,
						    const char namefmt[],
						    va_list args)
{
	DECLARE_COMPLETION_ONSTACK(done);
	struct task_struct *task;
	struct kthread_create_info *create = kmalloc(sizeof(*create),
						     GFP_KERNEL);

	if (!create)
		return ERR_PTR(-ENOMEM);
	create->threadfn = threadfn;
	create->data = data;
	create->node = node;
	create->done = &done; //

	spin_lock(&kthread_create_lock);
	list_add_tail(&create->list, &kthread_create_list);
	spin_unlock(&kthread_create_lock);

	wake_up_process(kthreadd_task); //kthradd_task线程会不断从kthread_create_list链表中取出待完成的新线程结构。
	/*
	 * Wait for completion in killable state, for I might be chosen by
	 * the OOM killer while kthreadd is trying to allocate memory for
	 * new kernel thread.
	 */
	if (unlikely(wait_for_completion_killable(&done))) {
		/*
		 * If I was SIGKILLed before kthreadd (or new kernel thread)
		 * calls complete(), leave the cleanup of this structure to
		 * that thread.
		 */
		if (xchg(&create->done, NULL))
			return ERR_PTR(-EINTR);
		/*
		 * kthreadd (or new kernel thread) will call complete()
		 * shortly.
		 */
		wait_for_completion(&done); //等待新线程的创建完成,睡眠等待,直到create_kthread函数调用kernel_thread完成创建。过程是kthreadd_task唤醒->kthreadd函数执行->create_kthread->create_kthread->_do_fork .....
	}
	task = create->result;
	if (!IS_ERR(task)) {
		static const struct sched_param param = { .sched_priority = 0 };
		char name[TASK_COMM_LEN];

		/*
		 * task is already visible to other tasks, so updating
		 * COMM must be protected.
		 */
		vsnprintf(name, sizeof(name), namefmt, args);
		set_task_comm(task, name);
		/*
		 * root may have changed our (kthreadd's) priority or CPU mask.
		 * The kernel thread should not inherit these properties.
		 */
		sched_setscheduler_nocheck(task, SCHED_NORMAL, &param);
		set_cpus_allowed_ptr(task, cpu_all_mask);
	}
	kfree(create);
	return task;
}

 在__kthread_create_on_node函数中:其中唤醒kthreadd_task线程来完成新线程的创建。kthread_task是在rest_init中创建的内核线程,其中电源kthreaddd函数通过while循环来创建内核线程。

static noinline void __init_refok rest_init(void)
{
    int pid;

    rcu_scheduler_starting();
    
    kernel_thread(kernel_init, NULL, CLONE_FS);
    numa_default_policy();
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    rcu_read_lock();
    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    rcu_read_unlock();
    complete(&kthreadd_done);
    
    ......
}


int kthreadd(void *unused)
{
    struct task_struct *tsk = current;

    ......

    for (;;) {
        set_current_state(TASK_INTERRUPTIBLE);
        if (list_empty(&kthread_create_list))
            schedule(); //如果链表空闲则调度出去,通过__kthread_create_on_node来唤醒。
        __set_current_state(TASK_RUNNING);

        spin_lock(&kthread_create_lock);
        while (!list_empty(&kthread_create_list)) {
            struct kthread_create_info *create;

            create = list_entry(kthread_create_list.next, struct kthread_create_info, list);
            list_del_init(&create->list);
            spin_unlock(&kthread_create_lock);

            create_kthread(create); //创建新内核线程。

            spin_lock(&kthread_create_lock);
        }
        spin_unlock(&kthread_create_lock);
    }

    return 0;
}

真正完成创建的函数create_kthread:其中是通过kernel_thread内核提供的函数完成task_struct的创建。kernel_thread创建的内核线程会被唤醒,执行就绪。

static void create_kthread(struct kthread_create_info *create)
{
    int pid;

    ......
//新内核线程的执行函数是kthread,create作为参数,其中就有需要真正执行的func函数。
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); //kernel_thread会真正执行do_fork创建新进程,并唤醒随时可以被执行。

    if (pid < 0) {//线程如果创建失败,下面的代码是错误处理,不是重点
        /* If user was SIGKILLed, I release the structure. */
        struct completion *done = xchg(&create->done, NULL);

        if (!done) {
            kfree(create);
            return;
        }
        create->result = ERR_PTR(pid);
        complete(done); //失败也需要complete
    }
}



pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
	return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
		(unsigned long)arg, NULL, NULL, 0);
}


long _do_fork(unsigned long clone_flags,
	      unsigned long stack_start,
	      unsigned long stack_size,
	      int __user *parent_tidptr,
	      int __user *child_tidptr,
	      unsigned long tls)
{

	p = copy_process(clone_flags, stack_start, stack_size,
			 child_tidptr, NULL, trace, tls, NUMA_NO_NODE);


	pid = get_task_pid(p, PIDTYPE_PID);
	nr = pid_vnr(pid);


	wake_up_new_task(p); //唤醒并得到执行。

}

上述创建完成后就会调用wake_up_new_task唤醒使得新线程可以马上执行,并complete(done),然后再schedule出去,让 __kthread_create_on_node 可以得到执行往前走。且kthread_run中后续的wake_up_process将新创建的线程在此唤醒执行真正的函数。

其中内核线程创建:kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD)执行的是kthread函数。将create作为参数。在 kernel/kthread.c 文件中。kthread函数执行完后调用do_exit 退出。


static int kthread(void *_create)
{
	/* Copy data: it's on kthread's stack */
	struct kthread_create_info *create = _create;
	int (*threadfn)(void *data) = create->threadfn;
	void *data = create->data;
	struct completion *done;
	struct kthread *self;
	int ret;

	self = kzalloc(sizeof(*self), GFP_KERNEL);
	set_kthread_struct(self);

	/* If user was SIGKILLed, I release the structure. */
	done = xchg(&create->done, NULL);
	if (!done) {
		kfree(create);
		do_exit(-EINTR);
	}

	if (!self) {
		create->result = ERR_PTR(-ENOMEM);
		complete(done);
		do_exit(-ENOMEM);
	}

	self->data = data;
	init_completion(&self->exited);
	init_completion(&self->parked);
	current->vfork_done = &self->exited;

	/* OK, tell user we're spawned, wait for stop or wakeup */
	__set_current_state(TASK_UNINTERRUPTIBLE);
	create->result = current;
	complete(done); //complete(done)
	schedule(); //此时调度出去,由于已经完成了新内核的创建,并已经可以执行到这里,complete了done。前面的kthread_create_on_node进程在wait_for_comple等待。将得到执行。

//下面的代码将是kthrad_run在wake_up_process后得到执行的。

	ret = -EINTR;
	if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) { //执行前先判断是否被kthread_stop函数给停了。
		cgroup_kthread_ready();
		__kthread_parkme(self);
		ret = threadfn(data); //执行真正的函数
	}
	do_exit(ret); //执行完成线程将推出。。。。。
}

kthread_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);
	set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
	kthread_unpark(k);
	wake_up_process(k);
	wait_for_completion(&kthread->exited);  //等待退出 。exited的completion在kthread函数中被current->vfork_done = &self->exited; 会在kernel/fork.c的进程退出的时候调用complete_vfork_done完成。
	ret = k->exit_code;
	put_task_struct(k);

	trace_sched_kthread_stop_ret(ret);
	return ret;
}
EXPORT_SYMBOL(kthread_stop);

进程的创建和释放:

task_struct的分配:

copy_process
	dup_task_struct
		alloc_task_struct_node
			kmem_cache_alloc_node

task_struct的释放:

do_wait
	do_wait_thread/ptrace_do_wait
		wait_task_stopped	
			put_task_struct
				__put_task_struct
					free_task
						free_task_struct
							kmem_cache_free

https://blog.csdn.net/CQ062364/article/details/39646623?spm=1001.2101.3001.6650.8&utm_medium=distribute.wap_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8-39646623-blog-81703583.wap_relevant_t0_download&depth_1-utm_source=distribute.wap_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8-39646623-blog-81703583.wap_relevant_t0_download

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古井无波 2024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值