Question

I'm using "int flag = [0 or 1]" to determine if my loop should go back to the do{}. Heres my code

void shell() 
{
    int flag = 1;
    do
    {
        // Retrieve PID of the parent process. 
        pid_t shell_pid = getpid();

        // Print shell prompt. 
        printf("{%i}$ ", shell_pid);

        // Retrieve input from stdin.
        char* input = NULL;
        size_t input_size = 0;
        getline(&input, &input_size, stdin);
        char delim = ' ';
        char **argvp;
        int argc = makeargv(input, &delim, &argvp);

        // Remove \n from last arg
        char* lastarg = argvp[argc - 1];
        while(*lastarg && *lastarg != '\n')
            lastarg++;
        *lastarg = '\0';

        // Create a child process to handle user input. 
        pid_t pid = fork();

        // Parent process.  
        if (pid != 0) 
        {
            wait(NULL);
        } 
        else // Child process
        {
            int i;
            // Handle user input here!

            //got some debugging tools here
            printf("========DEBUG==========\n");
            printf("There are %i args\n", argc);
            for(i = 0; i < argc; i++)
            {
                printf("arg %i: \"%s\"\n", i, *(argvp + i));
            }
            printf("=====END DEBUG==========\n\n");
            printf("********OUTPUT*********\n");
            //handle "echo" here
            if((i = strcmp(argvp[0],"echo")) == 0)
            {
                echo(argc, argvp);
            }

            //handle "exit" or "quit" here
            if((i = strcmp(argvp[0],"exit")) == 0 || (i = strcmp(argvp[0],"quit")) == 0)
            {
                printf("got in the exit\n");
                flag = 0;
            }

        }
        printf("****END OUTPUT*********\n");
        // Free memory allocated by getline(). 
        free(input);
    }while(flag == 1);    
}

and my input/output looks like this: [input is preceded by $]

$ ./shelltest
{13158}$ try first string
========DEBUG==========
There are 3 args
arg 0: "try"
arg 1: "first"
arg 2: "string"
=====END DEBUG==========

********OUTPUT*********
****END OUTPUT*********
{13159}$ echo try another
========DEBUG==========
There are 3 args
arg 0: "echo"
arg 1: "try"
arg 2: "another"
=====END DEBUG==========

********OUTPUT*********
try another 
****END OUTPUT*********
{13160}$ quit 
========DEBUG==========
There are 1 args
arg 0: "quit"
=====END DEBUG==========

********OUTPUT*********
got in the exit
****END OUTPUT*********
****END OUTPUT*********
{13160}$

Since "got in the exit" was shown in the output, then flag was immediately set to 0. how is it that the loop continues?

Was it helpful?

Solution

You are using fork(), the parent process is waiting for the child process to exit, the line:

printf("****END OUTPUT*********\n");

is executed by both the parent and child process, thus you saw it twice.

OTHER TIPS

Your child process is exiting the loop but your parent continues to run.

The normal paradigm for shells is for the parent to read and evaluate the input and only fork if a child process is needed.

Using that method, the parent would detect exit and finish without creating a child.

When you print

{13160}$ quit

In reality, 13160 is the pid of the parent of the process that will be created by fork to handle the quit command(To see this in action, print the pid of the child after fork). This one will parse quit and exit by setting flag to 0. You will then see ****END OUTPUT********* twice.

You have to remember that when you fork, memory is not shared with the parent(in Linux it is but it is copy on write. It was last time I read on it) so when child writes flag = 0, parent will not see this value so it will loop again. Hence why it asks for input again.

One other thing you process relationship looks like {13158}->{13159}->{13160}->... Since root process is 13158, I think what you wanted to do is spawn a single children from root after every input. So you might want to check that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top