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, ¶m);
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