精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解分析0號進程的前世(init_task)今生(idle)

Linux閱碼場 ? 來源:Linuxer ? 2020-06-03 16:08 ? 次閱讀

前言

Linux下有3個特殊的進程,idle進程(PID = 0), init進程(PID = 1)和kthreadd(PID = 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為父進程

我們下面就詳解分析0號進程的前世(init_task)今生(idle)

idle的創建

在smp系統中,每個處理器單元有獨立的一個運行隊列,而每個運行隊列上又有一個idle進程,即有多少處理器單元,就有多少idle進程。

idle進程其pid=0,其前身是系統創建的第一個進程,也是唯一一個沒有通過fork()產生的進程。在smp系統中,每個處理器單元有獨立的一個運行隊列,而每個運行隊列上又有一個idle進程,即有多少處理器單元,就有多少idle進程。系統的空閑時間,其實就是指idle進程的”運行時間”。既然是idle是進程,那我們來看看idle是如何被創建,又具體做了哪些事情?

我們知道系統是從BIOS加電自檢,載入MBR中的引導程序(LILO/GRUB),再加載linux內核開始運行的,一直到指定shell開始運行告一段落,這時用戶開始操作Linux。

0號進程上下文信息–init_task描述符

init_task是內核中所有進程、線程的task_struct雛形,在內核初始化過程中,通過靜態定義構造出了一個task_struct接口,取名為init_task,然后在內核初始化的后期,通過rest_init()函數新建了內核init線程,kthreadd內核線程

內核init線程,最終執行/sbin/init進程,變為所有用戶態程序的根進程(pstree命令顯示),即用戶空間的init進程

開始的init是有kthread_thread創建的內核線程, 他在完成初始化工作后, 轉向用戶空間, 并且生成所有用戶進程的祖先

內核kthreadd內核線程,變為所有內核態其他守護線程的父線程。

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

所以init_task決定了系統所有進程、線程的基因, 它完成初始化后, 最終演變為0號進程idle, 并且運行在內核態

內核在初始化過程中,當創建完init和kthreadd內核線程后,內核會發生調度執行,此時內核將使用該init_task作為其task_struct結構體描述符,當系統無事可做時,會調度其執行, 此時該內核會變為idle進程,讓出CPU,自己進入睡眠,不停的循環,查看init_task結構體,其comm字段為swapper,作為idle進程的描述符。

idle的運行時機

idle 進程優先級為MAX_PRIO-20。早先版本中,idle是參與調度的,所以將其優先級設低點,當沒有其他進程可以運行時,才會調度執行 idle。而目前的版本中idle并不在運行隊列中參與調度,而是在運行隊列結構中含idle指針,指向idle進程,在調度器發現運行隊列為空的時候運行,調入運行

簡言之,內核中init_task變量就是是進程0使用的進程描述符,也是Linux系統中第一個進程描述符,init_task并不是系統通過kernel_thread的方式(當然更不可能是fork)創建的, 而是由內核黑客靜態創建的.

該進程的描述符在[init/init_task](

http://lxr.free-electrons.com/source/init/init_task.c?v=4.5#L17)中定義,代碼片段如下

/* Initial task structure */

struct task_struct init_task = INIT_TASK(init_task);

EXPORT_SYMBOL(init_task);

init_task描述符使用宏INIT_TASK對init_task的進程描述符進行初始化,宏INIT_TASK在include/linux/init_task.h文件中

init_task是Linux內核中的第一個線程,它貫穿于整個Linux系統的初始化過程中,該進程也是Linux系統中唯一一個沒有用kernel_thread()函數創建的內核態進程(內核線程)

在init_task進程執行后期,它會調用kernel_thread()函數創建第一個核心進程kernel_init,同時init_task進程繼續對Linux系統初始化。在完成初始化后,init_task會退化為cpu_idle進程,當Core 0的就緒隊列中沒有其它進程時,該進程將會獲得CPU運行。新創建的1號進程kernel_init將會逐個啟動次CPU,并最終創建用戶進程!

備注:core0上的idle進程由init_task進程退化而來,而AP的idle進程則是BSP在后面調用fork()函數逐個創建的

進程堆棧init_thread_union

init_task進程使用init_thread_union數據結構描述的內存區域作為該進程的堆棧空間,并且和自身的thread_info參數公用這一內存空間空間,

請參見

http://lxr.free-electrons.com/source/include/linux/init_task.h?v=4.5#L193

.stack = &init_thread_info,

而init_thread_info則是一段體系結構相關的定義,被定義在[/arch/對應體系/include/asm/thread_info.h]中,但是他們大多數為如下定義

#define init_thread_info (init_thread_union.thread_info)#define init_stack (init_thread_union.stack)

其中init_thread_union被定義在init/init_task.c, 緊跟著前面init_task的定義

/* * Initial thread structure. Alignment of this is handled by a special * linker map entry. */union thread_union init_thread_union __init_task_data = { INIT_THREAD_INFO(init_task) };

我們可以發現init_task是用INIT_THREAD_INFO宏進行初始化的, 這個才是我們真正體系結構相關的部分, 他與init_thread_info定義在一起,被定義在/arch/對應體系/include/asm/thread_info.h中,以下為x86架構的定義

參見

http://lxr.free-electrons.com/source/arch/x86/include/asm/thread_info.h?v=4.5#L65

#define INIT_THREAD_INFO(tsk) { .task = &tsk, .flags = 0, .cpu = 0, .addr_limit = KERNEL_DS, }

其他體系結構的定義請參見

/arch/對應體系/include/asm/thread_info.h中

架構 定義
x86 arch/x86/include/asm/thread_info.h
arm64 arch/arm64/include/asm/thread_info.h

init_thread_info定義中的__init_task_data表明該內核棧所在的區域位于內核映像的init data區,我們可以通過編譯完內核后所產生的System.map來看到該變量及其對應的邏輯地址

cat System.map-3.1.6| grep init_thread_union

進程內存空間

init_task的虛擬地址空間,也采用同樣的方法被定義

由于init_task是一個運行在內核空間的內核線程, 因此其虛地址段mm為NULL, 但是必要時他還是需要使用虛擬地址的,因此avtive_mm被設置為init_mm

參見

http://lxr.free-electrons.com/source/include/linux/init_task.h?v=4.5#L202

.mm = NULL, .active_mm=&init_mm,

其中init_mm被定義為init-mm.c中,參見

http://lxr.free-electrons.com/source/mm/init-mm.c?v=4.5#L16

struct mm_struct init_mm = { .mm_rb = RB_ROOT, .pgd = swapper_pg_dir, .mm_users = ATOMIC_INIT(2), .mm_count = ATOMIC_INIT(1), .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(init_mm.mmlist), INIT_MM_CONTEXT(init_mm)};

0號進程的演化

rest_init創建init進程(PID =1)和kthread進程(PID=2)

Linux在無進程概念的情況下將一直從初始化部分的代碼執行到start_kernel,然后再到其最后一個函數調用rest_init

大致是在vmlinux的入口startup_32(head.S)中為pid號為0的原始進程設置了執行環境,然后原是進程開始執行start_kernel()完成Linux內核的初始化工作。包括初始化頁表,初始化中斷向量表,初始化系統時間等。

從rest_init開始,Linux開始產生進程,因為init_task是靜態制造出來的,pid=0,它試圖將從最早的匯編代碼一直到start_kernel的執行都納入到init_task進程上下文中。

這個函數其實是由0號進程執行的, 他就是在這個函數中, 創建了init進程和kthreadd進程

這部分代碼如下:

參見

http://lxr.free-electrons.com/source/init/main.c?v=4.5#L386

static noinline void __init_refok rest_init(void){ int pid; rcu_scheduler_starting(); smpboot_thread_init(); /* * 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); 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);}

調用kernel_thread()創建1號內核線程, 該線程隨后轉向用戶空間, 演變為init進程

調用kernel_thread()創建kthreadd內核線程。

init_idle_bootup_task():當前0號進程init_task最終會退化成idle進程,所以這里調用init_idle_bootup_task()函數,讓init_task進程隸屬到idle調度類中。即選擇idle的調度相關函數。

調用schedule()函數切換當前進程,在調用該函數之前,Linux系統中只有兩個進程,即0號進程init_task和1號進程kernel_init,其中kernel_init進程也是剛剛被創建的。調用該函數后,1號進程kernel_init將會運行!

調用cpu_idle(),0號線程進入idle函數的循環,在該循環中會周期性地檢查。

創建kernel_init

在rest_init函數中,內核將通過下面的代碼產生第一個真正的進程(pid=1):

kernel_thread(kernel_init, NULL, CLONE_FS);

這個進程就是著名的pid為1的init進程,它會繼續完成剩下的初始化工作,然后execve(/sbin/init), 成為系統中的其他所有進程的祖先。

但是這里我們發現一個問題, init進程應該是一個用戶空間的進程, 但是這里卻是通過kernel_thread的方式創建的, 哪豈不是式一個永遠運行在內核態的內核線程么, 它是怎么演變為真正意義上用戶空間的init進程的?

1號kernel_init進程完成linux的各項配置(包括啟動AP)后,就會在/sbin,/etc,/bin尋找init程序來運行。該init程序會替換kernel_init進程(注意:并不是創建一個新的進程來運行init程序,而是一次變身,使用sys_execve函數改變核心進程的正文段,將核心進程kernel_init轉換成用戶進程init),此時處于內核態的1號kernel_init進程將會轉換為用戶空間內的1號進程init。戶進程init將根據/etc/inittab中提供的信息完成應用程序的初始化調用。然后init進程會執行/bin/sh產生shell界面提供給用戶來與Linux系統進行交互。

調用init_post()創建用戶模式1號進程。

關于init其他的信息我們這次先不研究,因為我們這篇旨在探究0號進程的詳細過程,

創建kthreadd

在rest_init函數中,內核將通過下面的代碼產生第一個kthreadd(pid=2)

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

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

0號進程演變為idle

/*

* 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=0的進程,在創建了init進程后,pid=0的進程調用 cpu_idle()演變成了idle進程。

0號進程首先執行init_idle_bootup_task,讓init_task進程隸屬到idle調度類中。即選擇idle的調度相關函數。

這個函數被定義在kernel/sched/core.c中,如下

void init_idle_bootup_task(struct task_struct *idle)

{

idle->sched_class = &idle_sched_class;

}

接著通過schedule_preempt_disabled來執行調用schedule()函數切換當前進程,在調用該函數之前,Linux系統中只有兩個進程,即0號進程init_task和1號進程kernel_init,其中kernel_init進程也是剛剛被創建的。調用該函數后,1號進程kernel_init將會運行

這個函數被定義在kernel/sched/core.c中,如下

/*** schedule_preempt_disabled - called with preemption disabled** Returns with preemption disabled. Note: preempt_count must be 1*/void __sched schedule_preempt_disabled(void){ sched_preempt_enable_no_resched(); schedule(); preempt_disable();}

最后cpu_startup_entry**調用cpu_idle_loop(),0號線程進入idle函數的循環,在該循環中會周期性地檢查**

cpu_startup_entry定義在kernel/sched/idle.c

void cpu_startup_entry(enum cpuhp_state state){ /* * This #ifdef needs to die, but it's too late in the cycle to * make this generic (arm and sh have never invoked the canary * init for the non boot cpus!). Will be fixed in 3.11 */#ifdef CONFIG_X86 /* * If we're the non-boot CPU, nothing set the stack canary up * for us. The boot CPU already has it initialized but no harm * in doing it again. This is a good place for updating it, as * we wont ever return from this function (so the invalid * canaries already on the stack wont ever trigger). */ boot_init_stack_canary();#endif arch_cpu_idle_prepare(); cpu_idle_loop();}

其中cpu_idle_loop就是idle進程的事件循環,定義在kernel/sched/idle.c

整個過程簡單的說就是,原始進程(pid=0)創建init進程(pid=1),然后演化成idle進程(pid=0)。init進程為每個從處理器(運行隊列)創建出一個idle進程(pid=0),然后演化成/sbin/init。

idle的運行與調度

idle的workload–cpu_idle_loop

從上面的分析我們知道,idle在系統沒有其他就緒的進程可執行的時候才會被調度。不管是主處理器,還是從處理器,最后都是執行的cpu_idle_loop()函數

其中cpu_idle_loop就是idle進程的事件循環,定義在kernel/sched/idle.c,早期的版本中提供的是cpu_idle,但是這個函數是完全依賴于體系結構的,不利用架構的分層,因此在新的內核中更新為更加通用的cpu_idle_loop,由他來調用體系結構相關的代碼

所以我們來看看cpu_idle_loop做了什么事情。

因為idle進程中并不執行什么有意義的任務,所以通常考慮的是兩點

節能

低退出延遲。

其代碼如下

/* * Generic idle loop implementation * * Called with polling cleared. */static void cpu_idle_loop(void){while (1) {/* * If the arch has a polling bit, we maintain an invariant: * * Our polling bit is clear if we're not scheduled (i.e. if * rq->curr != rq->idle). This means that, if rq->idle has * the polling bit set, then setting need_resched is * guaranteed to cause the cpu to reschedule. */ __current_set_polling(); quiet_vmstat(); tick_nohz_idle_enter(); while (!need_resched()) { check_pgt_cache(); rmb(); if (cpu_is_offline(smp_processor_id())) { rcu_cpu_notify(NULL, CPU_DYING_IDLE, (void *)(long)smp_processor_id()); smp_mb(); /* all activity before dead. */ this_cpu_write(cpu_dead_idle, true); arch_cpu_idle_dead(); } local_irq_disable(); arch_cpu_idle_enter(); /* * In poll mode we reenable interrupts and spin. * * Also if we detected in the wakeup from idle * path that the tick broadcast device expired * for us, we don't want to go deep idle as we * know that the IPI is going to arrive right * away */if (cpu_idle_force_poll || tick_check_broadcast_expired()) cpu_idle_poll();else cpuidle_idle_call(); arch_cpu_idle_exit(); } /* * Since we fell out of the loop above, we know * TIF_NEED_RESCHED must be set, propagate it into * PREEMPT_NEED_RESCHED. * * This is required because for polling idle loops we will * not have had an IPI to fold the state for us. */ preempt_set_need_resched(); tick_nohz_idle_exit(); __current_clr_polling(); /* * We promise to call sched_ttwu_pending and reschedule * if need_resched is set while polling is set. That * means that clearing polling needs to be visible * before doing these things. */ smp_mb__after_atomic(); sched_ttwu_pending(); schedule_preempt_disabled(); }}

循環判斷need_resched以降低退出延遲,用idle()來節能。

默認的idle實現是hlt指令,hlt指令使CPU處于暫停狀態,等待硬件中斷發生的時候恢復,從而達到節能的目的。即從處理器C0態變到 C1態(見 ACPI標準)。這也是早些年windows平臺上各種”處理器降溫”工具的主要手段。當然idle也可以是在別的ACPI或者APM模塊中定義的,甚至是自定義的一個idle(比如說nop)。

1.idle是一個進程,其pid為0。

2.主處理器上的idle由原始進程(pid=0)演變而來。從處理器上的idle由init進程fork得到,但是它們的pid都為0。

3.Idle進程為最低優先級,且不參與調度,只是在運行隊列為空的時候才被調度。

4.Idle循環等待need_resched置位。默認使用hlt節能。

希望通過本文你能全面了解linux內核中idle知識。

idle的調度和運行時機

我們知道, linux進程的調度順序是按照 rt實時進程(rt調度器), normal普通進程(cfs調度器),和idel的順序來調度的

那么可以試想如果rt和cfs都沒有可以運行的任務,那么idle才可以被調度,那么他是通過怎樣的方式實現的呢?

由于我們還沒有講解調度器的知識, 所有我們只是簡單講解一下

在normal的調度類,cfs公平調度器sched_fair.c中, 我們可以看到

staticconststruct sched_class fair_sched_class = {

.next= &idle_sched_class,

也就是說,如果系統中沒有普通進程,那么會選擇下個調度類優先級的進程,即使用idle_sched_class調度類進行調度的進程

當系統空閑的時候,最后就是調用idle的pick_next_task函數,被定義在/kernel/sched/idle_task.c中

參見

http://lxr.free-electrons.com/source/kernel/sched/idle_task.c?v=4.5#L2

static struct task_struct *pick_next_task_idle(struct rq *rq){ schedstat_inc(rq, sched_goidle); calc_load_account_idle(rq); return rq->idle; //可以看到就是返回rq中idle進程。}

這idle進程在啟動start_kernel函數的時候調用init_idle函數的時候,把當前進程(0號進程)置為每個rq運行隊列的的idle上。

rq->curr = rq->idle = idle;

這里idle就是調用start_kernel函數的進程,就是0號進程。

idle進程總結

系統允許一個進程創建新進程,新進程即為子進程,子進程還可以創建新的子進程,形成進程樹結構模型。整個linux系統的所有進程也是一個樹形結構。樹根是系統自動構造的(或者說是由內核黑客手動創建的),即在內核態下執行的0號進程,它是所有進程的遠古先祖。

在smp系統中,每個處理器單元有獨立的一個運行隊列,而每個運行隊列上又有一個idle進程,即有多少處理器單元,就有多少idle進程。

idle進程其pid=0,其前身是系統創建的第一個進程(我們稱之為init_task),也是唯一一個沒有通過fork或者kernel_thread產生的進程。

init_task是內核中所有進程、線程的task_struct雛形,它是在內核初始化過程中,通過靜態定義構造出了一個task_struct接口,取名為init_task,然后在內核初始化的后期,在rest_init()函數中通過kernel_thread創建了兩個內核線程內核init線程,kthreadd內核線程, 前者后來通過演變,進入用戶空間,成為所有用戶進程的先祖, 而后者則成為所有內核態其他守護線程的父線程, 負責接手內核線程的創建工作

然后init_task通過變更調度類為sched_idle等操作演變成為idle進程, 此時系統中只有0(idle), 1(init), 2(kthreadd)3個進程, 然后執行一次進程調度, 必然切換當前進程到到init

附錄–rest_init的執行解析

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19178

    瀏覽量

    229201
  • Linux
    +關注

    關注

    87

    文章

    11232

    瀏覽量

    208958
  • 進程
    +關注

    關注

    0

    文章

    202

    瀏覽量

    13948

原文標題:Linux下0號進程的前世(init_task進程)今生(idle進程)

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    深入了解Java泛型——從前世今生到PECS原則

    本文主要介紹泛型誕生的前世今生,特性,以及著名PECS原則的由來。 在日常開發中,必不可少的會使用到泛型,這個過程中經常會出現類似“為什么這樣會編譯報錯?”,“為什么這個列表無法添加
    的頭像 發表于 11-21 11:45 ?83次閱讀
    深入了解Java泛型——從<b class='flag-5'>前世</b><b class='flag-5'>今生</b>到PECS原則

    移植NXP GUI Guider的界面到小安派SCP4.3

    ); //wifi_start_firmware_task(); lwip_sntp_init(); bflb_mtd_init(); easyflash_init(); /* lvg
    的頭像 發表于 11-06 11:29 ?173次閱讀
    移植NXP GUI Guider的界面到小安派SCP4.3

    一文搞懂Linux進程的睡眠和喚醒

    一、常見的進程狀態與理解 在操作系統內部,有專門用來管理進程的結構體,叫做struct task_struct,也稱作進程控制塊(PCB),主要包含描述
    發表于 11-04 15:15

    esp32s3遇到Task watchdog got triggered. The following tasks did not reset the watchdog in time故障怎么解決?

    ) task_wdt: Tasks currently running: E (1486850) task_wdt: CPU 0: IDLE0 E (1486850)
    發表于 07-19 07:21

    esp8266EX報\"event_task\"(stack_size = 0,task handle = 40108368) overflow the heap_size.是不是內存不夠用?

    @ Mar 30 2018 18:54:06 phy ver: 1055_1, pp ver: 10.7 rf cal sector: 251 idle_task_hdl : 40107ab0,prio:0
    發表于 07-09 07:43

    在menuconfig中,如何配置wifi thread的stacksize的選項?

    進程運行狀態 Task Name StatusPrio HWMTask# Task_cliR 4 30813 IDLE0R 0 1008
    發表于 06-26 07:33

    ble_mesh_fast_prov_client在初始化的時候看門狗一直重啟的原因?

    ) task_wdt:- IDLE0 (CPU 0)E (5570) task_wdt: Tasks currently running:E (5570)
    發表于 06-26 07:12

    esp32同時讓wifi和藍牙工作,會出現wifi task看門狗復位的情況怎么解決?

    in time: E (6870) task_wdt:- IDLE (CPU 0) E (6870) task_wdt: Tasks currently running: E (68
    發表于 06-21 06:21

    Linxu進程的延遲與周期調度

    pstree 命令以樹狀結構顯示系統進程的繼承關系。樹狀圖將會以 pid (如果有指定) 或是以 init 為根,如果指定 user,則樹狀結構只顯示該用戶所擁有的進程
    發表于 04-18 11:24 ?172次閱讀

    OpenHarmony中SELinux使用詳解

    OpenHarmony中SELinux使用詳解 目錄 1.SELinux簡介 2.SELinux概念 3.SELinux模式 4.OH中SELinux使用詳解 5.OH中SELinux報錯分析
    發表于 04-03 10:43

    verilog task和function區別

    verilog中的task和function都是用于實現模塊中的可重復的功能,并且可以接收參數和返回結果。但是它們在編寫和使用上有一些區別。下面將詳細介紹task和function的區別。 語法結構
    的頭像 發表于 02-22 15:53 ?992次閱讀

    verilog中function和task的區別

    在Verilog中,Function和Task是用于模塊化設計和重用代碼的兩種重要元素。它們允許開發人員將復雜的操作分解為更小的功能單元,并在需要時調用它們。雖然Function和Task在某些方面
    的頭像 發表于 02-22 15:40 ?1797次閱讀

    啟動System Init進入OpenHarmony系統過程分析與適配

    1 關鍵字 啟動、Init、產品配置、啟動配置 2 簡要描述 本文檔主要以XX開發版為例分析OpenHarmony系統啟動過程、產品配置、啟動配置,并舉例說明如何配置。 內核加載Init進程
    發表于 01-26 10:04

    二極管的前世今生

    二極管的前世今生
    的頭像 發表于 12-14 18:35 ?1091次閱讀
    二極管的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>

    kernel到android核心啟動過程

    轉向用戶空間, 演變為init進程 調用kernel_thread()創建kthreadd內核線程。 init_idle_bootup_task():當前0
    的頭像 發表于 12-04 16:59 ?903次閱讀
    kernel到android核心啟動過程