• 基于aarch64分析kernel源码 六:kernel_init进程(1号进程)、kthreadd进程(2号进程)


    一、kernel_init进程创建流程

    start_kernel 
    	--> arch_call_rest_init 
    		--> rest_init
    			--> pid = user_mode_thread(kernel_init, NULL, CLONE_FS)
    				---> kernel_clone
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、kernel_init

    static int __ref kernel_init(void *unused)
    {
    	int ret;
    
    	/*
    	 * Wait until kthreadd is all set-up.
    	 * 等到 kthreadd 全部设置完毕。
    	 */
    	wait_for_completion(&kthreadd_done);
    
    	kernel_init_freeable();
    	/* need to finish all async __init code before freeing the memory */
    	async_synchronize_full();
    
    	system_state = SYSTEM_FREEING_INITMEM;
    	kprobe_free_init_mem();
    	ftrace_free_init_mem();
    	kgdb_free_init_mem();
    	exit_boot_config();
    	free_initmem();
    	mark_readonly();
    
    	/*
    	 * Kernel mappings are now finalized - update the userspace page-table
    	 * to finalize PTI.
    	 */
    	pti_finalize();
    
    	system_state = SYSTEM_RUNNING;
    	numa_default_policy();
    
    	rcu_end_inkernel_boot();
    
    	do_sysctl_args();
    
    	if (ramdisk_execute_command) {
    		ret = run_init_process(ramdisk_execute_command);
    		if (!ret)
    			return 0;
    		pr_err("Failed to execute %s (error %d)\n",
    		       ramdisk_execute_command, ret);
    	}
    
    	/*
    	 * We try each of these until one succeeds.
    	 * 我们尝试其中的每一个,直到一个成功。
    	 *
    	 * The Bourne shell can be used instead of init if we are
    	 * trying to recover a really broken machine.
    	 * 如果我们试图恢复一台真正损坏的机器,可以使用 Bourne shell 代替 init。
    	 */
    	if (execute_command) {
    		ret = run_init_process(execute_command);
    		if (!ret)
    			return 0;
    		panic("Requested init %s failed (error %d).",
    		      execute_command, ret);
    	}
    
    	if (CONFIG_DEFAULT_INIT[0] != '\0') {
    		ret = run_init_process(CONFIG_DEFAULT_INIT);
    		if (ret)
    			pr_err("Default init %s failed (error %d)\n",
    			       CONFIG_DEFAULT_INIT, ret);
    		else
    			return 0;
    	}
    
    	if (!try_to_run_init_process("/sbin/init") ||
    	    !try_to_run_init_process("/etc/init") ||
    	    !try_to_run_init_process("/bin/init") ||
    	    !try_to_run_init_process("/bin/sh"))
    		return 0;
    
    	panic("No working init found.  Try passing init= option to kernel. "
    	      "See Linux Documentation/admin-guide/init.rst for guidance.");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    1、执行初始化函数。

    2、如果指定 ramdisk_execute_command,执行 ramdisk_execute_command 初始化程序。

    3、如果指定 execute_command,执行 execute_command 初始化程序。

    4、如果指定 CONFIG_DEFAULT_INIT,执行 CONFIG_DEFAULT_INIT 变量中保存的初始化程序。

    5、依次尝试执行 /sbin/init/etc/init/bin/init/bin/sh 程序。

    三、kthreadd 进程创建流程

    start_kernel 
    	--> arch_call_rest_init 
    		--> rest_init
    			--> pid = kernel_thread(kthreadd, NULL, NULL, CLONE_FS | CLONE_FILES)
    				---> kernel_clone
    
    • 1
    • 2
    • 3
    • 4
    • 5

    四、kthreadd

    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, housekeeping_cpumask(HK_TYPE_KTHREAD));
    	set_mems_allowed(node_states[N_MEMORY]);
    
    	current->flags |= PF_NOFREEZE;
    	cgroup_init_kthreadd();
    
    	for (;;) {
    		set_current_state(TASK_INTERRUPTIBLE);
    		if (list_empty(&kthread_create_list))
    			schedule();
    		__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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    kthreadd 利用 for(;;) 一直驻留在内存中运行,主要过程如下:

    • 检查 kthread_create_list 为空时,kthreadd 让出 cpu 的执行权。
    • kthread_create_list 不为空时,利用 while 循环遍历 kthread_create_list 链表。
    • 每取下一个链表节点后调用 create_kthread,创建内核线程。

    所有的内核线程都是 2 号进程创建的。

  • 相关阅读:
    MPEG-Pemetrexed 甲氧基聚乙二醇-培美曲塞
    windows平台goldgate同步oracle数据库
    (Spark Connect)使用Aerospike的 Spark 连接器
    STM32 HAL库 串口使用问题记录
    Web基础与HTTP协议
    成为职业游戏建模师有没有前景,未来自己该如何发展学习
    用mysql自带的定时器定时执行sql,每天0点执行,间隔分/时执行
    NoSQL:非关系型数据库分类
    【JVM技术专题】史上最清晰的探究和分析(Safe Point+Safe Region)的原理和运行机制「上篇」
    Mysql日志
  • 原文地址:https://blog.csdn.net/OnlyLove_/article/details/133752252