linux 内核多线程编程

这里写图片描述


这里写图片描述

/**
    创建并启动一个内核线程.
*/
#define kthread_run(threadfn, data, namefmt, ...)              \
({                                     \
    struct task_struct *__k                        \
        /**
            创建一个内核线程,名字namefmt。但是这个线程不会马上执行。
            需要调用下面的函数来激活
        */
        = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
    if (!IS_ERR(__k))                          \
        //唤醒一个特定的线程
        wake_up_process(__k);                      \
    __k;                                   \
})

/**
    返回should_stop 标志,
    看一下kthread_stop()源码
    int kthread_stop(struct task_struct *k)
{
    struct kthread *kthread;
    int ret;
    ....
    ...
    if (k->vfork_done != NULL) {
        kthread->should_stop = 1; //should_stop 被置1
        wake_up_process(k);
        wait_for_completion(&kthread->exited);//等待线程结束
    }
    ...
*/
int kthread_should_stop(void)
{
    return to_kthread(current)->should_stop;
}

/**
    二号进程 
    该函数主要做了 : 
                1 : 遍历链表 kthread_create_list
                        如果为空 : 让出cpu,休眠
                2 : 如果不为空: 从链表中取出来,创建内核进程
*/
int kthreadd(void *unused)
{
    struct task_struct * tak = current;
    /**
        设定task的名字
    */
    set_task_comm(tsk,"kthreadd");
    {
        ...
        strlcpy(tsk->comm,buf,sizeof(tsk->comm));
        ...
    }
    /**
        忽略所有的信号
    */
    ignore_signals(tsk);
    {
        int i ;
        for (i = 0; i < _NSIG; ++i)
        {
            /**
                默认处理函数设置为SIG_IGN

                //act.sa_handler = do_sig;
                //act.sa_handler = SIG_IGN;
                act.sa_handler = SIG_DFL;    

                manpage中有这样的描述:
                    sa_handler specifies the action to be associated with signum and may be
                    SIG_DFL for the default action, SIG_IGN to ignore  this  signal,
            */
            t->sighand->action[i].sa.sa_handler = SIG_IGN;
        }
        flush_signals(t);
    }

    ....
    /**
        死循环
    */
    for(;;)
    {
        /**
            设置该内核线程的状态为TASK_INTERRUPTIBLE
            是为了下面调用schedule()。
        */
        set_current_state(TASK_INTERRUPTIBLE);

        /**
            如果kthread_create_list链表为空,那么
            就休眠。
            那么它在什么时候 被谁来唤醒呢?
            由kthread_create()函数唤醒
                    wake_up_process(kthreadd_task);
            下面会有分析
        */
        if (list_empty(&kthread_create_list))
        {
            schedule();
        }
        /**
            如果该线程被唤醒、或者上面的条件不成立,
            那么就设置该线程的状态为TASK_RUNNING
        */
        __set_current_state(TASK_RUNNING);

        spin_lock(&kthread_create_lock);

        /**
            判断kthread_create_list是否为空
            如果不为空,会进入这个while循环,会创建内核线程
        */
        while (!list_empty(&kthread_create_list)) 
        {
            struct kthread_create_info *create;

            /*
                取出全局链表kthread_create_list第一个节点
                那么谁往这个全局链表上放入节点呢?是kthread_create()函数来完成的
                        list_add_tail(&create.list, &kthread_create_list);
                下面有分析
            */
            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);
            {
                pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
                {
                    .....
                    /**
                        最终还是调用了do_fork()函数来创建的。<<linux内核设计与实现 3版>>书中说,内核线程是内核态的标准进程。
                    */
                    return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
                }
            }

            spin_lock(&kthread_create_lock);
        }

        spin_unlock(&kthread_create_lock);

    }
    return 0;
}

/**
    该函数主要做了两件事情 : 
                1 : 构造了一个kthread_create_info 结构体,将其挂接到 kthread_create_list链表上
                2 : 唤醒 内核线程kthreadd ,让其创建内核线程
*/
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[],...)
{
    struct kthread_create_info create;

/**
    根据传入的 参数,初始化kthread_create_info结构

    struct kthread_create_info
    {

        int (*threadfn)(void *data); //用于新创建的内核线程的运行函数  
        void *data;                  //参数

        struct task_struct *result; //创建成功后 返回的进程描述符
        struct completion done;     //完成量

        struct list_head list; //用于连接到全局链表kthread_create_list
    }
*/

    create.threadfn = threadfn;
    create.data = data;

    /**
        初始化完成量
    */
    init_completion(&create.done);

    spin_lock(&kthread_create_lock);
    /**
        将kthread_create_info添加到 kthread_create_list链表上。
        kthread_create()创建的内核进程请求信息都会挂接在这个链表上。
    */
    list_add_tail(&create.list, &kthread_create_list);
    spin_unlock(&kthread_create_lock);

    /**
        唤醒内核线程kthreadd
        pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
        kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    */
    wake_up_process(kthreadd_task);
    /**
        等待内核线程kthreadd创建内核线程完成
    */
    wait_for_completion(&create.done);

    if (!IS_ERR(create.result)) 
    {
        ...
    }
    return create.result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值