Linux 程序建立

2021-05-22 09:14:29 字數 3136 閱讀 7399

華清遠見嵌入式學院

上海分中心講師。

在 linux 核心內,程序是由相當大的乙個稱為 task_struct 的結構表示的。此結構包含所有表示此程序所必需的資料,此外,還包含了大量的其他資料用來統計(accounting)和維護與其他程序的關係(父和子)。下面給出了 task_struct 的一小部分。task_struct 位於 ./linux/include/linux/sched.h。

struct task_struct ;

在task_struct中,可以看到幾個預料之中的項,比如執行的狀態、堆疊、一組標誌、父程序、執行的執行緒(可以有很多)以及開放檔案。對其做簡單宣告如下

<1> state 變數是一些表明任務狀態的位元位。最常見的狀態有:

1.task_running 表示程序正在執行,或是排在執行佇列中正要執行

2.task_interruptible 表示程序正在休眠

3.task_uninterruptible 表示程序正在休眠但不能叫醒

4.task_stopped 表示程序停止

注:這些標誌的完整列表可以在 ./linux/include/linux/sched.h 內找到。

<2> flags 定義了很多指示符,表明程序是否正在被建立(pf_starting)或退出(pf_exiting),或是程序當前是否在分配記憶體(pf_memalloc)。

<3> 每個程序都會被賦予優先順序(稱為 static_prio),但程序的實際優先順序是基於載入以及其他幾個因素動態決定的。優先順序值越低,實際的優先順序越高。

<5> 程序的位址空間由 mm 和 active_mm 字段表示。mm 代表的是程序的記憶體描述符,而 active_mm 則是前乙個程序的記憶體描述符(為改進上下文切換時間的一種優化)。

<6> 可執行程式的名稱(不包含路徑)占用 comm(命令)字段。

<7> thread_struct 則用來標識程序的儲存狀態。此元素依賴於 linux 在其上執行的特定架構,在 ./linux/include/asm-i386/processor.h 內有這樣的乙個例子。在此結構內,可以找到該程序自執行上下文切換後的儲存(硬體登錄檔、程式計數器等)。

在很多情況下,程序都是動態建立並由乙個動態分配的 task_struct 表示。當然 init 程序例外,它總是存在並由乙個靜態分配的 task_struct 表示。

linux 內所有程序的分配有兩種方式。第一種方式是通過乙個雜湊表,由 pid 值進行雜湊計算得到;第二種方式是通過雙鏈迴圈表。迴圈表非常適合於對任務列表進行迭代。由於列表是迴圈的,沒有頭或尾;但是由於 init_task 總是存在,所以可以將其用作繼續向前迭代的乙個錨點。

任務列表無法從使用者空間訪問,但該問題很容易解決,方法是以模組形式向核心內插入**。例如通過如下**,它會迭代任務列表並會提供有關每個任務的少量資訊(name、pid 和 parent 名)。

struct task_struct *task = &init_task;

/* walk through the task list, until we hit the init_task again */

do while ( (task = next_task(task)) != &init_task );

注意,還可以標識當前正在執行的任務。linux 維護乙個稱為 current 的符號,代表的是當前執行的程序(型別是 task_struct)。為此可使用如下**:

printk( kern_info, "current task is %s [%d]」, current->comm, current->pid );

linux建立使用者空間程序的情況與核心空間程序類似。二者底層機制是一致的,因為最終都會依賴於乙個名為 do_fork 的函式來建立新程序。

在建立核心執行緒時,核心會呼叫乙個名為 kernel_thread 的函式(參見 ./linux/arch/i386/kernel/process.c),此函式執行某些初始化後會呼叫 do_fork。

在使用者空間,乙個程式會呼叫 fork,這會導致對名為 sys_fork 的核心函式的系統呼叫(參見 ./linux/arch/i386/kernel/process.c)。

do_fork 是程序建立的基礎。可以在 ./linux/kernel/fork.c 內找到 do_fork 函式(以及相關函式 copy_process)。

do_fork 函式首先呼叫 alloc_pidmap,該呼叫會分配乙個新的 pid。接下來,do_fork 檢查偵錯程式是否在跟蹤父程序。如果是,在 clone_flags 內設定 clone_ptrace 標誌以做好執行 fork 操作的準備。之後 do_fork 函式還會呼叫 copy_process,向其傳遞這些標誌、堆疊、登錄檔、父程序以及最新分配的 pid。

新的程序在 copy_process 函式內作為父程序的乙個副本建立。此函式能執行除啟動程序之外的所有操作,啟動程序在之後進行處理。copy_process 內的第一步是驗證 clone 標誌以確保這些標誌是一致的。如果不一致,就會返回 einval 錯誤。接下來,詢問 linux security module (lsm) 看當前任務是否可以建立乙個新任務。

接下來,呼叫 dup_task_struct 函式(./linux/kernel/fork.c ),這會分配乙個新 task_struct 並將當前程序的描述符複製到其內。在新的執行緒堆疊設定好後,一些狀態資訊也會被初始化,並且會將控制返回給 copy_process。控制回到 copy_process 後,除了其他幾個限制和安全檢查之外,還會執行一些常規管理,包括在新 task_struct 上的各種初始化。之後,會呼叫一系列複製函式來複製此程序的各個方面,比如複製開放檔案描述符(copy_files)、複製符號資訊(copy_sighand 和 copy_signal)、複製程序記憶體(copy_mm)以及最終複製執行緒(copy_thread)。

之後,這個新任務會被指定給乙個處理程式,同時對允許執行程序的處理程式進行額外的檢查(cpus_allowed)。新程序的優先順序從父程序的優先順序繼承後,執行一小部分額外的常規管理,而且控制也會被返回給 do_fork。在此時,新程序存在但尚未執行。do_fork 函式通過呼叫 wake_up_new_task 來修復此問題。此函式(./linux/kernel/sched.c )初始化某些排程程式的常規管理資訊,將新程序放置在執行佇列之內,然後將其喚醒以便執行。最後,一旦返回至 do_fork,此 pid 值即被返回給呼叫程式,程序完成。

Linux 程序建立

1 linux建立程序的方式是先通過呼叫fork建立乙個和呼叫程序基本一樣的子程序,二者之間的區別在於pid和ppid不同。然後子程序呼叫exec函式裝載乙個新的程序到位址空間執行。其他的作業系統產生子程序的方式是spawn 在新的位址空間中建立程序,然後載入可執行檔案執行。2 傳統的fork是將所...

Linux程序 程序的建立

今天學習了linux的程序建立的基本原理,是基於0.11版本核心的。下面對其作一下簡單的總結。一 linux程序在記憶體中的相關資源 很容易理解,linux程序的建立過程就是記憶體中程序相關資源產生的過程,那麼linux程序在記憶體中有哪些相關資源呢?1 task陣列中的一項 乙個指標指向程序的ta...

Linux 程序建立 程序終止

程序終止 fork 在linux中fork函式時非常重要的函式,它從已存在程序中建立乙個新程序。新程序為子程序,而原程序為父程序。include pid t fork void 返回值 自程序中返回0,父程序返回子程序id,出錯返回 1子程序複製父程序的pcb,因此複製了父程序的程式計數器,所以和父...