ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

complete完成量——实例分析

2019-06-05 22:53:36  阅读:221  来源: 互联网

标签:kthread task complete create list 实例 done 完成 struct


一、完成量的使用步骤

1. 完成量的基本使用流程

/* 1.定义一个completion结构并初始化 */
struct completion done;
init_completion(&create.done);

/* 2.一个进程进行等待 */
wait_for_completion(&kthreadd_done);

/* 2.另一个进程执行唤醒 */
complete(&done);

 

2. 完成量是基于等待队列实现的,因此可能会阻塞,不能用于原子上下文

struct completion {
    unsigned int done;
    wait_queue_head_t wait;
};

 

二、完成量使用的经典例子——创建内核线程

 

1. 相关的kthreadd内核线程启动流程

start_kernel
    rest_init /*start_kernel的最后调用的是rest_init*/
        pid = kernel_thread(kernel_init, NULL, CLONE_FS); /*这里面启动init进程*/
            free_initmem();/*这个线程里释放了__init段的内存*/
            try_to_run_init_process("/sbin/init") /*调用execve函数簇将pid=1的内核线程替换为init进程(pid=1)*/
        pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
            for(;;) /*用来循环创建内核线程(pid=2)*/
            create_kthread(create); 

 

2. complete的使用流程

struct kthread_create_info
{
    int (*threadfn)(void *data);
    void *data;
    int node;
    struct task_struct *result;
    /* 完成量 */
    struct completion *done;
    struct list_head list;
};

在创建内核线程的例子中,使用了一个kthread_create_info结构来封装了一个完成量:

//linux4.14.39/kernel/kthread.c
struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
                            void *data, int node,
                            const char namefmt[],
                            va_list args)
{
    /* 1.静态定义并初始化一个完成量 */
    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);
    /* 2.将完成量添加到链表中 */
    list_add_tail(&create->list, &kthread_create_list);
    spin_unlock(&kthread_create_lock);

    /* 3.唤醒kthreadd内核线程,是由它负责创建所有的内核线程 */
    wake_up_process(kthreadd_task);
    /*
     * 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.
     */
    /* 4.等待kthreadd创建完成这个内核线程 */
    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);
    }

    /* 5.获取完成量的执行结果 */
    task = create->result;
    if (!IS_ERR(task)) {
        static const struct sched_param param = { .sched_priority = 0 };

        vsnprintf(task->comm, sizeof(task->comm), namefmt, args);
        /*
         * 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);
    }

    /* 6. 释放完成量 */
    kfree(create);
    return task;
}

 

int kthreadd(void *unused)
{
    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_MEMORY]);

    current->flags |= PF_NOFREEZE;
    cgroup_init_kthreadd();

    for (;;) {
        /* 1.没有任务要创建的时候就休眠,要创建内核线程时会把它唤醒 */
        set_current_state(TASK_INTERRUPTIBLE);
        if (list_empty(&kthread_create_list))
            schedule();
        __set_current_state(TASK_RUNNING);

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

            /* 2.从链表中取出这个kthread_create_info结构 */
            create = list_entry(kthread_create_list.next, struct kthread_create_info, list);
            list_del_init(&create->list);
            spin_unlock(&kthread_create_lock);

            /* 3. 创建内核线程 */
            create_kthread(create);

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

    return 0;
}

 

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

    /* We want our own signal handler (we take no signals by default). */
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
    if (pid < 0) {
        /* If user was SIGKILLed, I release the structure. */
        struct completion *done = xchg(&create->done, NULL);

        if (!done) {
            kfree(create);
            return;
        }
        /* 1.给完成量的结果赋值 */
        create->result = ERR_PTR(pid);
        /* 2.唤醒这个完成量上等待的线程 */
        complete(done);
    }
}

 

标签:kthread,task,complete,create,list,实例,done,完成,struct
来源: https://www.cnblogs.com/hellokitty2/p/10982397.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有