sleep系統呼叫
我是乙個執行緒,生活在linux帝國。一直以來辛勤工作,日子過得平平淡淡,可今天早上發生了一件事讓我回想起來都後怕。
早上,我還是如往常一樣執行著人類編寫的**指令,不多時走到了乙個冷門的分支,乙個sleep()函式呼叫擺在了我的面前。
終於可以去休息了!聽老一輩的執行緒們說,執行了這個函式就可以休息休息了。我瞄了一眼引數,足足有5秒鐘的休息時間,我簡直樂壞了,沒有猶豫,趕緊執行了這個呼叫。
進入sleep()
函式後,又來到了nano_sleep()
函式,接著看到了乙個syscall
系統呼叫指令,我繼續執行,來到了核心空間。
進入核心空間後,我接連穿過了
把我累得夠嗆,說好讓我休息,沒想到休息之前還有這麼多事要做。
終於,我來到了乙個叫schedule()
的函式面前。
執行緒排程
進入schedule()
後,迎面走來一位髮鬚皆已花白的長者。
「小夥子,這是要來休息了,我是負責執行緒排程的使者,讓我看下你占用的cpu號碼」,一邊說一邊查詢著什麼。
「哦,是2號cpu,來,跟我到這邊來」,在他的指引下,我又來到了乙個函式面前。
「你先去pick_next_task()
找到乙個接盤俠,哦不,找到下乙個需要執行的執行緒,這是2號cpu的就緒佇列
,你可拿好了,等你辦完回來我再帶你去辦理交接手續」,說完給我手裡塞了乙個引數rq
,隨即便離開了,留下我不知所措。
我只好按他說的照辦,邁進了pick_next_task()
函式的大門,一位美女接待映入眼簾。
「先生您好,您來此想必是要尋找**執行緒吧」,見我到來,美女起身招呼。
「你猜的不錯,要麻煩你幫我處理一下,多謝了」
「您別客氣,把就緒佇列給我看看吧」
我先是愣了一下,反應過來後將手裡的rq引數給了她。
struct rq
;
美女拿著rq
一陣端詳,說到:「您運氣不錯哦,rq->nr_running和rq->cfs.h_nr_running相等,看來沒有實時執行緒,全是普通執行緒,您直接去那邊的公平排程cfs視窗fair_sched_class
那裡去辦理吧。」
我順著美女指向的方向看去,那邊一共有5個視窗:
「唉,美女,那要是不相等該去哪個視窗辦理呢?你告訴我一下,下次來我就知道了」
「不相等的話那就說明就緒佇列裡除了普通執行緒還有其他優先順序更高的執行緒,就得按照優先順序從stop_sched_class
視窗挨個向後詢問,直到找到乙個執行緒。不過我在這幹了這麼久,就實時執行緒所在的rt_sched_class
視窗和普通執行緒所在的fair_sched_class
最常用」,美女耐心的給我解釋到。
聽了她的解釋,我想到了乙個問題:「那要是都找不到執行緒需要執行怎麼辦,比如他們都在等待io事件之類的?那我怎麼交差啊」
「放心吧,最後那個idle_sched_class
視窗絕對不會讓你空手而歸的」,美女笑著說。
原來如此,我點了點頭。
來到fair_sched_class
視窗的旁邊,遞交了我的rq
引數,只見工作人員取出了其中的cfs_rq
:
struct cfs_rq ;
我這才注意到,原來這個cfs_rq
中指向了一棵紅黑樹,再仔細一看,這樹上的每個節點都是乙個執行緒task_struct
。
工作人員很快就取出了乙個task_struct
交給我,乙個年紀輕輕的執行緒小t,我帶著小t告別了美女接待,回到了schedule()
。
context_switch
看到我回來,長者起身言道:「小夥子,回來啦,走,帶你們去context_switch()
」
進入這個context_switch()
之後,長者又帶著我又做了一些準備工作,比如把當前的程序位址空間換成了小t的,最終我們來到了乙個叫switch_to
的地方。
「小夥子,再往前走幾步就是換班的地方了,就可以休息了,我就不送你了,感謝你這段時間的辛苦工作」,長者一邊說一邊拍拍我的肩膀。
告別了長者,我和小t踏上了這神秘的switch_to
,跟隨著一步一步的指令,我把自己執行緒上下文的暫存器都儲存到了我的核心棧上面,然後將棧指標指向了小t的核心棧,最後把小t儲存在他核心棧的指令位址載入進指令暫存器,終於完成了交接工作。
「小t,接下來就該你工作了,我要去休息了」,我和小t握手告別,來到旁邊準備眯一會兒。
神秘的喚醒
「醒醒,醒醒」,睡夢中聽到有人喚我。
我揉揉睡眼,看了下時間,這才睡了2s,時間還沒到,難道現在是在做夢?
「總算把你叫醒了,快起來,換班時間到了,該你上了」,我抬起頭才發現另外乙個執行緒小h站在面前。
「我休息時間還沒夠啊,怎麼選中了我啊,讓我再睡會兒」,說罷我就要躺下。
小h一把拉住了我,「別磨嘰了,就是你,快走」。
在小h的帶領下,我們又來到了那個叫switch_to
地方,只不過這一次我的角色變了。
小h一頓和我之前一樣的操作,把執行流程交給了我。
我再次獲得了執行**的能力,隨後回到了context_switch()
,又回到了schedule()
,看到了熟悉的長者。
我和長者再次告了別,繼續返回,最後通過sysret
蟲洞,回到了使用者態空間。
不過我馬上意識到事情不對勁,這裡並不是我最開始呼叫sleep()
的地方,而是一片完全陌生的區域,難道**出了問題,我這是到了**?
這一定是在做夢,我還在sleep()
呢,時間還沒夠,我只好這樣安慰自己。
我小心翼翼的執行了這裡的**,只是簡單輸出了一行日誌,然後來到了乙個叫__restore_rt()
的函式,又一條syscall
指令擺在了我的面前,我沒有猶豫再一次一頭紮進了核心空間。
經過一番折騰,又來到了sysret
蟲洞面前,不知道這一次又將帶我去到**。我閉上了眼睛跳了進去···
等我睜開眼睛,竟然奇蹟般的回到了最開始呼叫sleep()
的地方,這場夢終於醒了,慶幸我回到了這裡。
我看了一眼sleep()
的返回值,竟然是3。我又看了一眼日誌檔案,竟看到了夢裡輸出的那一行日誌。
難道那不是夢?這究竟是怎麼一回事?
未完待續······
彩蛋「奇怪,這個tcp資料報的ack和seq怎麼和剛才那個一樣,估計是重傳了吧」,帝國網路部的小q丟掉了這個重複的資料報。不過,同樣的事情接二連三的出現,經歷了上次那件事的小q不敢大意,趕緊向安全部長匯報了情況。
Linux記憶體 核心位址空間
一,為什麼需要高階記憶體 答 對於32位機器,linux虛擬記憶體最大為4g,其中3 4g空間是用作核心空間,考慮到如果物理記憶體大於1g,那麼物理記憶體不能得到完全的對映,因此,linux 規定 核心直接對映空間 最多對映 896m 物理記憶體,arm體系架構上有高階記憶體的概念,不過不是固定在8...
Linux使用者空間與核心位址空間
linux 作業系統和驅動程式執行在核心空間,應用程式執行在使用者空間,兩者不能簡單地使用指標傳遞資料,因為linux使用的虛擬記憶體機制,使用者空間的資料可能被換出,當核心空間使用使用者空間指標時,對應的資料可能不在記憶體中。linux核心位址對映模型 x86 cpu採用了段頁式位址對映模型。程序...
Linux核心之程序位址空間
程序使用的是虛擬記憶體中的位址,也叫線性位址,由作業系統協助相關硬體 如mmu 對映到實體地址。線性位址是通過頁表 page table 對映到物理記憶體,頁表由作業系統維護並被處理器引用。核心空間在頁表中擁有較高特權級,因此使用者態程式試圖訪問這些頁時會導致乙個頁錯誤。在linux中,核心空間是持...