/**
创建并启动一个内核线程.
*/
#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, ®s, 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;
}
linux 内核多线程编程
最新推荐文章于 2021-05-06 17:18:41 发布