日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2025/3/21 linux 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux下有3個特殊的進程,idle進程(PID=0PID=0), init進程(PID=1PID=1)和kthreadd(PID=2PID=2)


* idle進程由系統自動創建, 運行在內核態?

idle進程其pid=0,其前身是系統創建的第一個進程,也是唯一一個沒有通過fork或者kernel_thread產生的進程。完成加載系統后,演變為進程調度、交換


* init進程由idle通過kernel_thread創建,在內核空間完成初始化后, 加載init程序, 并最終用戶空間?

由0進程創建,完成系統的初始化. 是系統中所有其它用戶進程的祖先進程?
Linux中的所有進程都是有init進程創建并運行的。首先Linux內核啟動,然后在用戶空間中啟動init進程,再啟動其他系統進程。在系統啟動完成完成后,init將變為守護進程監視系統其他進程。


* kthreadd進程由idle通過kernel_thread創建,并始終運行在內核空間, 負責所有內核線程的調度和管理?

它的任務就是管理和調度其他內核線程kernel_thread, 會循環執行一個kthread的函數,該函數的作用就是運行kthread_create_list全局鏈表中維護的kthread, 當我們調用kernel_thread創建的內核線程會被加入到此鏈表中,因此所有的內核線程都是直接或者間接的以kthreadd為父進程?

我們下面就詳解分析1號進程的前世(kernel_init)今生(init進程)

Linux系統中的init進程(pid=1)是除了idle進程(pid=0,也就是init_task)之外另一個比較特殊的進程,它是Linux內核開始建立起進程概念時第一個通過kernel_thread產生的進程,其開始在內核態執行,然后通過一個系統調用,開始執行用戶空間的/sbin/init程序,期間Linux內核也經歷了從內核態到用戶態的特權級轉變,/sbin/init極有可能產生出了shell,然后所有的用戶進程都有該進程派生出來

1號進程


前面我們了解到了0號進程是系統所有進程的先祖, 它的進程描述符init_task是內核靜態創建的, 而它在進行初始化的時候, 通過kernel_thread的方式創建了兩個內核線程,分別是kernel_init和kthreadd,其中kernel_init進程號為1

start_kernel在其最后一個函數rest_init的調用中,會通過kernel_thread來生成一個內核進程,后者則會在新進程環境下調 用kernel_init函數,kernel_init一個讓人感興趣的地方在于它會調用run_init_process來執行根文件系統下的 /sbin/init等程序:

kernel_init


0號進程創建1號進程的方式如下

kernel_thread(kernel_init, NULL, CLONE_FS);
  • 1

我們發現1號進程的執行函數就是kernel_init, 這個函數被定義init/main.c中,如下所示

kernel_init函數將完成設備驅動程序的初始化,并調用init_post函數啟動用戶空間的init進程。

由0號進程創建1號進程(內核態),1號內核線程負責執行內核的部分初始化工作及進行系統配置,并創建若干個用于高速緩存和虛擬主存管理的內核線程。

init進程


隨后,1號進程調用do_execve運行可執行程序init,并演變成用戶態1號進程,即init進程。

init進程是linux內核啟動的第一個用戶級進程。init有許多很重要的任務,比如像啟動getty(用于用戶登錄)、實現運行級別、以及處理孤立進程。

它按照配置文件/etc/initab的要求,完成系統啟動工作,創建編號為1號、2號…的若干終端注冊進程getty。

每個getty進程設置其進程組標識號,并監視配置到系統終端的接口線路。當檢測到來自終端的連接信號時,getty進程將通過函數do_execve()執行注冊程序login,此時用戶就可輸入注冊名和密碼進入登錄過程,如果成功,由login程序再通過函數execv()執行shell,該shell進程接收getty進程的pid,取代原來的getty進程。再由shell直接或間接地產生其他進程。

上述過程可描述為:0號進程->1號內核進程->1號用戶進程(init進程)->getty進程->shell進程

注意,上述過程描述中提到:1號內核進程調用執行init函數并演變成1號用戶態進程(init進程),這里前者是init是函數,后者是進程。兩者容易混淆,區別如下:

  • kernel_init函數在內核態運行,是內核代碼

  • init進程是內核啟動并運行的第一個用戶進程,運行在用戶態下。

  • 一號內核進程調用execve()從文件/etc/inittab中加載可執行程序init并執行,這個過程并沒有使用調用do_fork(),因此兩個進程都是1號進程。

  • 當內核啟動了自己之后(已被裝入內存、已經開始運行、已經初始化了所有的設備驅動程序和數據結構等等),通過啟動用戶級程序init來完成引導進程的內核部分。因此,init總是第一個進程(它的進程號總是1)。

    當init開始運行,它通過執行一些管理任務來結束引導進程,例如檢查文件系統、清理/tmp、啟動各種服務以及為每個終端和虛擬控制臺啟動getty,在這些地方用戶將登錄系統。

    在系統完全起來之后,init為每個用戶已退出的終端重啟getty(這樣下一個用戶就可以登錄)。init同樣也收集孤立的進程:當一個進程啟動了一個子進程并且在子進程之前終止了,這個子進程立刻成為init的子進程。對于各種技術方面的原因來說這是很重要的,知道這些也是有好處的,因為這便于理解進程列表和進程樹圖。init的變種很少。絕大多數Linux發行版本使用sysinit(由Miguel van Smoorenburg著),它是基于System V的init設計。UNIX的BSD版本有一個不同的init。最主要的不同在于運行級別:System V有而BSD沒有(至少是傳統上說)。這種區別并不是主要的。在此我們僅討論sysvinit。 配置init以啟動getty:/etc/inittab文件

    關于init程序


    1號進程通過execve執行init程序來進入用戶空間,成為init進程,那么這個init在哪里呢

    內核在幾個位置上來查尋init,這幾個位置以前常用來放置init,但是init的最適當的位置(在Linux系統上)是/sbin/init。如果內核沒有找到init,它就會試著運行/bin/sh,如果還是失敗了,那么系統的啟動就宣告失敗了。

    因此init程序是一個可以又用戶編寫的進程, 如果希望看init程序源碼的朋友,可以參見

    init包說明學習鏈接
    sysvinit早期一些版本使用的初始化進程工具, 目前在逐漸淡出linux歷史舞臺, sysvinit 就是 system V 風格的 init 系統,顧名思義,它源于 System V 系列 UNIX。它提供了比 BSD 風格 init 系統更高的靈活性。是已經風行了幾十年的 UNIX init 系統,一直被各類 Linux 發行版所采用。淺析 Linux 初始化 init 系統(1):sysvinit
    upstartdebian, Ubuntu等系統使用的initdaemon淺析 Linux 初始化 init 系統(2): UpStart
    systemdSystemd 是 Linux 系統中最新的初始化系統(init),它主要的設計目標是克服 sysvinit 固有的缺點,提高系統的啟動速度淺析 Linux 初始化 init 系統(3) Systemd

    Ubuntu等使用deb包的系統可以通過dpkg -S查看程序所在的包

    CentOS等使用rpm包的系統可以通過rpm -qf查看系統程序所在的包

    參見

    Linux下查看并下載命令源碼包(根據命令/應用程序逆向獲取并且安裝其所屬源碼包)

    附錄


    kernel_init_freeable流程分析


    static noinline void __init kernel_init_freeable(void) {/** Wait until kthreadd is all set-up.*/wait_for_completion(&kthreadd_done);/* Now the scheduler is fully set up and can do blocking allocations */gfp_allowed_mask = __GFP_BITS_MASK;/** init can allocate pages on any node*/set_mems_allowed(node_states[N_MEMORY]);/** init can run on any cpu.*/set_cpus_allowed_ptr(current, cpu_all_mask);cad_pid = task_pid(current);smp_prepare_cpus(setup_max_cpus);do_pre_smp_initcalls();lockup_detector_init();smp_init();sched_init_smp();page_alloc_init_late();do_basic_setup();/* Open the /dev/console on the rootfs, this should never fail */if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)pr_err("Warning: unable to open an initial console.\n");(void) sys_dup(0);(void) sys_dup(0);/** check if there is an early userspace init. If yes, let it do all* the work*/if (!ramdisk_execute_command)ramdisk_execute_command = "/init";if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {ramdisk_execute_command = NULL;prepare_namespace();}/** Ok, we have completed the initial bootup, and* we're essentially up and running. Get rid of the* initmem segments and start the user-mode stuff..** rootfs is available now, try loading the public keys* and default modules*/integrity_load_keys();load_default_modules();}
    • 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
    執行流程說明
    wait_for_completion實例在kernel/sched/completion.c中, 等待Kernel Thread kthreadd (PID=2)創建完畢
    gfp_allowed_mask__GFP_BITS_MASK;設置bitmask, 使得init進程可以使用PM并且允許I/O阻塞操作
    set_mems_allowed(node_states[N_MEMORY]);init進程可以分配物理頁面
    set_cpus_allowed_ptr通過設置cpu_bit_mask, 可以限定task只能在特定的處理器上運行, 而initcurrent進程此時必然是init進程,設置其cpu_all_mask即使得init進程可以在任意的cpu上運行
    task_pid設置到目前運行進程init的pid號給cad_pid(cad_pid是用來接收ctrl-alt-del?reboot signal的進程, 如果設置C_A_D=1就表示可以處理來自ctl-alt-del的動作), 最后會調用?ctrl_alt_del(void)并確認C_A_D是否為1,確認完成后將執行cad_work=deferred_cad,執行kernel_restart
    smp_prepare_cpus體系結構相關的函數,實例在arch/arm/kernel/smp.c中,調用smp_prepare_cpus時,會以全局變量setup_max_cpus為函式參數max_cpus,以表示在編譯核心時,設定支援的最大CPU數量
    do_pre_smp_initcalls實例在init/main.c中, 會透過函式do_one_initcall,執行Symbol中 __initcall_start與__early_initcall_end之間的函數
    smp_init實例在kernel/smp.c中, 函數主要是由Bootstrap處理器,進行Active多核心架構下其它的處理器. 如果發生Online的處理器個數(from num_online_cpus)超過在核心編譯時,所設定的最大處理器個數 setup_max_cpus (from NR_CPUS),就會終止流程.如果該處理器目前屬於Present (也就是存在系統中),但尚未是Online的狀態,就會呼叫函式cpu_up(in kernel/cpu.c)來啟動該處理器.
    sched_init_smp實例在kernel/sched.c中, (1), 呼叫get_online_cpus,如果目前CPU Hotplug Active Write行程是自己,就直接返回.反之就把 cpu_hotplug.refcount加1 (表示多一個Reader)
    (2),取得Mutex Lock “sched_domains_mutex”
    (3),呼叫arch_init_sched_domains,設定scheduler domains與groups,參考Linux Documentation/scheduler/sched-domains.txt文件,一個Scheduling Domain會包含一個或多個CPU Groups,排程的Load-Balance就會根據Domain中的Groups來做調整.
    (4),釋放Mutex Lock “sched_domains_mutex”
    (5),呼叫put_online_cpus,如果目前CPU Hotplug Active Writer行程是自己,就直接返回.反之就把 cpu_hotplug.refcount減1,如果 cpu_hotplug.refcount減到為0,表示沒有其他Reader,此時如果有CPU Hotplug Active Writer行程在等待,就會透過wake_up_process喚醒該行程,以便讓等待中的Writer可以被執行下去.(也可以參考_cpu_up中對於函式cpu_hotplug_begin的說明).
    (6)注冊CPU Notifier cpuset_cpu_active/cpuset_cpu_inactive/update_runtime?
    (7),呼叫set_cpus_allowed_ptr,透過這函式可以設定CPU bitmask,限定Task只能在特定的處理器上運作.在這會用參數”non_isolated_cpus”,也就是會把init指定給non-isolated CPU. Linux Kernel可以在啟動時,透過Boot Parameters “isolcpus=“指定CPU編號或是范圍,讓這些處理器不被包含在Linux Kernel SMP balancing/scheduling算法內,可以在啟動后指派給特定的Task運作.而不在 “isolcpus=“ 指定范圍內的處理器就算是non-isolated CPU.
    (8),呼叫sched_init_granularity,透過函式update_sysctl,讓sysctl_sched_min_granularity=normalized_sysctl_sched_min_granularity,sysctl_sched_latency=normalized_sysctl_sched_latency,sysctl_sched_wakeup_granularity=normalized_sysctl_sched_wakeup_granularit
    do_basic_setup實例在init/main.c中,
    1,diaousermodehelper_init (in kernel/kmod.c),產生khelper workqueue.
    2,調用init_tmpfs (in mm/shmem.c),對VFS注冊Temp FileSystem.
    3,呼叫driver_init (in drivers/base/init.c),初始化Linux Kernel Driver System Model.
    4,呼叫init_irq_proc(in kernel/irq/proc.c),初始化 “/proc/irq”與其下的File Nodes.
    5,呼叫do_ctors (in init/main.c),執行位於Symbol __ctors_start 到 __ctors_end間屬於Section “.ctors” 的Constructor函式.
    6,透過函式do_initcalls,執行介於Symbol __early_initcall_end與__initcall_end之間的函式呼叫,
    sys_open實例在fs/fcntl.c中,”SYSCALL_DEFINE1(dup, unsigned int, fildes)”,在這會連續執行兩次sys_dup,復制兩個sys_open開啟/dev/console所產生的檔案描述0 (也就是會多生出兩個1與2),只是都對應到”/dev/console”,我們在System V streams下的Standard Stream一般而言會有如下的對應
    0:Standard input (stdin)
    1:Standard output (stdout)
    2:Standard error (stderr)
    (為方便大家參考,附上Wiki URL?http://en.wikipedia.org/wiki/Standard_streams?)
    ramdisk_execute_command與prepare_namespace1,如果ramdisk_execute_command為0,就設定ramdisk_execute_command = “/init”
    2,如果sys_access確認檔案ramdisk_execute_command 失敗,就把ramdisk_execute_command 設定為0,然后呼叫prepare_namespace去mount root FileSystem.
    integrity_load_keys至此我們初始化工作完成, 文件系統也已經準備好了,那么接下來加載 load integrity keys hook
    load_default_modules加載基本的模塊

    kernel_init分析


    static int __ref kernel_init(void *unused) {int ret;kernel_init_freeable();/* need to finish all async __init code before freeing the memory */async_synchronize_full();free_initmem();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();flush_delayed_fput();rcu_end_inkernel_boot();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.*/if (execute_command) {ret = run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (error %d).",execute_command, ret);}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/init.txt 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
    執行流程說明
    kernel_init_freeable調用kernel_init_freeable完成初始化工作,準備文件系統,準備模塊信息
    async_synchronize_full用以同步所有非同步函式呼叫的執行,在這函數中會等待List async_running與async_pending都清空后,才會返回. Asynchronously called functions主要設計用來加速Linux Kernel開機的效率,避免在開機流程中等待硬體反應延遲,影響到開機完成的時間
    free_initmemfree_initmem(in arch/arm/mm/init.c),釋放Linux Kernel介於__init_begin到 __init_end屬于init Section的函數的所有內存.并會把Page個數加到變量totalram_pages中,作為后續Linux Kernel在配置記憶體時可以使用的Pages. (在這也可把TCM范圍(__tcm_start到__tcm_end)釋放加入到總Page中,但TCM比外部記憶體有效率,適合多媒體,中斷,…etc等對效能要求高的執行需求,放到總Page中,成為可供一般目的配置的存儲范圍
    system_state設置運行狀態SYSTEM_RUNNING
    加載init進程,進入用戶空間a,如果ramdisk_execute_command不為0,就執行該命令成為init User Process.
    b,如果execute_command不為0,就執行該命令成為init User Process.
    c,如果上述都不成立,就依序執行如下指令
    run_init_process(“/sbin/init”);
    run_init_process(“/etc/init”);
    run_init_process(“/bin/init”);
    run_init_process(“/bin/sh”);
    也就是說會按照順序從/sbin/init, /etc/init, /bin/init 與 /bin/sh依序執行第一個 init User Process.
    如果都找不到可以執行的 init Process,就會進入Kernel Panic.如下所示panic(“No init found. Try passing init= option to kernel. ”“See Linux Documentation/init.txt for guidance.”);

    總結

    以上是生活随笔為你收集整理的Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品一区二区三区免费 | 亚洲精品美女网站 | 色女人av| 精品一区电影国产 | 污片在线看 | 91看黄 | 极品久久| 污污网站在线观看 | 特黄aaaaaa私密按摩 | 中文字幕5566 | 毛片啪啪啪| 91免费看大片 | 国产欧美日韩精品在线 | 成人午夜又粗又硬又大 | 成人精品亚洲人成在线 | 91亚洲国产成人久久精品网站 | 91国产在线免费观看 | 人人草人人 | 美丽的姑娘在线观看免费 | av资源免费 | 不卡在线一区二区 | 久久国产精品波多野结衣 | 天天操中文字幕 | 丰满人妻一区二区三区大胸 | 四虎精品影视 | 成人午夜视频在线播放 | 一二三在线视频 | 深夜福利在线免费观看 | 性色av浪潮 | 黄在线免费观看 | 国语对白对话在线观看 | 成年视频在线播放 | 2024国产精品视频 | av在线麻豆 | 久久影院午夜理论片无码 | 三级av | 久久久久亚洲av片无码下载蜜桃 | 美女四肢被绑在床扒衣 | 精品久久一区二区三区 | 国产精品成人国产乱 | 亚洲熟女一区二区三区 | r级无码视频在线观看 | 青青青在线 | 99国产精品99久久久久久粉嫩 | 国产日韩在线播放 | 欧美大片aaa | 欧美色图在线观看 | 天堂在线资源网 | 在线观看波多野结衣 | 妺妺窝人体色www在线小说 | 国产精品自拍亚洲 | 成人观看网站 | h无码动漫在线观看 | 国产精品久久久久久久午夜 | 日韩欧美99| 成年人网站在线 | 成人区人妻精品一区二区不卡视频 | 国产成人免费 | xxx性视频| 香蕉视频在线观看免费 | 欧美黑吊大战白妞 | 青青操在线视频 | 午夜亚洲一区 | 黄色理伦片 | 中文字幕网站 | 国产成人在线免费 | 婷婷伊人五月 | 韩国无码一区二区三区精品 | 91精品人妻一区二区三区蜜桃欧美 | www.youjizz日本| 国产精品一二区在线观看 | 久久桃花网 | 三上悠亚一区二区三区 | 欧美成人精品三级网站 | 国产精久久久久久 | 91网站观看 | 久久亚洲少妇 | 嫩草视频一区二区三区 | 国产精品三级在线观看 | 国产三级做爰高清在线 | 欧美大片aaa | 好大好爽好舒服 | 女生扒开尿口给男生捅 | 国产色| 三级福利 | 欧美日韩操 | 搞黄网站在线观看 | 欧美成人精品一区二区综合免费 | 久久久久久国产精品三级玉女聊斋 | 日本一道在线 | av天天有| 国产成人在线一区二区 | 亚洲专区欧美 | 一级大片在线观看 | 中文字幕在线观看免费高清 | 无套暴操| 天降女子在线观看 | 日韩中文第一页 | 天堂网91 |