бесконечный цикл при использовании execvp и fork в цикле while - PullRequest
1 голос
/ 20 апреля 2019

Я пытаюсь написать небольшую программу оболочки и хочу, чтобы она оставалась активной после вызова другой программы (через execvp()). Я хочу, чтобы системный вызов fork «продублировал» процесс, создав почти идентичную копию (дочернюю) исходящего (родительского) процесса. Поэтому, когда родитель завершает работу из-за вызова excevp(), дети будут еще живы.

В коде, который я прикрепил ниже, я читаю пользовательский ввод (программу и аргументы для выполнения), а затем ожидаю, что родительский форк выполнит программу, а дочерний форк будет ждать следующего ввода пользователя, но после при первом вводе ввода (программа для выполнения и ее аргументы) программа застревает в бесконечном цикле. Когда дочерняя вилка получает контроль, она выполняет предыдущую программу и не ждет нового ввода (похоже, что после первого fgets() она больше не ждет ввода пользователя).

Вот проблемная часть кода:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "LineParser.h"
#include <limits.h>
#include <unistd.h>

char buf[PATH_MAX];
char buf_user[2048];
int pid;

void execute(cmdLine* pCmdLine) {
   int pid = fork();
   if(pid != 0) {
     printf("I'm the parent.\n");
       if(execvp(pCmdLine->arguments[0], pCmdLine->arguments) == -1) {
         perror("execute failed");
         _exit(1);
       }
   } else {
     freeCmdLines(pCmdLine);        
   }
}

int main(int argc, char *argv[])
{  
    while(1) {
        getcwd(buf, PATH_MAX);
        printf("%s> ", buf);
        fgets(buf_user, 2048, stdin);
        fflush(stdin);
        if(strcmp(buf_user, "quit\n") == 0) {
            exit(0);
        }
        cmdLine* parsedCmd = parseCmdLines(buf_user);
        execute(parsedCmd);
    }
    return 0;
}

cmdLine структура:

#define MAX_ARGUMENTS 256

typedef struct cmdLine
{
    char *const arguments[MAX_ARGUMENTS]; /* command line arguments (arg 0 is the command) */
    int argCount;       /* number of arguments */
    char const *inputRedirect;  /* input redirection path. NULL if no input redirection */
    char const *outputRedirect; /* output redirection path. NULL if no output redirection */
    char blocking;  /* boolean indicating blocking/non-blocking */
    int idx;                /* index of current command in the chain of cmdLines (0 for the first) */
    struct cmdLine *next;   /* next cmdLine in chain */
} cmdLine;

/* Parses a given string to arguments and other indicators */
/* Returns NULL when there's nothing to parse */ 
/* When successful, returns a pointer to cmdLine (in case of a pipe, this will be the head of a linked list) */
cmdLine *parseCmdLines(const char *strLine);    /* Parse string line */

/* Releases all allocated memory for the chain (linked list) */
void freeCmdLines(cmdLine *pCmdLine);       /* Free parsed line */

/* Replaces arguments[num] with newString */
/* Returns 0 if num is out-of-range, otherwise - returns 1 */
int replaceCmdArg(cmdLine *pCmdLine, int num, const char *newString);

1 Ответ

1 голос
/ 20 апреля 2019

Вы должны выполнять execvp не в родительском, а в дочернем.

Ваш терминал ожидает завершения родительского задания. Завершение родителя, не дожидаясь его завершения, приводит к процессу зомби .

Изменение вашего кода для выполнения команды в потомке и ожидания его завершения в родительской программе решило вашу проблему, когда я проверял ее.

Предлагаю прочитать man 3 wait !

...