進程的執行和掛起

1 進程總覽

進程是對邏輯的抽象,我們從操作系統的書籍中對進程有了很多的認識,但是對進程的實現可能不太瞭解,這篇文章嘗試解釋一下關於進程實現的大致原理。
    進程的實現,其實和我們平時寫代碼的時候一樣,比如我們要表示一個東西,我們會定義一個數據結構。進程也不例外。所以進程的本質就是一個數據結構,他保存了一系列的數據。操作系統以數組或者鏈表的形式和全部的進程管理起來。進程可以說分爲兩種
1 系統初始化時第一個進程,
2 除了第一個進程外的其他進程,他們都是由fork或者fork+execute系統調用創建出來的。
我們首先看一下進程的結構體都有什麼信息。
在這裏插入圖片描述
以上就是表示進程的結構體中主要的信息。那麼一個結構體就是表示一個進程。我們知道fork是以父進程爲模塊,複製一份父進程的結構體,然後修改某些字段。就變成了一個新的進程。如果調用execute的話,就是進一步修改複製出來的結構體中的字段(比如頁表、代碼段、數據段)。並且從硬盤加載相應的數據到內存。那麼第一個進程是如何產生的呢?因爲進程只是一個結構體,所以如果我們預定義了一個結構體,那麼就可以不通過fork的形式創建一個進程了。

2 進程的執行

當系統創建一個進程之後,會設置cs:ip寄存器的值,如果是fork,則ip就是fork函數後面的語句的ip地址。如果是execute則ip地址由編譯器指定。不管怎樣,當進程開始執行的時候,cpu就會解析cs:ip拿到一條指令去執行。那麼cs:ip是如何被解析的呢?
    執行進程的時候,tss選擇子(GDT索引)被加載到tss寄存器,然後把tss裏的上下文也加載到對應的寄存器,比如cr3,ldt選擇子。根據tss信息中的ldt索引首先從GDT找到進程ldt結構體數據的首地址,然後根據當前段的屬性,比如代碼段,則從cs中取得選擇子,系統從ldt表中取得進程線性空間的首地址、限長、權限等信息。用線性地址的首地址加上ip中的偏移,得到線性地址,然後再通過頁目錄和頁表得到物理地址,物理地址還沒有分配則進行缺頁異常等處理。

3 進程的掛起和喚醒

進程的掛起、阻塞、多進程。這些概念我們平時聽得比較多,現在我們來看看他是實現是怎樣的。進程的掛起,或者說阻塞分爲兩種。
1 主動掛起。通過sleep讓進程間歇性掛起。sleep的原理之前有分析過,就不再分析。大概的原理

  • 就是設置一個定時器,到期後喚醒進程。
  • 修改進程爲掛起狀態,等待喚醒。

2 被動掛起。
被動掛起的場景比較多,主要是進程申請一個資源,但是資源沒有滿足條件,則進程被操作系統掛起。比如我們讀一個管道的時候。管道沒有數據可讀,則進程被掛起。插入到管道的等待隊列。
在這裏插入圖片描述
當管道有內容寫入的時候,進程被喚醒。進程被掛起(分爲可被信號喚醒和不能被信號喚醒兩種)和喚醒的實現。

// 當前進程掛載到睡眠隊列p中,p指向隊列頭指針的地址
void sleep_on(struct task_struct **p)
{
	struct task_struct *tmp;

	if (!p)
		return;
	if (current == &(init_task.task))
		panic("task[0] trying to sleep");
	/*
		*p爲第一個睡眠節點的地址,即tmp指向第一個睡眠節點
		頭指針指向當前進程,這個版本的實現沒有采用真正鏈表的形式,
		他通過每個進程在棧中的臨時變量形成一個鏈表,每個睡眠的進程,
		在棧裏有一個變量指向後面一個睡眠節點,然後把鏈表的頭指針指向當前進程,
		然後切換到其他進程執行,當被wake_up喚醒的時候,wake_up會喚醒鏈表的第一個
		睡眠節點,因爲第一個節點裏保存了後面一個節點的地址,所以他喚醒後面一個節點,
		後面一個節點以此類推,從而把整個鏈表的節點喚醒,這裏的實現類似nginx的filter,
		即每個模塊保存後面一個節點的地址,然後把全局指針指向自己。
	*/
	tmp = *p;
	*p = current;
	// 不可中斷睡眠只能通過wake_up喚醒,即使有信號也無法喚醒
	current->state = TASK_UNINTERRUPTIBLE;
	// 進程調度
	schedule();
	// 喚醒後面一個節點
	if (tmp)
		tmp->state=0;
}

// 喚醒隊列中的第一個節點,並清空鏈表,因爲第一個節點會向後喚醒其他節點
void wake_up(struct task_struct **p)
{
	if (p && *p) {
		(**p).state=0;
		*p=NULL;
	}
}

我們發現,進程的實現,和我們平時寫代碼差不多,就是定義數據結構,然後實現操作數據結構的算法。當然,因爲涉及到硬件底層,操作系統的實現比我們的代碼複雜得多。時間有限,先說這麼多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章