女人荫蒂被添全过程13种图片,亚洲+欧美+在线,欧洲精品无码一区二区三区 ,在厨房拨开内裤进入毛片

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

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

3天內不再提示

Linux中內核搶占相關的基礎知識

Linux愛好者 ? 來源:老吳嵌入式 ? 作者:吳偉東Jack ? 2021-11-09 16:48 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

今天要分享的是搶占相關的基礎知識。本文以內核搶占為引子,概述一下 Linux 搶占的圖景。我盡量避開細節(jié)問題和源碼分析。

什么是內核搶占?

別急,咱們慢慢來。

先理解搶占 (preemption) 這個概念:

involuntarily suspending a running process is called preemption

奪取一個進程的 cpu 使用權的行為就叫做搶占。

根據是否可以支持搶占,多任務操作系統 (multitasking operating system) 分為 2 類:

1、cooperative multitasking os

這種 os,進程會一直運行直到它自愿停下來。這種自愿停止運行自己的行為稱為 yielding。協作式多任務系統,一聽就知道這是一個烏托邦式的系統,只有當所有進程都很 nice 并樂意經常 yielding 時,系統才能正常工作。如果某個進程太傻或者太壞,系統很快就完蛋了。

2、preemptive multitasking os

這種 os,會有一個調度器 (scheduler,其實就是一段用于調度進程的程序),scheduler 決定進程何時停止運行以及新進程何時開始運行。當一個進程的 cpu 使用權被 scheduler 分配給另一個進程時,就稱前一個進程被搶占了。

你可以把 sheduler 想象成非常智能的交警,交警按照一定的交通規(guī)則、當前的交通狀況以及車輛的優(yōu)先級 (救護車之類的),決定了哪些車可以行駛、哪些車要停下來等待。

很明顯,現階段,preemptive os 優(yōu)于 cooperative os。所以 Linux 被設計成 preemptive。

搶占的核心操作包括 2 個步驟:

1、從用戶態(tài)陷入到內核態(tài) (trap kernel),3 個路徑:

a. 系統調用,本質是 soft interrupt,通常就是一條硬件指令 (x86 的 int 0x80)。

b. 硬件中斷,最典型的就是會周期性發(fā)生的 timer 中斷,或者其他各種外設中斷。

c. exception,例如 page fault、div 0。

2、陷入到內核態(tài)后,在合適的時機下,調用 sheduler 選出一個最重要的進程,如果被選中的不是當前正在運行的進程的話,就會執(zhí)行 context switch 切換到新的進程。

根據搶占時機點的不同,搶占分為 2 種類型:

1、user preemption

這里的 user 并不是指在 user-space 里進行搶占,而是指在返回 user-space 前進行搶占,具體的:

When returning to user-space from a system call

When returning to user-space from an interrupt handler

即從 system call 和 interrupt handler 返回到 user-space 前進行搶占,這時仍然是在 kernel-space 里,搶占是需要非常高的權限的事情,user-space 沒權利也不應該干這事。

2、kernel preemption

Linux 2.6 之前是不支持內核搶占的。這意味著當處于用戶空間的進程請求內核服務時,在該進程阻塞(進入睡眠)等待某事(通常是 I/O)或系統調用完成之前,不能調度其他進程。支持內核搶占意味著當一個進程在內核里運行時,另一個進程可以搶占第一個進程并被允許運行,即使第一個進程尚未完成其在內核里的工作。

支持內核搶占 vs 不支持內核搶占

在上圖中,進程 A 已經通過系統調用進入內核,也許是對設備或文件的 write() 調用。內核代表進程 A 執(zhí)行時,具有更高優(yōu)先級的進程 B 被中斷喚醒。內核搶占進程 A 并將 CPU 分配給進程 B,即使進程 A 既沒有阻塞也沒有完成其在內核里的工作。

內核搶占的時機:

When an interrupt handler exits, before returning to kernel-space

When kernel code becomes preemptible again

If a task in the kernel explicitly calls schedule()

If a task in the kernel blocks (which results in a call to schedule() )

為什么要引入內核搶占?

根本原因:

trade-offs between latency and throughput

在系統延遲和吞吐量之間進行權衡。

并不是說內核搶占就是絕對的好,使用什么搶占機制最優(yōu)是跟你的應用場景掛鉤的。如果不是為了滿足用戶,內核其實是完全不想進行進程切換的,因為每一次 context switch,都會有 overhead,這些 overhead 就是對 cpu 的浪費,意味著吞吐量的下降。

但是,如果你想要系統的響應性好一點,就得盡量多的允許搶占的發(fā)生,這是 Linux 作為一個通用操作系統所必須支持的。當你的系統做到隨時都可以發(fā)生搶占時,系統的響應性就會非常好。

為了讓用戶根據自己的需求進行配置,Linux 提供了 3 種 Preemption Model。

CONFIG_PREEMPT_NONE=y:不允許內核搶占,吞吐量最大的 Model,一般用于 Server 系統。

CONFIG_PREEMPT_VOLUNTARY=y:在一些耗時較長的內核代碼中主動調用cond_resched()讓出CPU,對吞吐量有輕微影響,但是系統響應會稍微快一些。

CONFIG_PREEMPT=y:除了處于持有 spinlock 時的 critical section,其他時候都允許內核搶占,響應速度進一步提升,吞吐量進一步下降,一般用于 Desktop / Embedded 系統。

另外,還有一個沒有合并進主線內核的 Model: CONFIG_PREEMPT_RT,這個模式幾乎將所有的 spinlock 都換成了 preemptable mutex,只剩下一些極其核心的地方仍然用禁止搶占的 spinlock,所以基本可以認為是隨時可被搶占。

搶占前的檢查

這里的檢查是同時針對所有的 preemption 的。如果你理解了前面的 4 種 preempiton model 的話,應該能感覺到其實是不用太嚴格區(qū)分 user / kernel preemption,所有搶占的作用和性質都一樣:降低 lantency,完全可以將它們一視同仁。

搶占的發(fā)生要同時滿足兩個條件:

需要搶占;

能搶占;

1、是否需要搶占?

判斷是否需要搶占的依據是:thread_info 的成員 flags 是否設置了 TIF_NEED_RESCHED 標志位。

相關的 API:

set_tsk_need_resched() 用于設置該 flag。

tif_need_resched() 被用來判斷該 flag 是否置位。

resched_curr(struct rq *rq),標記當前 runqueue 需要搶占。

2、是否能搶占?

搶占發(fā)生的前提是要確保此次搶占是安全的 (preempt-safe)。什么才是 preempt-safe:不產生 race condition / deadlock。

值得注意的是,只有 kernel preemption 才有被禁止的可能,而 user preemption 總是被允許,因此這時馬上就要返回 user space 了,肯定是處于一個可搶占的狀態(tài)了。

在引入內核搶占機制的同時引入了為 thread_info 添加了新的成員:preempt_count ,用來保證搶占的安全性,獲取鎖時會增加 preempt_count,釋放鎖時則會減少。搶占前會檢查 preempt_count 是否為 0,為 0 才允許搶占。

相關的 API:

preempt_enable(),使能內核搶占,可嵌套調用。

preempt_disable(),關閉內核搶占,可嵌套調用。

preempt_count(),返回 preempt_count。

什么場景會設置需要搶占 (TIF_NEED_RESCHED = 1)

通過 grep resched_curr 可以找出大多數標記搶占的場景。

下面列舉的是幾個我比較關心的場景。

1、周期性的時鐘中斷

時鐘中斷處理函數會調用 scheduler_tick(),它通過調度類(scheduling class) 的 task_tick 方法 檢查進程的時間片是否耗盡,如果耗盡則標記需要搶占:

// kernel/sched/core.c

void scheduler_tick(void)

{

[。..]

curr-》sched_class-》task_tick(rq, curr, 0);

[。..]

}

Linux 的調度策略被封裝成調度類,例如 CFS、Real-Time。CFS 調度類的 task_tick() 如下:

// kernel/sched/fair.c

task_tick_fair()

-》 entity_tick()

-》 resched_curr(rq_of(cfs_rq));

2、喚醒進程的時候

當進程被喚醒的時候,如果優(yōu)先級高于 CPU 上的當前進程,就會觸發(fā)搶占。相應的內核代碼中,try_to_wake_up() 最終通過 check_preempt_curr() 檢查是否標記需要搶占:

// kernel/sched/core.c

void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)

{

const struct sched_class *class;

if (p-》sched_class == rq-》curr-》sched_class) {

rq-》curr-》sched_class-》check_preempt_curr(rq, p, flags);

} else {

for_each_class(class) {

if (class == rq-》curr-》sched_class)

break;

if (class == p-》sched_class) {

resched_curr(rq);

break;

}

}

}

[。..]

}

參數 “p” 指向被喚醒進程,“rq” 代表搶占的 CPU。如果 p 的調度類和 rq 當前的調度類相同,則調用 rq 當前的調度類的 check_preempt_curr() (例如 cfs 的 check_preempt_wakeup()) 來判斷是否要標記需要搶占。

如果 p 的調度類 》 rq 當前的調度類,則用 resched_curr() 標記需要搶占,反之,則不標記。

3、新進程創(chuàng)建的時候

如果新進程的優(yōu)先級高于 CPU 上的當前進程,會需要觸發(fā)搶占。相應的代碼是 sched_fork(),它再通過調度類的 task_fork() 標記需要搶占:

// kernel/sched/core.c

int sched_fork(unsigned long clone_flags, struct task_struct *p)

{

[。..]

if (p-》sched_class-》task_fork)

p-》sched_class-》task_fork(p);

[。..]

}

// kernel/sched/fair.c

static void task_fork_fair(struct task_struct *p)

{

[。..]

if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) {

resched_curr(rq);

}

[。..]

}

4、進程修改 nice 值的時候

如果修改進程 nice 值導致優(yōu)先級高于 CPU 上的當前進程,也要標記需要搶占,代碼見 set_user_nice()。

// kernel/sched/core.c

void set_user_nice(struct task_struct *p, long nice)

{

[。..]

// If the task increased its priority or is running and lowered its priority, then reschedule its CPU

if (delta 《 0 || (delta 》 0 && task_running(rq, p)))

resched_curr(rq);

}

還有很多場景,這里就不一一列舉了。

什么場景下要禁止內核搶占 (preempt_count 》 0)

有幾種場景是明確需要關閉內核搶占的。

1、訪問 Per-CPU data structures 的時候

看下面這個例子:

struct this_needs_locking tux[NR_CPUS];

tux[smp_processor_id()] = some_value;

/* task is preempted here.。. */

something = tux[smp_processor_id()];

如果搶占發(fā)生在注釋所在的那一行,當進程再次被調度時,smp_processor_id() 值可能已經發(fā)生變化了,這種場景下需要通過禁止內核搶占來做到 preempt safe。

2、訪問 CPU state 的時候

這個很好理解,你正在操作 CPU 相關的寄存器以進行 context switch 時,肯定是不能再允許搶占。

asmlinkage __visible void __sched schedule(void)

{

struct task_struct *tsk = current;

sched_submit_work(tsk);

do {

// 調度前禁止內核搶占

preempt_disable();

__schedule(false);

sched_preempt_enable_no_resched();

} while (need_resched());

sched_update_worker(tsk);

}

3、持有 spinlock 的時候

支持內核搶占,這意味著進程有可能與被搶占的進程在相同的 critical section 中運行。為防止這種情況,當持有自旋鎖時,要禁止內核搶占。

static inline void __raw_spin_lock(raw_spinlock_t *lock)

{

preempt_disable();

spin_acquire(&lock-》dep_map, 0, 0, _RET_IP_);

LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);

}

還有很多場景,這里就不一一列舉了。

真正執(zhí)行搶占的地方

這部分是 platform 相關的,下面以 ARM64 Linux-5.4 為例,快速看下執(zhí)行搶占的具體代碼。

執(zhí)行 user preemption

系統調用和中斷返回用戶空間的時候:

它們都是在 ret_to_user() 里判斷是否執(zhí)行用戶搶占。

// arch/arm64/kernel/entry.S

ret_to_user() // 返回到用戶空間

work_pending()

do_notify_resume()

schedule()

// arch/arm64/kernel/signal.c

asmlinkage void do_notify_resume(struct pt_regs *regs,

unsigned long thread_flags)

{

do {

[。..]

// 檢查是否要需要調度

if (thread_flags & _TIF_NEED_RESCHED) {

local_daif_restore(DAIF_PROCCTX_NOIRQ);

schedule();

} else {

[。..]

} while (thread_flags & _TIF_WORK_MASK);

}

執(zhí)行 kernel preemption

中斷返回內核空間的時候:

// arch/arm64/kernel/entry.S

el1_irq

irq_handler

arm64_preempt_schedule_irq

preempt_schedule_irq

__schedule(true)

// kernel/sched/core.c

/* This is the entry point to schedule() from kernel preemption */

asmlinkage __visible void __sched preempt_schedule_irq(void)

{

[。..]

do {

preempt_disable();

local_irq_enable();

__schedule(true);

local_irq_disable();

sched_preempt_enable_no_resched();

} while (need_resched());

exception_exit(prev_state);

}

內核恢復為可搶占的時候:

前面列舉了集中關閉搶占的場景,當離開這些場景時,會恢復內核搶占。

例如 spinlock unlock 時:

static inline void __raw_spin_unlock(raw_spinlock_t *lock)

{

spin_release(&lock-》dep_map, 1, _RET_IP_);

do_raw_spin_unlock(lock);

preempt_enable(); // 使能搶占時,如果需要,就會執(zhí)行搶占

}

// include/linux/preempt.h

#define preempt_enable()

do {

barrier();

if (unlikely(preempt_count_dec_and_test()))

__preempt_schedule();

} while (0)

內核顯式地要求調度的時候:

內核里有大量的地方會顯式地要求進行調度,最常見的是:cond_resched() 和 sleep()類函數,它們最終都會調用到 __schedule()。

內核阻塞的時候:

例如 mutex,sem,waitqueue 獲取不到資源,或者是等待 IO。這種情況下進程會將自己的狀態(tài)從TASK_RUNNING 修改為 TASK_INTERRUPTIBLE,然后調用 schedule() 主動讓出 CPU 并等待喚醒。

// block/blk-core.c

static struct request *get_request(struct request_queue *q, int op,

int op_flags, struct bio *bio,

gfp_t gfp_mask)

{

[。..]

prepare_to_wait_exclusive(&rl-》wait[is_sync], &wait,

TASK_UNINTERRUPTIBLE);

io_schedule(); // 會調用 schedule();

[。..]

}

責任編輯:haq

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

    關注

    5144

    文章

    19592

    瀏覽量

    316087
  • 內核
    +關注

    關注

    3

    文章

    1414

    瀏覽量

    41227
  • Linux
    +關注

    關注

    87

    文章

    11492

    瀏覽量

    213196

原文標題:內核搶占,讓世界變得更美好

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    效果器的基礎知識

    電子發(fā)燒友網站提供《效果器的基礎知識.doc》資料免費下載
    發(fā)表于 03-26 14:30 ?4次下載

    PCB繪制基礎知識

    電子發(fā)燒友網站提供《PCB繪制基礎知識.pdf》資料免費下載
    發(fā)表于 01-21 15:20 ?6次下載
    PCB繪制<b class='flag-5'>基礎知識</b>

    射頻前端設計的功率等級基礎知識

    伴隨更多頻段的增加和愈發(fā)復雜的移動設備出現,蜂窩通信市場已發(fā)生巨大變化。隨著4G和5G的部署,3GPP的最新規(guī)范已將PC2引入FDD頻段,更高的發(fā)射功率水平也由此帶來了與之相關的全新挑戰(zhàn)。下面,就讓我們回顧一下PC2的基礎知識,并深入探討PC2如何隨著這些新的5G部署而演
    的頭像 發(fā)表于 01-07 11:26 ?1380次閱讀
    射頻前端設計<b class='flag-5'>中</b>的功率等級<b class='flag-5'>基礎知識</b>

    EMC基礎知識-華為

    EMC基礎知識-華為
    發(fā)表于 01-06 14:09 ?2次下載

    品質管理基礎知識

    品質管理基礎知識
    的頭像 發(fā)表于 11-01 11:08 ?634次閱讀
    品質管理<b class='flag-5'>基礎知識</b>

    連接器相關基礎知識大講解

    最近很多讀者想要補補連接器相關知識,今天小編就和大家來探討下連接器的相關知識。 以下和大家來了連接器基礎知識,將從六個方面和大家分享,想了
    的頭像 發(fā)表于 11-01 11:03 ?1218次閱讀

    linux內核通用HID觸摸驅動

    linux內核,為HID觸摸面板實現了一個通用的驅動程序,位于/drivers/hid/hid-multitouch.c文件。hid觸摸驅動是以struct hid_driver
    的頭像 發(fā)表于 10-29 10:55 ?2136次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b>通用HID觸摸驅動

    Verilog HDL的基礎知識

    本文繼續(xù)介紹Verilog HDL基礎知識,重點介紹賦值語句、阻塞與非阻塞、循環(huán)語句、同步與異步、函數與任務語法知識
    的頭像 發(fā)表于 10-24 15:00 ?1130次閱讀
    Verilog HDL的<b class='flag-5'>基礎知識</b>

    負載開關基礎知識

    電子發(fā)燒友網站提供《負載開關基礎知識.pdf》資料免費下載
    發(fā)表于 10-08 09:56 ?2次下載
    負載開關<b class='flag-5'>基礎知識</b>

    全新的半導體基礎知識

    《全新的半導體基礎知識》首先對流行于電子書刊上數十年之久的經典半導體基礎知識存在的謬誤進行了全方位的討論,然后以半導體內部結構為抓手,以G型半導體(客供電子型半導體)、H型半導體(主供電子型半導體
    的頭像 發(fā)表于 09-20 11:30 ?1950次閱讀
    全新的半導體<b class='flag-5'>基礎知識</b>

    linux驅動程序如何加載進內核

    Linux系統,驅動程序是內核與硬件設備之間的橋梁。它們允許內核與硬件設備進行通信,從而實現對硬件設備的控制和管理。 驅動程序的編寫 驅動程序的編寫是
    的頭像 發(fā)表于 08-30 15:02 ?1038次閱讀

    Linux內核測試技術

    Linux 內核Linux操作系統的核心部分,負責管理硬件資源和提供系統調用接口。隨著 Linux 內核的不斷發(fā)展和更新,其復雜性和代碼規(guī)
    的頭像 發(fā)表于 08-13 13:42 ?997次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>測試技術

    Linux內核頁表映射的基礎知識

    大家在看內核代碼時會經常看的以上術語,但在ARM的芯片手冊并沒有用到這些術語,而是使用L1,L2,L3頁表這種術語。
    的頭像 發(fā)表于 08-07 15:53 ?1482次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b>頁表映射的<b class='flag-5'>基礎知識</b>

    Linux內核的頁面分配機制

    Linux內核是如何分配出頁面的,如果我們站在CPU的角度去看這個問題,CPU能分配出來的頁面是以物理頁面為單位的。也就是我們計算機中常講的分頁機制。本文就看下Linux
    的頭像 發(fā)表于 08-07 15:51 ?614次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b>的頁面分配機制

    C++語言基礎知識

    電子發(fā)燒友網站提供《C++語言基礎知識.pdf》資料免費下載
    發(fā)表于 07-19 10:58 ?8次下載
    主站蜘蛛池模板: 江源县| 秀山| 穆棱市| 安达市| 凤台县| 柳林县| 河北区| 梁山县| 洮南市| 大冶市| 西丰县| 达孜县| 含山县| 弥渡县| 武安市| 昌乐县| 乳山市| 东乡县| 巴青县| 自贡市| 志丹县| 肃宁县| 孙吴县| 宁河县| 集安市| 宣城市| 开阳县| 遵义县| 双辽市| 军事| 灌云县| 灵璧县| 左权县| 宜阳县| 宾阳县| 田东县| 儋州市| 凤城市| 朔州市| 安顺市| 汤原县|