linux kthread_work解析

Linux内核实现透视---kthread_work - Little_Village - 博客园

kthreadd-linux下2号进程 - yuxi_o - 博客园

kthread_create_worker函数创建worker:

struct kthread_worker *
kthread_create_worker(unsigned int flags, const char namefmt[], ...)
{
	struct kthread_worker *worker;
	va_list args;

	va_start(args, namefmt);
	worker = __kthread_create_worker(-1, flags, namefmt, args);
	va_end(args);

	return worker;
}

__kthread_create_worker函数创建线程并绑定worker,即一个worker对应一个线程: 

static struct kthread_worker *
__kthread_create_worker(int cpu, unsigned int flags,
			const char namefmt[], va_list args)
{
	struct kthread_worker *worker;
	struct task_struct *task;
	int node = -1;

	worker = kzalloc(sizeof(*worker), GFP_KERNEL);

	kthread_init_worker(worker);

	if (cpu >= 0)
		node = cpu_to_node(cpu);
    
    //创建线程
	task = __kthread_create_on_node(kthread_worker_fn, worker,
						node, namefmt, args);

	if (cpu >= 0)
		kthread_bind(task, cpu);

	worker->flags = flags;

    //一个worker对应一个线程
	worker->task = task;
	wake_up_process(task);
	return worker;

}

 线程对应的处理函数,从该处理函数中可以看出:该线程在不断调用worker链表里的work->func(work),直到worker链表为空。

int kthread_worker_fn(void *worker_ptr)
{
	struct kthread_worker *worker = worker_ptr;
	struct kthread_work *work;

	worker->task = current;

	if (worker->flags & KTW_FREEZABLE)
		set_freezable();

repeat:
	set_current_state(TASK_INTERRUPTIBLE);	/* mb paired w/ kthread_stop */

	if (kthread_should_stop()) {
		__set_current_state(TASK_RUNNING);
		worker->task = NULL;
		return 0;
	}

	work = NULL;

	if (!list_empty(&worker->work_list)) {

        //worker链表中取出work,并将它从worker链表中删除
		work = list_first_entry(&worker->work_list,struct kthread_work, node);
		list_del_init(&work->node);
	}

	worker->current_work = work;

	if (work) {
		__set_current_state(TASK_RUNNING);
        //work->func(work)都是在一个线程内被执行
		work->func(work);
	} else if (!freezing(current))
		schedule();

	try_to_freeze();
	cond_resched();
    
    //进入循环遍历
	goto repeat;
}

__kthread_create_on_node创建内核线程 ,创建内核线程又与kthreadd线程相关。

static 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);

    //所创线程的threadfn线程处理函数是在kthreadd线程里的一个kthread线程内被调用。
	create->threadfn = threadfn;
	create->data = data;
	create->node = node;
	create->done = &done;

    //该线程链表被kthreadd线程维护的
	list_add_tail(&create->list, &kthread_create_list);

    //唤醒kthreadd线程
	wake_up_process(kthreadd_task);

	if (unlikely(wait_for_completion_killable(&done))) {
	
		if (xchg(&create->done, NULL))
			return ERR_PTR(-EINTR);

		wait_for_completion(&done);
	}

	task = create->result;

	kfree(create);

	return task;
}

kthreadd:管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kthread_create创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程。所有的内核线程的PPID都是2。

在linux启动的C阶段start_kernel()的最后,rest_init()会开启两个进程:kernel_init,kthreadd,之后主线程变成idle线程。

static noinline void __ref rest_init(void)
{
        struct task_struct *tsk;
        int pid;

        pid = kernel_thread(kernel_init, NULL, CLONE_FS);
        ......       
        pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
        kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
        ......
}

相关数据结构定义:

static DEFINE_SPINLOCK(kthread_create_lock);
static LIST_HEAD(kthread_create_list);
struct task_struct *kthreadd_task;

struct kthread_create_info
{
     /* Information passed to kthread() from kthreadd. */
    int (*threadfn)(void *data);
    void *data;
    int node;

    /* Result passed back to kthread_create() from kthreadd. */
    struct task_struct *result;
    struct completion done;

    struct list_head list;
};

struct kthread {
    int should_stop;
    void *data;
    struct completion exited;
};

kthreadd线程处理函数: 

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

    ......

    for (;;) {

        set_current_state(TASK_INTERRUPTIBLE);

        //kthread_create_list链表为空,挂起
        if (list_empty(&kthread_create_list))
            schedule();

        __set_current_state(TASK_RUNNING);

        //为kthread_create_list链表中的每个kthread_create_info成员创建对应的线程 
        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);
             //创建kthread线程,该线程就是为每个kthread_create_info变量创建的对应的线程
            create_kthread(create);

        }

    }

    return 0;
}
static void create_kthread(struct kthread_create_info *create)
{
    int pid;
    
    //create对应的线程就是ktread线程
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
    if (pid < 0) {
        create->result = ERR_PTR(pid);
        complete(&create->done);
    }   
}

kthread线程处理函数: 

static int kthread(void *_create)
{

    struct kthread_create_info *create = _create;
    int (*threadfn)(void *data) = create->threadfn;
    void *data = create->data;
    struct kthread self;
    int ret;

    self.should_stop = 0;
    self.data = data;
    init_completion(&self.exited);
    current->vfork_done = &self.exited;

    __set_current_state(TASK_UNINTERRUPTIBLE);

    //create对应的线程就是ktreadd线程创建的kthead线程
    create->result = current;
    complete(&create->done);
    //线程创建完成,挂起,等待唤醒
    schedule();

    ret = -EINTR;

    if (!self.should_stop)
        //执行上面传下来的新创建的线程的处理函数
        ret = threadfn(data); 

    /* we can't just return, we must preserve "self" on stack */
    do_exit(ret);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
kthread_park和kthread_init_worker都是Linux内核提供的用于创建内核线程的函数,但它们的功能和用法不同。 kthread_park是一个较新的函数,它可以创建一个内核线程,并使其处于休眠状态,直到有任务需要执行时再被唤醒。kthread_park的函数原型如下: ``` struct task_struct *kthread_park(struct kthread_park_info *park); ``` 其中,kthread_park_info结构体定义了休眠等待的条件和超时时间等信息。kthread_park会返回一个指向task_struct结构体的指针,该结构体描述了内核线程的各种属性。 kthread_park适用于需要等待事件发生的场景,比如等待硬件中断、等待网络数据等。使用kthread_park创建的线程会自动进入休眠状态,不会占用CPU资源,等待唤醒后才会再次执行。 kthread_init_worker是一个较早的函数,它创建的内核线程主要用于执行一些后台任务,比如文件系统的后台清理、网络数据包的处理等。kthread_init_worker的函数原型如下: ``` struct task_struct *kthread_init_worker(int (*func)(void *data), void *data, const char *namefmt, ...); ``` 其中,func是内核线程的入口函数,data是传递给线程的参数,namefmt是线程的名称。kthread_init_worker会返回一个指向task_struct结构体的指针,该结构体描述了内核线程的各种属性。 kthread_init_worker创建的线程会立即执行,不会进入休眠状态。它通常用于执行一些需要在后台运行的任务,可以通过多线程编程技术来实现并发执行。 需要注意的是,kthread_park和kthread_init_worker都需要在内核中使用,不能直接在用户空间中调用。使用这两个函数创建内核线程时,需要注意线程同步和互斥的问题,比如使用信号量、互斥锁等机制来保护共享资源,避免竞态条件等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值