linux kthread
来源:互联网 发布:真正美腿的数据化标准 编辑:程序博客网 时间:2024/05/16 06:38
前言
Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2):
a. PID=0 系统自动创建、运行在内核态;
b. PID=1 由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程;
c. PID=2 它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程。
1. kthreadd线程
路径:\linux-3.10.x\init\main.c start_kernel()-->rest_init();
static noinline void __init_refok rest_init(void){int pid;rcu_scheduler_starting();/* * We need to spawn init first so that it obtains pid 1, however * the init task will end up wanting to create kthreads, which, if * we schedule it before we create kthreadd, will OOPS. */kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);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); //唤醒完成量/* * The boot idle thread must execute schedule() * at least once to get things moving: */init_idle_bootup_task(current);schedule_preempt_disabled();/* Call into cpu_idle with preempt disabled */cpu_startup_entry(CPUHP_ONLINE);}
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); kthread线程创建,源码如下:
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); //运行kthread在任意cpu上运行set_mems_allowed(node_states[N_MEMORY]);current->flags |= PF_NOFREEZE;for (;;) {set_current_state(TASK_INTERRUPTIBLE); //设置当前进程为中断模式,即可被cpu打断if (list_empty(&kthread_create_list)) //kthread_create_list 链表是否为空,为空就调用schedule()让出cpu进入休眠schedule();__set_current_state(TASK_RUNNING); //到这里表示此进程已从休眠状态恢复,即kthread_create_list链表不为空,设置当前进程为运行态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;}
这里要看下是在哪里对kthread_create_list链表进行添加的, 在链表里主要是线程执行函数、线程参数进行绑定:
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...){struct kthread_create_info create;create.threadfn = threadfn; //线程执行函数create.data = data; //线程执行函数参数create.node = node;init_completion(&create.done); //初始化线程完成量spin_lock(&kthread_create_lock);list_add_tail(&create.list, &kthread_create_list); //加入到kthread_create_list链表中spin_unlock(&kthread_create_lock);wake_up_process(kthreadd_task); //唤醒kthreadd_task内核任务线程wait_for_completion(&create.done); //等待threadfn线程完成//至此线程创建完毕 , 会唤醒kthread_create_on_node()函数内的完成量wait_for_completion(&create.done);if (!IS_ERR(create.result)) {static const struct sched_param param = { .sched_priority = 0 };va_list args;va_start(args, namefmt);vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args);va_end(args);/* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m);set_cpus_allowed_ptr(create.result, cpu_all_mask);}return create.result;}EXPORT_SYMBOL(kthread_create_on_node);
通过create_kthread(create),完成真正的进程创建:
static void create_kthread(struct kthread_create_info *create){int pid;#ifdef CONFIG_NUMAcurrent->pref_node_fork = create->node;#endif/* 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) {create->result = ERR_PTR(pid);complete(&create->done);}}调用kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD)完成create线程的创建:
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 kthread self;int ret;self.flags = 0;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; //current 表示当前新创建的 thread 的 task_struct 结构complete(&create->done); //至此线程创建完毕 , 会唤醒kthread_create_on_node()函数内的等待完成量wait_for_completion(&create.done);schedule();ret = -EINTR;if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {__kthread_parkme(&self);ret = threadfn(data); //执行新进程中的函数}/* we can't just return, we must preserve "self" on stack */do_exit(ret);}
线程创建完毕:
创建新 thread 的进程恢复运行 kthread_create() 并且返回新创建线程的任务描述符 新创建的线程由于执行了 schedule() 调度,此时并没有执行.直到我们使用wake_up_process(p);唤醒新创建的线程线程被唤醒后, 会接着执行threadfn(data)
总结:
kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理,它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程我们在内核中通过kernel_create或者其他方式创建一个内核线程, 然后kthreadd内核线程被唤醒, 来执行内核线程创建的真正工作,新的线程将执行kthread函数, 完成创建工作,创建完毕后让出CPU,因此新的内核线程不会立刻运行.需要手工 wake up, 被唤醒后将执行自己的真正工作函数。
任何一个内核线程入口都是 kthread()
通过 kthread_create() 创建的内核线程不会立刻运行.需要手工 wake up.
通过 kthread_create() 创建的内核线程有可能不会执行相应线程函数threadfn而直接退出
- linux kthread
- Linux内核线程kthread
- Kthread
- kthread
- KThread
- 【Linux API】kthread的使用
- Linux 中的IPC(二)-----内核线程(Kthread)
- Linux内核---58.kthread与wait_event
- Linux OS内核 作业一:kthread和workqueue
- kthread usage
- kthread usage
- kthread usage
- kthread例子
- linuk kthread
- kthread schedule
- linux 下 kernel + kthread + 内核list + vmalloc + vfree + interruptible_sleep_on_timeout 学习实例
- linux模块编程(二)——运行不息的内核线程kthread
- linux模块编程(二)——运行不息的内核线程kthread
- Okhttp3+Rxjava+Retrofit2封装
- Redis入门
- idea搭建ssm项目
- BigDecimal类型的使用
- 存储过程的优缺点
- linux kthread
- 通过Java代码对咳嗽症状的一种简单表示(人工智能)
- 程序人生,从这里起航!——我的第一篇CSDN博客
- Linux 用户和用户组管理
- Python-opencv学习
- java 中的反射
- FireFox 火狐浏览器57以上版本linux下隐藏标题栏方法插件
- scrapy安装手把手指南
- [第二类斯特林数 FFT] BZOJ5093. 图的价值