参考:

1. linux常见进程与内核线程

2. Linux下2号进程的kthreadd--Linux进程的管理与调度(七)

本文中代码内核版本:3.2.0

kthreadd:这种内核线程只有一个,它的作用是管理调度其它的内核线程。这个线程不能关闭。它在内核初始化的时候被创建,会循环运行一个叫做kthreadd的函数,该函数的作用是运行kthread_create_list全局链表中维护的kthread。其他任务或代码想创建内核线程时需要调用kthread_create(或kthread_create_on_node)创建一个kthread,该kthread会被加入到kthread_create_list链表中,同时kthread_create会weak up kthreadd_task(即kthreadd)(增链表)。kthreadd再执行kthread时会调用老的接口——kernel_thread运行一个名叫“kthread”的内核线程去运行创建的kthread,被执行过的kthread会从kthread_create_list链表中删除(减链表),并且kthreadd会不断调用scheduler 让出CPU。kthreadd创建的kthread执行完后,会调到kthread_create()执行,之后再执行最初原任务或代码。

创建

在linux启动的C阶段start_kernel()的最后,rest_init()会开启两个进程:kernel_init,kthreadd,之后主线程变成idle线程,init/main.c。

linux下的3个特殊的进程:idle进程(PID=0),init进程(PID=1)和kthreadd(PID=2)。

* idle进程由系统自动创建, 运行在内核态   PID=0
idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换。

* init进程由idle通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终用户空间运行  PID=1 PPID=0
由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程 。
Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。

* kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理 PID=2 PPID=0
它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kthread_create创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程。所有的内核线程的PPID都是2。

注:所有的内核线程在大部分时间里都处于阻塞状态(TASK_INTERRUPTIBLE)只有在系统满足进程需要的某种资源的情况下才会运行。

  1. /*

* We need to finalize in a non-__init function, or else race conditions
* between the root thread and the init thread may cause start_kernel to
* be reaped by free_initmem before the root thread has proceeded to
* cpu_idle.
*
* gcc-3.4 accidentally inlines this function, so use noinline.
*/

  1. static __initdata DECLARE_COMPLETION(kthreadd_done);
  2.  
  3. static noinline void __init_refok rest_init(void)
  4. {
  5. int pid;
  6.  
  7. rcu_scheduler_starting();
  8. /*
  9. * We need to spawn init first so that it obtains pid 1, however
  10. * the init task will end up wanting to create kthreads, which, if
  11. * we schedule it before we create kthreadd, will OOPS.
  12. */
  13. kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
  14. numa_default_policy();
  15. pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
  16. rcu_read_lock();
  17. kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
  18. rcu_read_unlock();
  19. complete(&kthreadd_done);
  20.  
  21. /*
  22. * The boot idle thread must execute schedule()
  23. * at least once to get things moving:
  24. */
  25. init_idle_bootup_task(current);
  26. preempt_enable_no_resched();
  27. schedule();
  28.  
  29. /* Call into cpu_idle with preempt disabled */
  30. preempt_disable();
  31. cpu_idle();
  32. }

kthreadd任务

函数体定义在kernel/kthread.c中。

  1. static DEFINE_SPINLOCK(kthread_create_lock);
    static LIST_HEAD(kthread_create_list);
    struct task_struct *kthreadd_task;
  1. struct kthread_create_info
  2. {
  3. /* Information passed to kthread() from kthreadd. */
  4. int (*threadfn)(void *data);
  5. void *data;
  6. int node;
  7.  
  8. /* Result passed back to kthread_create() from kthreadd. */
  9. struct task_struct *result;
  10. struct completion done;
  11.  
  12. struct list_head list;
  13. };
  14.  
  15. struct kthread {
  16. int should_stop;
  17. void *data;
  18. struct completion exited;
  19. };
  1. int kthreadd(void *unused)
  2. {
  3. struct task_struct *tsk = current;
  4.  
  5. /* Setup a clean context for our children to inherit. */
  6. set_task_comm(tsk, "kthreadd");
  7. ignore_signals(tsk);
  8. set_cpus_allowed_ptr(tsk, cpu_all_mask);
  9. set_mems_allowed(node_states[N_HIGH_MEMORY]);
  10.  
  11. current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
  12.  
  13. for (;;) {
  14. set_current_state(TASK_INTERRUPTIBLE);
  15. if (list_empty(&kthread_create_list))
  16. schedule();
  17. __set_current_state(TASK_RUNNING);
  18.  
  19. spin_lock(&kthread_create_lock);
  20. while (!list_empty(&kthread_create_list)) {
  21. struct kthread_create_info *create;
  22.  
  23. create = list_entry(kthread_create_list.next,
  24. struct kthread_create_info, list);
  25. list_del_init(&create->list);
  26. spin_unlock(&kthread_create_lock);
  27.  
  28. create_kthread(create);
  29.  
  30. spin_lock(&kthread_create_lock);
  31. }
  32. spin_unlock(&kthread_create_lock);
  33. }
  34.  
  35. return ;
  36. }
  1. static void create_kthread(struct kthread_create_info *create)
  2. {
  3. int pid;
  4.  
  5. #ifdef CONFIG_NUMA
  6. current->pref_node_fork = create->node;
  7. #endif
  8. /* We want our own signal handler (we take no signals by default). */
  9. pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
  10. if (pid < ) {
  11. create->result = ERR_PTR(pid);
  12. complete(&create->done);
  13. }
  14. }

kthread任务

  1. static int kthread(void *_create)
  2. {
  3. /* Copy data: it's on kthread's stack */
  4. struct kthread_create_info *create = _create;
  5. int (*threadfn)(void *data) = create->threadfn;
  6. void *data = create->data;
  7. struct kthread self;
  8. int ret;
  9.  
  10. self.should_stop = ;
  11. self.data = data;
  12. init_completion(&self.exited);
  13. current->vfork_done = &self.exited;
  14.  
  15. /* OK, tell user we're spawned, wait for stop or wakeup */
  16. __set_current_state(TASK_UNINTERRUPTIBLE);
  17. create->result = current;
  18. complete(&create->done);
  19. schedule();
  20.  
  21. ret = -EINTR;
  22. if (!self.should_stop)
  23. ret = threadfn(data);
  24.  
  25. /* we can't just return, we must preserve "self" on stack */
  26. do_exit(ret);
  27. }
  1. /**
  2. * kthread_create_on_node - create a kthread.
  3. * @threadfn: the function to run until signal_pending(current).
  4. * @data: data ptr for @threadfn.
  5. * @node: memory node number.
  6. * @namefmt: printf-style name for the thread.
  7. *
  8. * Description: This helper function creates and names a kernel
  9. * thread. The thread will be stopped: use wake_up_process() to start
  10. * it. See also kthread_run().
  11. *
  12. * If thread is going to be bound on a particular cpu, give its node
  13. * in @node, to get NUMA affinity for kthread stack, or else give -1.
  14. * When woken, the thread will run @threadfn() with @data as its
  15. * argument. @threadfn() can either call do_exit() directly if it is a
  16. * standalone thread for which no one will call kthread_stop(), or
  17. * return when 'kthread_should_stop()' is true (which means
  18. * kthread_stop() has been called). The return value should be zero
  19. * or a negative error number; it will be passed to kthread_stop().
  20. *
  21. * Returns a task_struct or ERR_PTR(-ENOMEM).
  22. */
  23. struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
  24. void *data,
  25. int node,
  26. const char namefmt[],
  27. ...)
  28. {
  29. struct kthread_create_info create;
  30.  
  31. create.threadfn = threadfn;
  32. create.data = data;
  33. create.node = node;
  34. init_completion(&create.done);
  35.  
  36. spin_lock(&kthread_create_lock);
  37. list_add_tail(&create.list, &kthread_create_list);
  38. spin_unlock(&kthread_create_lock);
  39.  
  40. wake_up_process(kthreadd_task);
  41. wait_for_completion(&create.done);
  42.  
  43. if (!IS_ERR(create.result)) {
  44. static const struct sched_param param = { .sched_priority = };
  45. va_list args;
  46. va_start(args, namefmt);
  47. vsnprintf(create.result->comm, sizeof(create.result->comm),
  48. namefmt, args);
  49. va_end(args);
  50. /*
  51. * root may have changed our (kthreadd's) priority or CPU mask.
  52. * The kernel thread should not inherit these properties.
  53. */
  54. sched_setscheduler_nocheck(create.result, SCHED_NORMAL, &param);
  55. set_cpus_allowed_ptr(create.result, cpu_all_mask);
  56. }
  57. return create.result;
  58. }
  59. EXPORT_SYMBOL(kthread_create_on_node);

kernel/kthread.c的头文件include/linux/kthread.h定义kthread_create():

  1. #define kthread_create(threadfn, data, namefmt, arg...) \
  2. kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)

kthreadd-linux下2号进程的更多相关文章

  1. linux下1号进程的前世(kthread_init)今生(init)

    参考: 1.  Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度(六) 2. linux挂载根文件系统过程 3. BusyBox init工作 ...

  2. Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)【转】

    前言 Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2) idle进程由系统自动创建, 运行在内核态 idle进程其pi ...

  3. Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度(六)

    前面我们了解到了0号进程是系统所有进程的先祖, 它的进程描述符init_task是内核静态创建的, 而它在进行初始化的时候, 通过kernel_thread的方式创建了两个内核线程,分别是kernel ...

  4. Linux下2号进程的kthreadd--Linux进程的管理与调度(七)

    2号进程 内核初始化rest_init函数中,由进程 0 (swapper 进程)创建了两个process init 进程 (pid = 1, ppid = 0) kthreadd (pid = 2, ...

  5. linux的0号进程和1号进程

    linux的 0号进程 和 1 号进程 Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2) * idle进程由系统自动创 ...

  6. windows和linux下关闭Tomcat进程

    windows和linux下解决Tomcat进程 windows下启动Tomcat报错,8080端口号被占用,报错信息如下 两种解决方法,一种是关闭了这个端口号,另外一种是修改Tomcat下的serv ...

  7. windows和linux下杀死Tomcat进程,解决端口占用

    windows和linux下解决Tomcat进程 windows下启动Tomcat报错,8080端口号被占用,报错信息如下 两种解决方法,一种是关闭了这个端口号,另外一种是修改Tomcat下的serv ...

  8. linux下查看当前进程以及杀死进程

    ###linux下查看当前进程以及杀死进程 查看进程 ps命令查找与进程相关的PID号: ps a :显示现行终端机下的所有程序,包括其他用户的程序. ps -A :显示所有程序. ps c :列出程 ...

  9. Linux下查看某个进程打开的文件数-losf工具常用参数介绍

    Linux下查看某个进程打开的文件数-losf工具常用参数介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在linux操作系统中,一切皆文件.通过文件不仅仅可以访问常规数据,还 ...

随机推荐

  1. iOS计算富文本(NSMutableAttributedString)高度

    有时候开发中我们为了样式好看, 需要对文本设置富文本属性, 设置完后那么怎样计算其高度呢, 很简单, 方法如下: - (NSInteger)hideLabelLayoutHeight:(NSStrin ...

  2. Python的编码注释# -*- coding:utf-8 -*-

    # -*- coding:utf-8 -*-的主要作用是指定文件编码为utf-8, 因为一般默认的是ASCII码,如果要在文件里面写中文,运行时会出现乱码,加上这句之后会把文件编码强制转换为utf-8 ...

  3. Linux 命令缩写部分解释

    转:http://blog.chinaunix.net/uid-28408358-id-3890783.html bin = BINaries  /dev = DEVices  /etc = ETCe ...

  4. ActiveMQ实战-集群

    原文:http://blog.csdn.net/lifetragedy/article/details/51869032 ActiveMQ的集群 内嵌代理所引发的问题: 消息过载 管理混乱 如何解决这 ...

  5. TSynDBSQLDataSet

    TSynDBSQLDataSet 非内存表 TSynDBSQLDataSet = class(TSynBinaryDataSet) TSynBinaryDataSet = class(TSynVirt ...

  6. Android 拍照、从相册获取及裁剪的相关实现

    首先这些功能都是通过Intent去启动系统的服务去实现的,所以自然就有相应的Action.相关Actiong如下: 拍照——MediaStore.ACTION_IMAGE_CAPTURE (" ...

  7. JavaScript获取table中某一列的值的方法

    1.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  8. http://blog.csdn.net/hahalzb/article/details/5889545

    http://blog.csdn.net/hahalzb/article/details/5889545

  9. Scala快学笔记(二)

    一,基本概念 1,映射 Map与HashMap与TreeMap,SotredMap等区别: 1.HashMap键无序,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度 ...

  10. MongoDB分片集群新增分片(自用)

    机器IP为192.168.58.11,计划在上面新建两个分片并添加到原有分片集群中. 实施如下: 1.58.11创建mongodb文件夹 mkdir -p /opt/mongodb cd  /opt/ ...