[英]Not able to get waitpid() to return correct WEXITSTATUS for error condition
我有一個命令和一些輸入,在命令行上運行時將返回錯誤,並且相關錯誤代碼為1:
$ foo bar
[some useful error message...]
$ echo $?
1
我正在嘗試使用waitpid()
捕獲此錯誤代碼:
...
char *proc_cmd = "foo bar"
pid_t proc = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE);
...
if (waitpid(proc, &global_foo_status, WNOHANG | WUNTRACED) == -1) {
/* process failed */
}
...
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data);
pthread_join(proc_thread, (void **) NULL);
...
我的線程將運行perform_foo_function()
直到沒有更多的bar_data
要處理,或者直到該處理由於數據錯誤而失敗為止:
static void * perform_foo_function (data *bar_data) {
/* check before */
if (WIFEXITED(global_foo_status)) {
int exit_status = WEXITSTATUS(global_foo_status);
if (exit_status != 0)
/* process failed */
}
/* do stuff with bar_data */
while (bar_data) {
/* causes error ... */
}
/* check after */
if (WIFEXITED(global_foo_status)) {
int exit_status = WEXITSTATUS(global_foo_status);
if (exit_status != 0)
/* process failed */
}
pthread_exit(NULL);
}
我的問題是如何捕獲此過程的錯誤狀態? 在調試過程中,無論我故意創建錯誤情況還是提供合法輸入, WEXITSTATUS
始終為零。
我對waitpid()
和相關的狀態代碼檢查有什么誤解,應該進行哪些更改才能使它起作用?
跟進
以下代碼似乎可以正常工作,而不會阻塞:
...
char *proc_cmd = "foo bar"
pid_t global_foo_pid = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE);
...
if (waitpid(global_foo_pid, &global_foo_status, WNOHANG | WUNTRACED) == -1) {
/* process failed */
}
...
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data);
pthread_join(proc_thread, (void **) NULL);
...
static void * perform_foo_function (data *bar_data)
{
/* do stuff with bar_data */
while (bar_data) {
/* causes error ... */
}
/* check after */
if (WIFEXITED(global_foo_status)) {
waitpid(global_foo_pid, &global_foo_status, WUNTRACED);
int exit_status = WEXITSTATUS(global_foo_status);
if (exit_status != 0)
/* process failed */
}
pthread_exit(NULL);
}
我猜想“ waitpid()
之后的檢查”調用不會掛起,因為該進程已在此步驟中退出。
這里有幾件事。
首先,您的global_foo_status
變量將在調用waitpid()
或好友之后且僅在調用之后更新。 在提供的代碼中,在創建線程之前,只調用一次waitpid()
。 因此,您正在使用的所有WIFEXITED
和WEXITSTATUS
宏都在與您對waitpid()
初始調用中獲得的global_foo_status
值相同。 這幾乎可以肯定是為什么在調試時始終看到零值的原因,因為在進程終止后您永遠都不會獲得更新的值,而您只是反復檢查該初始值。 如果要檢查進程是否退出,則每次都必須再次調用waitpid()
。
其次,如果進程正常終止,則WIFEXITED
評估為true,但這不是進程可以終止的唯一方法。 還有另一個宏WIFSIGNALED
,如果該過程由於接收到信號而終止,則將評估為true。 如果您僅使用WIFEXITED
來檢查終止,並且您的進程被信號異常終止,那么您將永遠無法成功檢查。 更好的方法是使用waitpid()
的返回值來確定進程是否由於某種原因而終止。
您的函數應該看起來像這樣:
static void * perform_foo_function (data *bar_data) {
/* check before */
pid_t status = waitpid(global_foo_pid, &global_foo_status, WNOHANG);
if ( status == -1 ) {
perror("error calling waitpid()");
exit(EXIT_FAILURE);
}
else if ( status == global_foo_pid ) {
/* Process terminated */
if ( WIFEXITED(global_foo_status) ) {
/* Process terminated normally */
int exit_status = WEXITSTATUS(global_foo_status);
if ( exit_status ) {
/* Process failed */
return NULL;
}
else {
/* Process terminated normally and successfully */
return NULL;
}
}
else {
/* Process terminated abnormally */
return NULL;
}
}
/* Process is still running if we got here */
/* do stuff with bar_data */
while (bar_data) {
/* causes error ... */
}
/* Check after - if getting an error from doing stuff
with bar_data implies the process should always
shortly terminate, then you probably don't want
WNOHANG in the following line. */
status = waitpid(global_foo_pid, &global_foo_status, WNOHANG);
if ( status == -1 ) {
perror("error calling waitpid()");
exit(EXIT_FAILURE);
}
else if ( status == global_foo_pid ) {
/* Process terminated */
if ( WIFEXITED(global_foo_status) ) {
/* Process terminated normally */
int exit_status = WEXITSTATUS(global_foo_status);
if ( exit_status ) {
/* Process failed */
return NULL;
}
else {
/* Process terminated normally and successfully */
return NULL;
}
}
else {
/* Process terminated abnormally */
return NULL;
}
}
pthread_exit(NULL);
}
整個過程檢查也是將其分解為單獨功能的主要候選對象。
如果您有多個線程同時運行perform_foo_function()
,則waitpid()
將僅在其中一個中適當地返回。 您可能需要一個單獨的變量global_foo_has_finished
或類似變量,線程可以在嘗試調用waitpid()
之前進行檢查。 您還希望同步對所有這些全局變量的訪問,或者重新設計它們,因此它們是不必要的(例如,您可以將global_foo_pid
直接傳遞到線程函數中,並且global_foo_status
不必是全局變量,因為它從未在其他任何地方訪問過) )。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.