作用 和會話期 程序組 第五十四期 程序的結束

2021-10-14 15:54:31 字數 4073 閱讀 7611

在之間的章節我們了解了程序的建立和執行,在程序執行完畢或者發生一些意料之外的事之後難免會被結束,因此linux提供了exit()的系統呼叫來完成程序結束以及釋放占用資源的功能。其中有兩種系統呼叫能用來完成結束程序或者執行緒的功能。

sys_exit()可以用來結束單個程序或執行緒,sys_exit_group()可以用來結束乙個執行緒組,均需要傳入乙個錯誤碼(error_code)來執行。 宣告如下:(路徑:/kernel-4.19/includelinuxsyscalls.h)

asmlinkage long sys_exit(int error_code);

asmlinkage long sys_exit_group(int error_code);

實現如下:(路徑:/kernel-4.19/kernel/exit.c)

syscall_define1(exit, int, error_code)

...syscall_define1(exit_group, int, error_code)

從以上可以看出,系統呼叫sys_exit()是呼叫了do_exit()函式,系統呼叫sys_exit_group()是呼叫了do_group_exit()函式。

接下來再分別看看do_exit()以及do_group_exit()函式的實現過程。

do_exit()的作用是結束當前的程序,部分**如下[1]:(路徑:/kernel-4.19/kernel/exit.c)

void __noreturn do_exit(long code)

//如果此pf_exiting標識未被設定, 則通過exit_signals來設定

exit_signals(tsk); /* sets pf_exiting */

/*記憶體屏障,用於確保在它之後的操作開始執行之前,它之前的操作已經完成*/

smp_mb();

/* 一直等待,直到獲得current->pi_lock自旋鎖 */

raw_spin_lock_irq(&tsk->pi_lock);

raw_spin_unlock_irq(&tsk->pi_lock);

.../* 釋放線性區描述符和頁表 */

exit_mm();

/* 輸出程序審計資訊 */

if (group_dead)

acct_process();

trace_sched_process_exit(tsk);

/* 釋放使用者空間的「訊號量」 */

exit_sem(tsk);

/* 釋放鎖 */

exit_shm(tsk);

/* 釋放檔案物件相關資源 */

exit_files(tsk);

exit_fs(tsk);

/* 脫離控制終端 */

if (group_dead)

disassociate_ctty(1);

/* 釋放命名空間 */

exit_task_namespaces(tsk);

exit_task_work(tsk);

/* 釋放task_struct中的thread_struct結構 */

.../* 更新所有子程序的父程序 */

exit_notify(tsk, group_dead);

/* 程序事件聯結器(通過它來報告程序fork、exec、exit以及程序使用者id與組id的變化) */

proc_exit_connector(tsk);

mpol_put_task_policy(tsk);

.../* 釋放struct io_context結構體所占用的記憶體 */

if (tsk->io_context)

exit_io_context(tsk);

/* 釋放與程序描述符splice_pipe欄位相關的資源 */

if (tsk->splice_pipe)

free_pipe_info(tsk->splice_pipe);

.../* 檢查有多少未使用的程序核心棧 */

check_stack_usage();

...do_task_dead();

}

在最後的do_task_dead()中呼叫了__schedule()切換到了其他就緒程序,至此該程序在作業系統中的生命週期就完全結束了。

我們如果了解linux的執行緒實現機制的話,會知道所有的執行緒是屬於乙個執行緒組的。即使不是執行緒, linux也允許多個程序組成程序組,多個程序組組成乙個會話,因此我們了解到不管是多執行緒還是程序組,其本質都是多個程序組成的乙個集合,那麼我們的應用程式在退出的時候,自然希望一次性的退出組內所有的程序,do_group_exit()也就應運而生了[2]。

do_group_exit()函式將會殺死屬於當前執行緒組的所有執行緒,它具體執行的是下述操作[2]:

檢查當前程序的signal_group_exit標誌是否不為0,如果不為0,說明核心已經開始為線性組執行退出的過程。在這種情況下,就把存放在current->signal->group_exit_code的值當作退出碼,然後跳轉到第4步。

否則,設定程序的signal_group_exit標誌並把終止代號放到current->signal->group_exit_code字段。

呼叫zap_other_threads()函式殺死current執行緒組中的其它程序。為了完成這個步驟,函式掃瞄與current->tgid對應的pidtype_tgid型別的雜湊表中的pid鍊錶,向表中所有不同於current的程序傳送sigkill訊號,所有這樣的程序都將執行do_exit()函式,從而被結束。

呼叫do_exit()函式,把程序的終止**傳遞給它。正如我們將在之前看到的,do_exit()結束程序而且不再返回。

do_group_exit()的部分**如下:(路徑:/kernel-4.19/kernel/exit.c)

void do_group_exit(int exit_code)

spin_unlock_irq(&sighand->siglock);

}/* 呼叫do_exit() */

do_exit(exit_code);

}

在上述的函式中,清除了當前程序所占用或者與它相關的資料結構,最後執行的一步都將是schedule()函式,在這個函式中就將跳轉到其他的程序。由於當前程序的各種相關的資料結構都不再存在,因此永遠也不會再跳轉到這個程序來執行,也就是程序被永遠宣告了死亡。

在本章我們了解了程序結束的過程,分別學習了do_exit()do_group_exit()函式,簡而言之,他們的作用都是清除關於程序或程序組所佔據的資源並開啟排程。關於程序的生命週期(建立、執行、結束)的講解到這裡就告一段落,在下一章我們將開始對程序位址空間的學習。

參考:

[1]

[3]《深入linux核心架構》

作用 和會話期 程序組 程序組和會話

程序組 程序組是指乙個或多個程序的集合。通常與乙個作業相關聯,可以接收來自同一終端的訊號。每個程序組有乙個唯一的程序組id,它類似於程序id,是乙個正整數 其實就是組長程序的程序id 可以通過函式獲得 include pid t getpgrp void 程序組都有乙個組長,組長程序的標識是其程序組...

Linux程序組和會話

linux的程序相互之間有一定的關係。比如說,在linux程序基礎中,我們看到,每個程序都有父程序,而所有的程序以init程序為根,形成乙個樹狀結構。我們在這裡講解程序組和會話,以便以更加豐富的方式了管理程序。每個程序都會屬於乙個程序組 process group 每個程序組中可以包含多個程序。程序...

程式設計訓練第五十期 合併區間

以陣列 intervals 表示若干個區間的集合,其中單個區間為 intervals i starti,endi 請你合併所有重疊的區間,並返回乙個不重疊的區間陣列,該陣列需恰好覆蓋輸入中的所有區間。1.排序 雙指標 如果我們按照區間的左端點排序,那麼在排完序的列表中,可以合併的區間一定是連續的。我...