程序挂起连接到FIFO(命名管道)

时间:2011-02-18 07:19:17

标签: c shell

我正在尝试通过使用mkfifo()创建许多FIFO管道来在操作系统shell项目中实现流水线操作。目前,该程序似乎在打开第一个FIFO进行写入后挂起。此外,在工作目录上执行ls时会出现FIFO。我在这个例子中使用了freopen()错误吗?

void execute_external()
{
    int backgrounding = 0;
    if (raw_command[strlen(raw_command)-1] == '&')
    {
        pmesg(2, "Backgrounding requested.\n");
        raw_command[strlen(raw_command)-1] = '\0';
        raw_command = realloc(raw_command, strlen(raw_command)-1);
        backgrounding = 1;
    }

    int numCommands = 1;
    char **commands;
    commands = malloc(sizeof(char *));

    if(strstr(raw_command, "|") != NULL)        
    {
        numCommands = separate_pipeline_commands(commands);
    }
    else
    {
        commands[0] = malloc(strlen(raw_command) * sizeof(char));
        commands[0] = raw_command;
    }

    int i;
    char *fifo = malloc(MAXFIFOLEN);
    for (i = 0; i < numCommands; i++)
    {
        char **parameters_array = malloc(strlen(commands[i]) * sizeof(char *));
        int num_params;
        num_params = str_to_str_array(commands[i], parameters_array);
        pmesg(2, "Command is %s.\n", commands[i]);

        if (numCommands > 1)
        {
            int j;
            for (j = 0; j < numCommands - 1; j++)
            {
                sprintf(fifo, "fifo%i", j);
                mkfifo(fifo, S_IWUSR | S_IRUSR );
            }
        }

        pid_t pid = fork();

        pmesg(2, "Process forked. ID = %i. \n", pid);
        if (pid < 0)
        {
            fprintf(to_write_to, "Could not fork a process to complete the external command.\n");
            exit(EXIT_FAILURE);
        }
        int status;
        if (pid == 0) // This is the child process
        {
            pmesg(1, "input: [%s] output: [%s] input: %d, output: %d backgrounding is %d\n",input_file_name, output_file_name, redirect_input, redirect_output, backgrounding);
            if (numCommands > 1 && i == 0) // we may be pipelining and this is the first process
            {
                sprintf(fifo, "%s%i", "fifo", i);
                printf("Initial output: %s.\n", fifo);
                freopen(fifo, "w", stdout);
                //~ unlink(fifo);
            }
            else if (numCommands > 1 && i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process
            {
                sprintf(fifo, "%s%i", "fifo", i-1);
                printf("Input for process %i: %s.\n", i, fifo);
                freopen(fifo, "r", stdin);
                //~ unlink(fifo);
                sprintf(fifo, "%s%i", "fifo", i+1);
                printf("Output for process %i: %s.\n", i, fifo);
                freopen(fifo, "w", stdout);
                //~ unlink(fifo_2);
            }
            else if (numCommands != 1 &&i == numCommands)
            {
                char *fifo = malloc(strlen("fifo")+2);
                sprintf(fifo, "%s%i", "fifo", i);
                freopen(fifo, "r", stdin);  
                free(fifo);             
            }
            if(redirect_output == 1)
            {
                freopen(output_file_name, "w", stdout);
            }
            if(redirect_input == 1)
            {
                freopen(input_file_name, "r", stdin);
            }
            if (backgrounding != 0)
            {
                freopen("/dev/null", "w", stdout);
            }
            pmesg(2, "This is the child process, running execlp.\n");
            pmesg(1, "Command: [%s]\n", parameters_array[0]);
            if (execvp(parameters_array[0], parameters_array) < 0)
            {
                fprintf(to_write_to, "Could not execute the external command. errno: %i.\n", errno);
                exit(EXIT_FAILURE);
            }
            else    { pmesg(2, "Executed the child process.\n");}
        }
        else
        {
            if (backgrounding != 0)
            {
                enqueue(&process_queue, pid, clock(), 0, 0);
                printQueue(process_queue);
            }
            if (backgrounding == 0) { while(wait(&status) != pid); }// Wait for the child to finish executing
        } 
        pmesg(1, "The child has finished executing.\n");
        free(parameters_array);
    }
    free(commands);
}

2 个答案:

答案 0 :(得分:1)

我已经在下面的代码中添加了一些评论,但XAder的摘要值得先阅读,以帮助我在详细的挑剔之前了解大局。

我建议用很长的形式写出你要为两个命令的管道执行的确切代码,然后是三个命令的管道代码,然后是四个......然后然后围绕重复的代码放置一个循环。 (事实上​​,你只有一个fork()向我建议你为两个命令做了代码,但不是三个。:)

希望这有帮助。

/* if numCommands == 1 or 0, the rest is probably useless too
   so this should guard the entire routine, not just the routine
   that creates FIFOs */
if (numCommands > 1)
{
    int j;
    for (j = 0; j < numCommands - 1; j++)
    {
        char *fifo = malloc(strlen("fifo")+1);  /* BUG #1 */
        sprintf(fifo, "%s%i", "fifo", j); /* BUG #2 */
        mkfifo(fifo, S_IWUSR | S_IRUSR );
        free(fifo); /* messy */
    }
}

/* Bug #1 The malloc(strlen()+1) is only good for "fifo", doesn't
   actually allocate space for your number. Don't forget the
   ascii NUL character at the end of the string. Add another +1. */
/* Bug #2 works for numCommands < 10; with 10 commands, you'll need to +2
   for two characters, and so on */
/* messy -- maybe just have a 'char fifo[MAXFIFOLEN];' allocation,
   and set MAXFIFOLEN to 255 or 4096 or something. No need to allocate
   and free a simple little buffer a dozen times. */

pid_t pid = fork();

/* You should probably place fork() in a for loop; one new process
   per command. Another choice is to write this whole routine recursively
   which might be adding too many moving parts into one program */

pmesg(2, "Process forked. ID = %i. \n", pid);
/* Note that parent and child get different values of 'pid', so printing
   the value of pid here may be very confusing */
int status;
if (fork < 0) /* BUG #3 fork() is a function; should be pid */
{
    fprintf(to_write_to, "Could not fork a process to complete the external command.\n");
/* perror() is a wonderful routine! it helps users know _why_ something failed */
    exit(EXIT_FAILURE);
}

if (pid == 0) // This is the child process
/* only ONE path below will ever execute; this is why your fork()
   should be in a loop over numCommands, so each command's process
   can get its own individual stdin and stdout hooked together */
{
    pmesg(1, "input: [%s] output: [%s] input: %d, output: %d backgrounding is %d\n",input_file_name, output_file_name, redirect_input, redirect_output, backgrounding);
    if (numCommands > 1 && i == 0) // we may be pipelining and this is the first process
    {
        char *fifo = malloc(strlen("fifo")+2);
        sprintf(fifo, "%s%i", "fifo", i); /* could just be sprintf(fifo, "fifo%i", i); */
        printf("Initial output: %s.\n", fifo);
        freopen(fifo, "w", stdout);
        //~ unlink(fifo);
        free(fifo);
    }
    else if (numCommands > 1 && i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process
    {
        char *fifo = malloc(strlen("fifo")+2);
        sprintf(fifo, "%s%i", "fifo", i-1);
        printf("Input for process %i: %s.\n", i, fifo);
        freopen(fifo, "r", stdin);
        //~ unlink(fifo);
        char *fifo_2 = malloc(strlen("fifo")+2);
        sprintf(fifo_2, "%s%i", "fifo", i+1);
        printf("Output for process %i: %s.\n", i, fifo);
        freopen(fifo_2, "w", stdout);
        //~ unlink(fifo_2);
        free(fifo);
        free(fifo_2);
    }
    else if (numCommands != 1 &&i == numCommands)
    {
        char *fifo = malloc(strlen("fifo")+2);
        sprintf(fifo, "%s%i", "fifo", i);
        freopen(fifo, "r", stdin);  
        free(fifo);             
    }

答案 1 :(得分:0)

一般来说:

  • mkfifo filename的错误内存分配
  • 根据代码,只有子进程的逻辑,它只能通过3个路径之一,所以总是只有一个进程打开文件,根据手册页,它将被阻塞,直到两方打开fh。
  • i,numofcommands和逻辑非常不清楚 - 试试这个approach
相关问题