35
國國國國國國 國國國國國國 國國國國 第第第 第第第第第第

作業系統

Embed Size (px)

DESCRIPTION

作業系統. 第七章 行程相關實作. 第七章 行程相關實作. 資料結構 行程描述器 行程狀態 行程串列 就緒佇列 行程運作 行程間的溝通 摘要. 資料結構. 以作業系統的觀點來看行程,一個行程控制區塊就代表一個行程。 Linux 中與行程相關的資料結構 行程控制 區塊 行程狀態 行程串列 就緒佇列. 行程描述器. 描述器用來描述系統元件,如行程描述器。 描述器就是對應到實作的程式碼中的某個結構。 行程描述器是個儲存在核心位址空間中的龐大結構。 - PowerPoint PPT Presentation

Citation preview

國立台灣大學資訊工程學系

作業系統

第七章 行程相關實作

資工系網媒所 NEWS實驗室

01:46 /432

第七章 行程相關實作

資料結構行程描述器行程狀態行程串列就緒佇列

行程運作行程間的溝通摘要

資工系網媒所 NEWS實驗室

01:46 /433

資料結構

以作業系統的觀點來看行程,一個行程控制區塊就代表一個行程。Linux 中與行程相關的資料結構

行程控制區塊行程狀態行程串列就緒佇列

資工系網媒所 NEWS實驗室

01:46 /434

行程描述器描述器用來描述系統元件,如行程描述器。描述器就是對應到實作的程式碼中的某個結構。行程描述器是個儲存在核心位址空間中的龐大結構。Linux 中行程描述器稱為 task_struct 。定義在 Linux 核心源碼的 include/linux/sched.h 中。

資工系網媒所 NEWS實驗室

01:46 /435

行程狀態

在 Linux 中,行程的狀態記錄在行程描述器中的 state 欄位:

#define TASK_RUNNING 0#define TASK_INTERRUPTIBLE 1#define TASK_UNINTERRUPTIBLE 2#define TASK_ZOMBIE 4#define TASK_STOPPED 8

volatile long state; /* -1 不可執行, 0 可執行, >0 被停止*/

資工系網媒所 NEWS實驗室

01:46 /436

行程狀態 ( 續 )

TASK_RUNNING :行程正在執行或是等待被執行時。TASK_INTERRUPTIBLE :等待某些事件發生時,如等待信號的傳遞。TASK_UNINTERRUPTIBLE :與TASK_INTERRUPTIBLE 一樣,不同的是信號傳遞時並不會造成狀態的改變。TASK_STOPPED :收到 SIGSTOP 、 SIGTSTP 、 SIGTTIN 或 SIGTTOU 信號時。TASK_ZOMBIE :當子行程結束時,父行程尚未呼叫類似 wait() 的系統呼叫來得知子行程的狀態並作適當處理,於是子行程就會處於這個狀態。

資工系網媒所 NEWS實驗室

01:46 /437

行程串列

Linux 使用鏈結串列將系統中所有的 PCB 串在一起。行程描述器中的 next_task 與 prev_task 這兩個欄位,就是鏈結串列的指標。

使用 for_each_task 巨集可以輕易地走訪整個行程串列。

struct task_struct *next_task, *prev_task;

資工系網媒所 NEWS實驗室

01:46 /438

Linux 的行程串列

prev_task prev_tasknext_taskprev_task next_task next_task

init_task

資工系網媒所 NEWS實驗室

01:46 /439

就緒佇列

在就緒佇列中的所有行程,其狀態皆為TASK_RUNNING 。行程描述器中實作就緒佇列的 run_list 欄位:

就緒佇列的開頭

struct list_head run_list;

static LIST_HEAD(runqueue_head);

資工系網媒所 NEWS實驗室

01:46 /4310

就緒佇列 ( 續 )

將一個行程加入就緒佇列:add_to_runqueue()

static inline void add_to_runqueue(struct task_struct * p){

list_add(&p->run_list, &runqueue_head);nr_running++;

}

資工系網媒所 NEWS實驗室

01:46 /4311

第七章 行程相關實作

資料結構行程運作

行程建立內文切換行程結束

行程間的溝通摘要

資工系網媒所 NEWS實驗室

01:46 /4312

行程運作

在多行程系統中,行程必須能夠動態地被建立與刪除。Linux 中行程如何

建立內文切換刪除

資工系網媒所 NEWS實驗室

01:46 /4313

行程建立與建立行程有關的系統呼叫

fork()

vfork()

clone()

fork() 複製一份與父行程相同的位址空間copy-on-write 技術

vfork() 允許父行程與子行程共用相同的位址空間

父行程呼叫 vfork() 後會被阻隔

資工系網媒所 NEWS實驗室

01:46 /4314

行程建立 ( 續 )

clone() 可以透過一些參數來設定父行程與子行程間可以共用那一些系統資源。在核心中 fork() 、 vfork() 與 clone() 系統呼叫皆會觸發 do_fork() 。以 vfork() 為例: asmlinkage int sys_vfork(struct pt_regs regs){

return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0);}

資工系網媒所 NEWS實驗室

01:46 /4315

行程建立 ( 續 )

do_fork() 函式執行的內容大致可以分成 6 個部分,分別為:

配置 task_struct 的空間。複製父行程 task_struct 中所有的欄位。改變子行程 task_struct 中不可繼承的欄位並作一些初始化的設定。根據 clone_flags 判斷要複製那些父行程資源,並且初始化子行程的核心堆疊。將子行程的 task_struct 加入系統的行程串列中。將子行程喚醒。

資工系網媒所 NEWS實驗室

01:46 /4316

內文切換

內文切換時,最重要的就是將行程執行時的 CPU 暫存器值保存下來。與硬體架構關係非常地密切,需要使用組合語言來輔助撰寫。Linux 中內文切換的工作是由 switch_to 這個巨集來執行。

資工系網媒所 NEWS實驗室

01:46 /4317

行程與 CPU 暫存器狀態的示意圖( 1 )

行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1d001d00

esp:0x1f002100

esp:0x1a00c100

0x1c100100

0x1c001100

0x1b00a100

行程 prev 的行程描述器

行程 next 的行程描述器

主記憶體

eip:0x1a00a000

eip:0x1b01c000

資工系網媒所 NEWS實驗室

01:46 /4318

行程與 CPU 暫存器狀態的示意圖( 2 )

esp:0x1a00c100行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1d001d00

esp:0x1d001d000x1c100100

0x1c001100

0x1b00a104

行程 prev 的行程描述器

行程 next 的行程描述器

eip:0x1b01c000

eip:0x1a00a000

主記憶體

資工系網媒所 NEWS實驗室

01:46 /4319

行程與 CPU 暫存器狀態的示意圖( 3 )

行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1a00c100

esp:0x1d001d00

esp:0x1a00c100

0x1c100100

0x1c001100

0x1b00a108

行程 prev 的行程描述器

行程 next 的行程描述器

eip:0x1b01c000

eip:0x1a00a000

主記憶體

資工系網媒所 NEWS實驗室

01:46 /4320

行程與 CPU 暫存器狀態的示意圖( 4 )

行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1a00c100

esp:0x1d001d00

esp:0x1a00c100

0x1c100100

0x1c001100

0x1b00a10c

行程 prev 的行程描述器

行程 next 的行程描述器

eip:0x1a00a000

eip:0x1d001d18

主記憶體

資工系網媒所 NEWS實驗室

01:46 /4321

行程與 CPU 暫存器狀態的示意圖( 5 )

行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1a00c100

esp:0x1d001d00

esp:0x1a00c100

0x1c100100

0x1c001100

行程 prev 的行程描述器

行程 next 的行程描述器

主記憶體eip:0x1a00a000

0x1a00a000

eip:0x1d001d18

資工系網媒所 NEWS實驗室

01:46 /4322

行程與 CPU 暫存器狀態的示意圖( 6 )

行程 next

行程 prev

stack

data

text

stack

data

text

ESP

ESI

EDI

EIP

CPU 暫存器

0x1a00c100

esp:0x1d001d00

esp:0x1a00c100

0x1c100100

0x1c001100

0x1a00a00c

行程 prev 的行程描述器

行程 next 的行程描述器

主記憶體eip:0x1a00a000

eip:0x1d001d18

資工系網媒所 NEWS實驗室

01:46 /4323

行程結束

大部分的行程結束是指行程執行完最後一個指令。需要將行程先前使用過的一些系統資源回收。正常的情況下,行程執行到最後一個指令時會觸發 exit() 系統呼叫。在核心中真正作處理的是 do_exit() 函式。

資工系網媒所 NEWS實驗室

01:46 /4324

行程結束 ( 續 )

do_exit() 函式會依序執行下列動作:將行程描述器中的 flag 欄位設為 PF_EXITING ,代表這個行程正在結束。分別移除號誌佇列與計時器佇列中該行程曾經插入的元素。將行程所用到的記憶體空間、開啟的檔案、檔案系統資源與信號佇列回收。將行程描述器中的 state 與 exit_code 欄位分別設為 TASK_ZOMBIE 與相應的返回值。 更新父行程與子行程間的相互關係。呼叫排程器 schedule() 選出下一個可以執行的行程。

資工系網媒所 NEWS實驗室

01:46 /4325

第七章 行程相關實作資料結構行程運作行程間的溝通旋轉鎖號誌訊息佇列

摘要

資工系網媒所 NEWS實驗室

01:46 /4326

行程間的溝通 Linux 提供了一些行程的通訊機制,讓行程間進行溝通:管道號誌訊息共享記憶體插口

Linux 核心中進行行程間的溝通時,為了保持重要核心資料結構的一致性,使用了一些同步機制,如:旋轉鎖號誌

資工系網媒所 NEWS實驗室

01:46 /4327

旋轉鎖

最基本的同步機制之一,它就像門鎖一樣,當門鎖鎖上後,其他人就不能再進入這個房間。在單處理器的環境下,有可能造成等待的行程一直忙碌等待,而將鎖鎖上的行程卻沒有機會進行內文切換,將鎖打開。 多處理器的環境下旋轉鎖相當有效率。

資工系網媒所 NEWS實驗室

01:46 /4328

旋轉鎖 ( 續 )

每個旋轉鎖以 spinlock_t 結構來代表,其中只有一個 lock 欄位:

lock 的值為 1 時,表示鎖是開著的。lock 的值小於等於 0 時,則表示鎖已被鎖上。

spin_lock() 將 spinlock_t 結構中的 lock 欄位值減 1 ,如果 lock 的值小於 0 ,則使用迴圈一直去測試 lock 欄位值是否等於 0 。spin_unlock() 將 lock 的欄位值設為 1 。當兩個行程同時讀取同一份資料時,使用旋轉鎖是比較沒有效率的:讀 / 寫的旋轉鎖。

資工系網媒所 NEWS實驗室

01:46 /4329

讀 / 寫旋轉鎖

臨界區

行程 A行程 AR

行程 B行程 BR

行程 C行程 CW

臨界區

行程 D行程 DW

行程 F行程 FR

行程 E行程 EW

R

W

:讀取用:寫入用

資工系網媒所 NEWS實驗室

01:46 /4330

號誌Linux 號誌可分為核心號誌與使用者號誌。Linux 核心號誌的型別為 struct semaphore 。struct semaphore 的欄位 count :

大於 0 時,代表現在可以使用此號誌。小於或等於 0 時,代表這個號誌現在正忙碌中。

使用或釋出信號:down() - 將號誌的 count 值減 1 。 up() - 將 count 值加 1 。

資工系網媒所 NEWS實驗室

01:46 /4331

訊息佇列使用者號誌、訊息與共用記憶體屬於 IPC 的範圍。 透過代號來使用 IPC 資源。semget() 、 msgget() 或 shmget() 分別取得信號、訊息或共用記憶體的 IPC 代號。Linux 中所有與 IPC 相關的函式都是透過 ipc() 系統呼叫來完成的。訊息佇列:

msgget() - 取得訊息佇列的代號。msgsnd() - 傳送訊息。msgrcv() - 接受訊息。

資工系網媒所 NEWS實驗室

01:46 /4332

訊息佇列 ( 續 )Linux IPC 訊息佇列的資料結構:

struct ipc_ids - 每一種 IPC 資源各自擁有一個 ipc_ids 結構,訊息佇列為 msg_ids 。struct msg_queue - 代表一個訊息佇列。struct msg_msg 、 struct msg_msgseg - struct msg_msg 用來代表一個訊息,每個訊息使用雙向鏈結串列連接在一起。訊息超過一個分頁( 4 KB)時,使用其它的 struct msg_msgseg 來儲存。struct msg_sender 、 struct msg_receiver - 用來代表正在等待的傳送端與接收端行程。

msgsnd() 在核心中是呼叫 sys_msgsnd() ,大致可分為三個部分,分別為:

初始化。檢查訊息佇列是否有空間存放訊息。檢查訊息佇列中的接收端行程串列是否有行程正等待訊息。

資工系網媒所 NEWS實驗室

01:46 /4333

IPC 訊息佇列的資料結構

m_listm_list

……

……

entries[]entries[]

……

q_messagesq_messages

q_sendersq_senders

q_receiversq_receivers

msg_queue

…… 77 … … …… … …

msg_ids

msg_msg

nextnext

m_listm_list

……

msg_msg

nextnext

msg_msgseg

listlist

tsktsk

nextnext

msg_sender

r_listr_list

r_tskr_tsk

……

r_msgr_msg

msg_receiver

資工系網媒所 NEWS實驗室

01:46 /4334

摘要 (1)

Linux 核心中的行程控制區塊是由一個 task_struct 結構來代表。Linux 核心中動態建立行程的系統呼叫

fork()

vfork()

clone()

Linux 核心中處理內文切換的巨集:switch_to

資工系網媒所 NEWS實驗室

01:46 /4335

摘要 (2)

Linux 核心中的同步機制旋轉鎖 / 讀寫旋轉鎖號誌

down() - 使用號誌。up() - 釋出號誌。

Linux 提供 IPC 機制,允許使用者空間的行程進行同步或相互溝通。Linux 核心中的訊息佇列

msgget() - 取得訊息佇列的代號。msgsnd() - 傳送訊息。 msgrcv() - 接受訊息。