waitpid() - Unix,Linux 系統呼叫
廣告
名稱
wait, waitpid - 等待程序狀態改變
語法
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t * infop , int options );
|
描述
所有這些系統呼叫都用於等待呼叫程序子程序的狀態變化,並獲取有關狀態已更改的子程序的資訊。狀態更改被認為是:子程序終止;子程序被訊號停止;或子程序被訊號恢復。對於終止的子程序,執行 wait 允許系統釋放與子程序關聯的資源;如果沒有執行 wait,則終止的子程序將保持“殭屍”狀態(請參見下面的註釋)。
如果子程序已經更改狀態,則這些呼叫立即返回。否則,它們將阻塞,直到子程序更改狀態或訊號處理程式中斷呼叫(假設系統呼叫不會使用 **sigaction**(2) 的 **SA_RESTART** 標誌自動重新啟動)。在本頁的其餘部分,狀態已更改且尚未由這些系統呼叫之一等待的子程序稱為 *可等待的*。
wait() 和 waitpid()
**wait**() 系統呼叫掛起當前程序的執行,直到其一個子程序終止。呼叫 *wait(&status)* 等效於
**waitpid**() 系統呼叫掛起當前程序的執行,直到由 *pid* 引數指定的子程序更改狀態。預設情況下,**waitpid**() 僅等待終止的子程序,但此行為可以透過 *options* 引數進行修改,如下所述。
*pid* 的值可以是
| 標籤 | 描述 |
| < -1 | 表示等待任何程序組 ID 等於 *pid* 的絕對值的子程序。 |
| -1 | 表示等待任何子程序。 |
| 0 | 表示等待任何程序組 ID 等於呼叫程序的程序組 ID 的子程序。 |
| > 0 | 表示等待程序 ID 等於 *pid* 值的子程序。 |
*options* 的值是以下常量之一或多個的 OR
|
|
| 標籤 | 描述 |
|
WNOHANG | 如果沒有任何子程序退出,則立即返回。 |
| WUNTRACED | 如果子程序已停止(但未透過 **ptrace**(2) 跟蹤),則也返回。即使未指定此選項,也會提供已停止的 *跟蹤* 子程序的狀態。 |
| WCONTINUED | (自 Linux 2.6.10 起)如果已停止的子程序已透過傳遞 **SIGCONT** 恢復,則也返回。 |
|
(對於僅限 Linux 的選項,請參見下文。)僅當 **SIGCHLD** 訊號未設定 **SA_NOCLDSTOP** 標誌時,**WUNTRACED** 和 **WCONTINUED** 選項才有效(請參見 **sigaction**(2))。
如果 *status* 不為 NULL,**wait**() 和 **waitpid**() 會將狀態資訊儲存到它指向的 *int* 中。可以使用以下宏檢查此整數(這些宏將整數本身作為引數,而不是指向它的指標,就像在 **wait**() 和 **waitpid**() 中一樣!)
| 標籤 | 描述 |
| **WIFEXITED(**status**) | 如果子程序正常終止,則返回 true,即透過呼叫 **exit**(3) 或 **_exit**(2),或從 main() 返回。 |
| **WEXITSTATUS(**status**) | 返回子程序的退出狀態。它由子程序在呼叫 **exit**() 或 **_exit**() 或作為 main() 中 return 語句的引數時指定的 *status* 引數的最低有效 16-8 位組成。只有當 **WIFEXITED** 返回 true 時,才應使用此宏。 |
|
**WIFSIGNALED(**status**) | 如果子程序被訊號終止,則返回 true。 |
|
**WTERMSIG(**status**) | 返回導致子程序終止的訊號編號。只有當 **WIFSIGNALED** 返回 true 時,才應使用此宏。 |
|
**WCOREDUMP(**status**) | 如果子程序生成了核心轉儲,則返回 true。只有當 **WIFSIGNALED** 返回 true 時,才應使用此宏。此宏未在 POSIX.1-2001 中指定,並且在某些 Unix 實現(例如 AIX、SunOS)上不可用。僅在 #ifdef WCOREDUMP ... #endif 中使用它。 |
|
**WIFSTOPPED(**status**) | 如果子程序因訊號傳遞而停止,則返回 true;這隻有在使用 **WUNTRACED** 或子程序正在被跟蹤(請參見 **ptrace**(2))時才有可能。 |
|
**WSTOPSIG(**status**) | 返回導致子程序停止的訊號編號。只有當 **WIFSTOPPED** 返回 true 時,才應使用此宏。 |
|
**WIFCONTINUED(**status**) | (自 Linux 2.6.10 起)如果子程序已透過傳遞 **SIGCONT** 恢復,則返回 true。 |
waitid()
**waitid**() 系統呼叫(自 Linux 2.6.9 起可用)提供了對要等待哪些子程序狀態更改的更精確的控制。
*idtype* 和 *id* 引數選擇要等待的子程序,如下所示
| 標籤 | 描述 |
|
*idtype* == **P_PID** | 等待程序 ID 與 *id* 匹配的子程序。 |
|
*idtype* == **P_PGID** | 等待任何程序組 ID 與 *id* 匹配的子程序。 |
|
*idtype* == **P_ALL** | 等待任何子程序;*id* 被忽略。 |
| 要等待的子程序狀態更改透過在 *options* 中對以下標誌之一或多個進行 OR 來指定 |
|
WEXITED | 等待已終止的子程序。 |
|
WSTOPPED | 等待因訊號傳遞而停止的子程序。 |
|
WCONTINUED | 等待(先前已停止的)已透過傳遞 **SIGCONT** 恢復的子程序。 |
| 以下標誌還可以與 *options* 進行 OR 運算 |
|
WNOHANG | 與 **waitpid**() 相同。 |
|
WNOWAIT | 使子程序保持可等待狀態;以後的 wait 呼叫可用於再次檢索子程序狀態資訊。 |
| 成功返回後,**waitid**() 將填充 *infop* 指向的 **siginfo_t** 結構的以下欄位 |
|
si_pid
| 子程序的程序 ID。 |
|
si_uid
| 子程序的真實使用者 ID。(此欄位在大多數其他實現中未設定。) |
|
si_signo
| 始終設定為 **SIGCHLD**。 |
|
si_status
| 子程序的退出狀態,如傳遞給 **_exit**(2)(或 **exit**(3)),或導致子程序終止、停止或繼續的訊號。 *si_code* 欄位可用於確定如何解釋此欄位。 |
|
si_code
| 設定為以下之一:**CLD_EXITED**(子程序呼叫 **_exit**(2));**CLD_KILLED**(子程序被訊號殺死);**CLD_STOPPED**(子程序被訊號停止);或 **CLD_CONTINUED**(子程序被 **SIGCONT** 繼續)。 |
如果在 *options* 中指定了 **WNOHANG** 並且沒有任何子程序處於可等待狀態,則 **waitid**() 將立即返回 0,並且 *infop* 指向的 **siginfo_t** 結構的狀態未定義。為了區分這種情況與子程序處於可等待狀態的情況,在呼叫之前將 *si_pid* 欄位清零,並在呼叫返回後檢查此欄位中的非零值。
返回值
**wait**():成功時,返回終止的子程序的程序 ID;錯誤時,返回 -1。
**waitpid**():成功時,返回狀態已更改的子程序的程序 ID;錯誤時,返回 -1;如果指定了 **WNOHANG** 並且 *pid* 指定的子程序尚未更改狀態,則返回 0。
**waitid**():成功時或如果指定了 **WNOHANG** 並且 *id* 指定的子程序尚未更改狀態時返回 0;錯誤時返回 -1。
在發生錯誤的情況下,這些呼叫中的每一個都會將 *errno* 設定為適當的值。
錯誤
| 標籤 | 描述 |
|
ECHILD | (對於 **wait**())呼叫程序沒有任何未等待的子程序。 |
|
ECHILD | (對於 **waitpid**() 或 **waitid**())由 *pid*(**waitpid**())或 *idtype* 和 *id*(**waitid**())指定的程序不存在或不是呼叫程序的子程序。(如果 SIGCHLD 的操作設定為 SIG_IGN,則對於自己的子程序也可能發生這種情況。另請參見關於執行緒的 LINUX 註釋部分。) |
|
EINTR |
未設定 **WNOHANG**,並且捕獲了未阻塞的訊號或 **SIGCHLD**。 |
|
EINVAL | *options* 引數無效。 |
註釋
如果一個子程序終止,但父程序尚未對其執行等待操作,則該子程序將成為一個“殭屍”程序。核心會維護關於殭屍程序的一組最小資訊(PID、終止狀態、資源使用資訊),以便父程序稍後執行等待操作以獲取有關子程序的資訊。
只要殭屍程序沒有透過等待操作從系統中移除,它就會佔用核心程序表中的一個槽位,如果該表填滿,則將無法建立更多程序。如果父程序終止,則其“殭屍”子程序(如果有)將由**init**(8) 採用,**init**(8) 會自動執行等待操作以移除殭屍程序。
POSIX.1-2001 規定,如果**SIGCHLD** 的處理方式設定為**SIG_IGN** 或為**SIGCHLD** 設定了**SA_NOCLDWAIT** 標誌(參見**sigaction**(2)),則終止的子程序不會變成殭屍程序,並且對**wait**() 或**waitpid**() 的呼叫將阻塞,直到所有子程序都終止,然後以**ECHILD** 設定的*errno* 失敗。(原始 POSIX 標準未指定將**SIGCHLD** 設定為**SIG_IGN** 的行為。)Linux 2.6 符合此規範。但是,Linux 2.4(及更早版本)不符合:如果在忽略**SIGCHLD** 時進行**wait**() 或**waitpid**() 呼叫,則該呼叫的行為就像沒有忽略**SIGCHLD** 一樣,也就是說,該呼叫會阻塞,直到下一個子程序終止,然後返回該子程序的程序 ID 和狀態。
LINUX 註釋
在 Linux 核心中,核心排程執行緒與程序不是一個獨立的構造。相反,執行緒只是一個使用 Linux 獨有的**clone**(2) 系統呼叫建立的程序;其他例程(例如可移植的**pthread_create**(3) 呼叫)使用**clone**(2) 實現。 在 Linux 2.4 之前,執行緒只是程序的一種特殊情況,因此一個執行緒不能等待另一個執行緒的子程序,即使後者屬於同一個執行緒組。但是,POSIX 規定了這樣的功能,並且從 Linux 2.4 開始,執行緒可以並且預設情況下會等待同一執行緒組中其他執行緒的子程序。
以下 Linux 特定的*選項*用於使用**clone**(2) 建立的子程序;它們不能與**waitid**() 一起使用。
| 標籤 | 描述 |
|
__WCLONE | 僅等待“clone”子程序。如果省略,則僅等待“非 clone”子程序。(“clone”子程序是在終止時不會向其父程序傳遞任何訊號或除**SIGCHLD** 之外的訊號的子程序。)如果也指定了**__WALL**,則忽略此選項。 |
|
__WALL | (自 Linux 2.4 起)等待所有子程序,無論型別(“clone”或“非 clone”)。 |
|
__WNOTHREAD | (自 Linux 2.4 起)不等待同一執行緒組中其他執行緒的子程序。這是 Linux 2.4 之前的預設設定。 |
示例
以下程式演示了**fork**(2) 和**waitpid**(2) 的用法。該程式建立一個子程序。如果未向程式提供命令列引數,則子程序使用**pause**(2) 掛起其執行,以允許使用者向子程序傳送訊號。否則,如果提供命令列引數,則子程序立即退出,使用命令列上提供的整數作為退出狀態。父程序執行一個迴圈,使用**waitpid**(2) 監視子程序,並使用上面描述的 W*() 宏分析等待狀態值。
以下 shell 會話演示了程式的用法。
$ ./a.out &
Child PID is 32360
[1] 32359
$ kill -STOP 32360
stopped by signal 19
$ kill -CONT 32360
continued
$ kill -TERM 32360
killed by signal 15
[1]+ Done ./a.out
$
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); }
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
|
符合標準
SVr4、4.3BSD、POSIX.1-2001。
參見
廣告
|