Reputation: 173
I am trying to make a program that mimics a Linux shell.
And it runs in two modes
(1) Interactive Mode (No arguments)
Wait for the child process. Execute one command at a time.
(2) Batch Mode (Given A file)
Do not wait. Try to execute the commands in parallel.
My code is pretty long so I decided to make a sample program to address (focus) on the problem that I am facing.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
struct commands
{
char *cmd[2];
};
int main(int argc, char *argv[])
{
printf("A program made to understand execvp\n");
commands threeCommands[3];
pid_t process;
int child_status;
threeCommands[0].cmd[0] = "date";
threeCommands[0].cmd[1] = NULL;
threeCommands[1].cmd[0] = "pwd";
threeCommands[1].cmd[1] = NULL;
threeCommands[2].cmd[0] = "cal";
threeCommands[2].cmd[1] = NULL;
for(int i = 0;i <3;i++)
{
process = fork();
if(process == 0)
{
execvp(threeCommands[i].cmd[0],threeCommands[i].cmd);
}
else
{
//wait(&child_status);
}
}
return 0;
}
As you can see I am commenting out the wait so that I try to do concurrent processing and the results of the commands are randomized and maybe intermixed.
The problem is after the execution of the three commands date,pwd,cal
The program doesn't terminate. It freezes in this state and doesn't just end, so my cursor is there as if it needs input. And my program doesn't end. How can I fix this?
Should I use kill or what?
Upvotes: 1
Views: 413
Reputation: 9770
You must call wait
for the child processes to terminate cleanly. You don't have to call wait
immediately, but you must call wait
before the program ends otherwise you have zombie child processes. This works for me and still runs all of the programs in parallel:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct commands
{
char *cmd[2];
};
int main(int argc, char *argv[])
{
printf("A program made to understand execvp\n");
struct commands threeCommands[3];
pid_t process;
int child_status;
threeCommands[0].cmd[0] = "date";
threeCommands[0].cmd[1] = NULL;
threeCommands[1].cmd[0] = "pwd";
threeCommands[1].cmd[1] = NULL;
threeCommands[2].cmd[0] = "cal";
threeCommands[2].cmd[1] = NULL;
for(int i = 0;i <3;i++)
{
process = fork();
if(process == 0)
{
execvp(threeCommands[i].cmd[0],threeCommands[i].cmd);
}
}
for(int i = 0;i <3;i++)
{
wait(&child_status);
}
return 0;
}
The other option is to ignore the SIGCHLD
signal:
signal(SIGCHLD, SIG_IGN); // automatically reap child processes
Upvotes: 0
Reputation: 409216
Just press the Enter key after the output.
If the parent process exits before the child processes then the shell will print the prompt after the parent process exits, then the child processes prints their output but the shell won't print a new prompt. Look a few lines above the end of the output to see the prompt after the parent process exits.
For example, after modifying your code to add a sleep(1)
before calling execvp
(to force the child processes to be delayed) I get the following output on my system:
[~/tmp]$ ./a.out A program made to understand execvp [~/tmp]$ tis 9 feb 2016 18:54:06 CET /home/XXXX/tmp Februari 2016 sö må ti on to fr lö 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
As you see the prompt is printed before the date
command runs (the .[~/tmp]$
before the date
output). Pressing the Enter brings the prompt back.
Upvotes: 1