waitid() - 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 的值是以下常量的或運算結果,可以為零個或多個
|
標籤 | 描述 |
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() 時指定的status引數的最低有效 16-8 位,或作為 main() 中 return 語句的引數。只有在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中對以下一個或多個標誌進行或運算來指定 |
WEXITED | 等待已終止的子程序。 |
WSTOPPED | 等待已被訊號停止的子程序。 |
WCONTINUED | 等待(先前已停止的)已透過傳遞SIGCONT恢復的子程序。 |
此外,可以在options中對以下標誌進行或運算 |
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():成功時返回 0,或者如果指定了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、終止狀態、資源使用資訊),以便父程序稍後執行 wait 以獲取有關子程序的資訊。
只要殭屍程序沒有透過 wait 從系統中刪除,它就會消耗核心程序表中的一個槽,如果此表填滿,則將無法建立更多程序。如果父程序終止,則其“殭屍”子程序(如果有)將由init(8) 採用,後者會自動執行 wait 以刪除殭屍程序。
POSIX.1-2001 規定,如果將SIGCHLD的處理方式設定為SIG_IGN,或者為SIGCHLD設定了SA_NOCLDWAIT標誌(參見sigaction(2)),那麼終止的子程序不會變成殭屍程序,而對wait() 或waitpid() 的呼叫將阻塞,直到所有子程序都終止,然後失敗並設定errno為ECHILD。(最初的 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。
另請參見
廣告
|