开发者

Fork(): Dont return from child until it's terminated

I'm having some troubles with fork() and that kind of things.

I'm developing a shell, where the user can write commands that whill be executed as in a normal and common shell.

I have a main function like this:

void Shell::init() {
    string command;
    while (1) {
        cout << getPrompt() << " ";
        command = readCommand();
        if (command.length() > 0) handleCommand(command);
    }
}

handleCommand() is the function that does pretty much everything. Somewhere in it, I have the following:

...
else {
    pid_t pid;
    pid = fork();

    char* arg[tokens.开发者_JAVA技巧size() + 1];
    for (int i = 0; i < tokens.size(); ++i) {
        arg[i] = (char*) tokens[i].c_str();
    }
    arg[tokens.size()] = NULL;

    if (pid == 0) {
        if (execvp(tokens[0].c_str(), arg) == -1) {
            cout << "Command not known. " << endl;
        };
    } else {
        wait();
    }
}

What I want is that when I reach that point, the command will be treated as a program invocation, so I create a child to run it. It's working almost perfect, but I get the prompt again before the program output. Example:

tronfi@orion:~/NetBeansProjects/Shell2$ whoami
tronfi@orion:~/NetBeansProjects/Shell2$ tronfi

tronfi@orion:~/NetBeansProjects/Shell2$ 

The child should die after the execvp, so it shouldn't be calling the prompt, and the parent is waiting until the child die.

So... what I'm doing wrong?

Thanks!!


You are calling wait() incorrectly. It expects to be passed a pointer-to-int, in which the child's exit status will be stored:

int status;
wait(&status);

Really, though, you should be using waitpid() to check for the specific child that you're after. You also need to loop around if waitpid() is interrupted by a signal:

int r;
do {
    r = waitpid(pid, &status, 0);
} while (r < 0 && errno == EINTR);


I'm not sure that this is exactly the problem, but you must ensure that the child exits even if execvp() fails:

if (pid == 0) {
    if (execvp(tokens[0].c_str(), arg) == -1) {
        cout << "Command not known. " << endl;
    };
    exit(1); // or some other error code to indicate execvp() fails
} else {
    wait();
}

If you don't do this, then if excecvp() fails then you will end up with two instances of your shell, which is probably not what you want.


The child must be terminated using the call

exit(0)
(only on success), as this helps in clening of memory and flushes the buffer. This status returned by the child must be checked by the parent and then only it should give the prompt.

Let me know if you need more details.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜