1

I'm making a shell in C for a school project that is capable of running processes in parallel if it is commanded to do so.

This is the loop of the shell application that waits for commands:

while (1) {
    action = parseShellArgs();

    if (action == 1) {
        printf("Exiting...\n");
        break;
    } else if (action == 0) {
        int pid = fork();

        if (pid < 0) {
            printf("Failed to fork\n");
        } else if (pid == 0) {
            (*NUM_PROCESSES_RUNNING)++;
            printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
            char * solverArgs[] = {"a", shellArgs[1], NULL};    // first element is placeholder for argv[0]
            execv("CircuitRouter-SeqSolver", solverArgs);
            exit(0);
        } else if (pid > 0) {
            if (*NUM_PROCESSES_RUNNING >= MAXCHILDREN) {
                printf("All processes are busy\n");
                continue;
            }
            int status, childpid;

            wait(&status);
            childpid = WEXITSTATUS(status);
            (*NUM_PROCESSES_RUNNING)--;
            printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
            (void)childpid;     // suppress "unused variable" warning
        } else {
            printf("Wait what\n");
        }
    } else {
        printf("Oops, bad input\n");
    }
}

Please do disregard the constants being incremented and decremented.

Now, this only works partially. Whenever I give it a command to create another process and run another program (condition action == 0, this has been tested and works), the fork happens and the program is correctly executed.

However, I cannot fork multiple times. What I mean by this is: the program forks and the child executes as instructed in the execv call. The problem is that instead of the parent process then goes back to expecting input to possibly fork again, it waits for the child process to finish.

What I am trying to make this cycle do is for the parent to always be expecting input and forking as commanded, having multiple children if necessary. But as I explained above, the parent gets "stuck" waiting for the single child to finish and only then resumes activity.

Thank you in advance.

Edit: I have experimented multiple combinations of not waiting for the child process, using extra forks to expect input etc.

Saucy Goat
  • 1,587
  • 1
  • 11
  • 32
  • 1
    This question seems to have nothing to do with its title – rici Sep 29 '18 at 13:31
  • @rici thank you for pointing that out. I was going to ask another question and mixed up the titles. Fixed. – Saucy Goat Sep 29 '18 at 14:40
  • when asking a question about a run time problem, as this question is doing, post a [mcve] so we can reproduce the problem. – user3629249 Oct 01 '18 at 14:57
  • 1
    why invoke `childpid = WEXITSTATUS(status);` when the code is not making use of the 'exit status'? – user3629249 Oct 02 '18 at 01:06
  • 1
    error messages should be output to `stderr`, not `stdout` and when the error indication is from a C library function should also output the text reason the system thinks the error occurred. Suggest using `perror()` as it performs all the requiremets – user3629249 Oct 02 '18 at 01:09
  • 1
    regarding: `} else { printf("Wait what\n");` this code will never be executed because all three conditions have already been checked and handled – user3629249 Oct 02 '18 at 01:11
  • 1
    regarding: `} else if (pid > 0) { if (*NUM_PROCESSES_RUNNING >= MAXCHILDREN) { printf("All processes are busy\n"); continue; }` this results in the latest child process being ignored. Probably not what you want to do. Also, if could not start another process, the call to `fork()` would have failed and returned -1 – user3629249 Oct 02 '18 at 01:13
  • 1
    regarding; `execv("CircuitRouter-SeqSolver", solverArgs); exit(0);` between these two statements should be a call to `perror() so the user will know about the problem. Also, in general, returning `0` indicates success but the call to `execv()` was not successful. Suggest using: `exit( EXIT_FAILURE );` – user3629249 Oct 02 '18 at 01:16
  • 1
    regarding: `int pid = fork();` The returned type from `fork()` is a `pid_t` While it may 'currently' be defined as a typedef for `int`, that is not something that can be depended upon. – user3629249 Oct 02 '18 at 01:19

1 Answers1

4

From man wait.2

The wait() system call suspends execution of the calling process until one of its children terminates.

Your program gets stuck because that's what wait does. Use waitpid instead with WNOHANG.

waitpid(pid_child, &status, WNOHANG);

doesn't suspend execution of the calling process. You can read the waitpid man page to find out the return values and how to know if a child terminated.

nullp0tr
  • 485
  • 3
  • 11