首页 > 解决方案 > waitpid() 总是返回 '-1'

问题描述

我有一个任务是在 C 中制作类似 unix 的 shell。用户可以输入“procs”,它打印所有正在运行的进程,在执行这个函数之前,我必须使用函数“updateProcessList”,它遍历进程列表并在帮助下waitpid() 更新进程的状态。如果一个进程“新”终止,我必须从列表中删除这个进程(仍然没有实现它)。我遇到的问题是更新功能。每次调用 waitpid() 都会返回 -1,错误号为“10”,这意味着父进程下不存在给定 id 的子进程,这当然不是真的(这个子进程处于僵尸状态),甚至是正在运行的进程像“sleep 5 &”('&' 表示它是非阻塞的,因此父进程不会' t 被阻止)未找到。手册页很难理解,并且在这个特定部分中对作业的解释非常糟糕(到目前为止,我已经在手册页的帮助下自己完成了所有工作,但是对于这个我迷路了,花了已经几个小时了,我被困住了)。如果有人能查明我在这里缺少的东西,我会非常高兴。谢谢!

#include "LineParser.h"
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#define TERMINATED  -1
#define RUNNING 1
#define SUSPENDED 0
#define SIZE 2048
#define FORKED(x) (strcmp(x, "cd") != 0 && strcmp(x, "procs") != 0)
int debugMode = 0;

typedef struct process{
    cmdLine* cmd;                         /* the parsed command line*/
    pid_t pid;                        /* the process id that is running the command*/
    int status;                           /* status of the process: RUNNING/SUSPENDED/TERMINATED */
    struct process *next;                     /* next process in chain */
} process;

process **processList;


void updateProcessStatus(process* process_list, int pid, int status) {
    process* temp = process_list;
    while (temp != NULL) {
        if (temp -> pid == pid) {
            temp -> status = pid;
            return;
        }
        temp = temp -> next;
    }
}

void updateProcessList(process **process_list) {
    int status;
    process **curr = process_list;
    while ((*curr) !=  NULL) {
        pid_t statusChangedId = waitpid((*curr) -> pid, &status, WNOHANG | WUNTRACED | WCONTINUED);
        if (statusChangedId == -1) {
            perror("");
            printf("%d\n", errno);
            printf("%d\n", (*curr) -> pid);
        }
        if (statusChangedId > 0) {
            updateProcessStatus(*curr, statusChangedId, status);
        }
        curr = &((*curr) -> next);
    }
}


void addProcess(process** process_list, cmdLine* cmd, pid_t pid) {
    process **tail = process_list;
    while (*tail != NULL) {
        tail = &((*tail) -> next);
    }
    *tail = (process *) malloc(sizeof(process));
    (*tail) -> cmd = cmd;
    (*tail) -> pid = pid;
    (*tail) -> status = RUNNING;
    (*tail) -> next = NULL;
}


void printProcessList(process** process_list) {
    updateProcessList(process_list);
    process *curr = *process_list;
    while (curr != NULL) {
        printf("%-13s%-13s%s\n", "PID", "Command", "STATUS");
        printf("%-13d%-13s%s\n", curr -> pid, curr -> cmd -> arguments[0], 
                                                                        (curr -> status) == -1 ? "TERMINATED" :
                                                                        (curr -> status) == 0 ? "SUSPENDED" :
                                                                                                "RUNNING");
        curr = curr -> next;
    }
}


void execute(cmdLine *pCmdLine) {
    if (!FORKED(pCmdLine -> arguments[0])) {
        if (strcmp(pCmdLine -> arguments[0], "cd") == 0) {
            if (chdir(pCmdLine -> arguments[1]) < 0) {
                perror("");
                fprintf(stderr, "%d\n", errno);
            }
        }
        else if (strcmp(pCmdLine -> arguments[0], "procs") == 0) {
            printProcessList(processList);
        }
        free(pCmdLine);
    } 
    else {
        // if we're here, it means user input wasn't "cd" nor "procs"
        pid_t id = fork();
        if (id == -1) {
            fprintf(stderr, "fork() couldn't open child, terminating...");
            _exit(-1);
        }
        if (id != 0) {                                                  // this is the parent and it will be blocked if needed
            addProcess(processList, pCmdLine, id);
            if (pCmdLine -> blocking) {
                waitpid(id, NULL, 0);
            }
        }
        else {
            execvp(pCmdLine -> arguments[0], pCmdLine -> arguments);
            perror("Error ");                                           // returns here only if execv encounterd some error
            _exit(errno);
        }
    }
    //_exit(0);
    if (debugMode) {
        fprintf(stderr, "Process ID: %d\nExecuting command: %s\n", getpid(), pCmdLine -> arguments[0]);
    }
    // if (!FORKED(pCmdLine -> arguments[0]))
    //     freeCmdLines(pCmdLine);

}


int main(int argc, char **argv) {
    processList = (process **) malloc(4);
    char cmdBuffer[SIZE];
    char cwdName[PATH_MAX];

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-d") == 0) {
            debugMode = 1;
        }
    }
    getcwd(cwdName, PATH_MAX);
    printf("%s\n", cwdName);
    while (fgets(cmdBuffer, SIZE, stdin) != NULL) {
        if (strncmp(cmdBuffer, "quit", 4) == 0) {
            break;
        }
        cmdLine* currCmd = parseCmdLines(cmdBuffer);
        execute(currCmd);
    }

    freeProcessList(*processList);
    return 0;
}

标签: clinuxshellforkwaitpid

解决方案


推荐阅读