Forking Multiple Times - c

So this is a snippet of my code:
pid_t children[MAX_PIPES];
for (i = 0; i < numPipes; i++)
{
pid_t child_pid = fork();
children[i] = child_pid;
switch(child_pid)
{
case 0:
// Some code thats executed in the child that executes execv()
break;
case -1: // Unable to create child
perror("fork");
break;
}
}
// Wait for children
for (j = 0; j < numPipes && children[j] != 0; j++)
{
if (background)
waitpid(children[j], &status, WNOHANG);
else
waitpid(children[j], &status, 0);
}
Currently it works fine when I only call execv() once, but I am trying to execute multiple commands using execv() one after the other inside the already forked child process.
How do I go about adding that functionality? I have tried to add another fork() inside a loop inside the child but it wasnt successful.
Any ideas would be greatly appreciated. Thanks

execv, like the other exec() commands, doesn't return except on failure. The context for the new program is loaded in place of the current program.

Your problems is that execv replaces the entire child process with the command being called, so you can't put more than one execv command into the child process.
If you want to have multiple commands, you have to fork(), execv() each one. You're could use system(), but it doesn't process parameters in the same manner as execv() (it launches a shell).
If you want to run multiple commands, then you should do a second fork() ... execv() using a wrapper akin to:
int
subv(char *path, char * const argv[])
{
int ret;
pid_t a_pid = fork();
if (a_pid == -1) return -1;
if (a_pid != 0) { wait(&ret); return ret; }
return execv(path, argv);
}
The you replace all the execv calls with subv() and deal with the return code appropriately.

Related

Fork() with multiple children and with waiting for all of them to finish

I want to create a program in C, where I use fork() to create multiple children, then wait for all of them to finish and do parent code (only once).
I tried using for loop and two forks but I there is a problem: either parent code isn't running at the end or children are not running parallel.
//Number of processes I want to create
int processes = 6;
pid_t *main_fork = fork();
if(main_fork ==0){
for(int i=0;i<processes;i++){
pid_t *child_fork = fork();
if(child_fork ==0){
// child code
exit(0);
}
else if(child_fork >0){
//And here is the problem, with the wait: children don't
//run parallel and if I delete it, the main parent code doesn't run
wait(NULL);
}else{
// Child fork failed
printf("fork() failed!\n");
return 1;
}
}
}else if(main_fork >0){
wait(NULL);
//Main parent code - here I want to do something only once after all
//children are done
}else{
// Main fork failed
printf("fork() failed!\n");
return 1;
}
If somebody could could fix my code, or write a better solution to this problem I would be so grateful!
If you want all the children to run in parallel, you have to do the wait after all the children has been started. Otherwise you start a child, wait for it to finish, start a new one, wait for that to finish, start a third one, wait for the third one to finish, and so on...
So what you typically want to do is to start all the children and put all the pid_t in an array, and when you are finished you may call wait() for each pid_t
This is the simple, and good enough solution for your case.
Here is a sample code that you can fit to your problem:
pid_t children[processes];
for(int i=0; i<processes; i++)
{
pid_t child = fork();
if(child == 0)
{
// child code
....
// We call _exit() rather than exit() since we don't want to clean up
// data structures inherited from parent
_exit(0);
}
else if (child == -1)
{
// Child fork failed
fprintf(stderr, "myprog: fork failed, %s", strerror(errno));
// Do real cleanup on failure is to complicated for this example, so we
// just exit
exit(EXIT_FAILURE);
}
children[i] = child;
}
// Do something if you want to do something before you expect the children to exit
....
for(int i=0; i<processes; i++)
{
pid_t child = children[i];
int status;
waitpid(child, &status, );
// Do something with status
}
Naturally this is not a complete example that fits any situation. Sometimes you have to tell the children when they should exit. Other times the children are not started/stopped in one go, and you have to play with asynchronous events, and so on...

Keep a parent process waiting and run linux command as many times as wanted

I have the below C code in linux (using gcc):
void doWho(void)
{
char entry[10];
int ret, i;
ret = read(0, entry, 10);
if (*entry == 'u')
{
for(i=0; i<3; i++)
{
execl("/usr/bin/who","who",NULL);
}
}
}
int main(int argc, char *argv[])
{
int childpid;
printf("Before it forks\n");
childpid = fork();
if(childpid == 0)
{
printf("This is a child process\n");
doWho();
exit(0);
} else
{
printf("This is the parent process\n");
wait(NULL);
}
return 0;
}
I want the parent process to keep waiting indefinitely and run "who" every time I press the "u" key. I only get the desired effect one time and then the child and parent processes exit. Any help on this?
Observe below loop :
for(i=0; i<3; i++)
{
execl("/usr/bin/who","who",NULL);
}
It doesn't matter how many times you rotate the loop , it will execute only once because when child process starts running(PCB created), you are calling function doWho then control will come to doWho function and in doWho function what you are doing ? execl(). what execl() does is that " it replaces current process(child) with new process, after when i = 0 whole child process image got replaced with new one using execl(), so there is nothing left in child process that's why it will execute only once.
If you want to execute as many as you should use fork() in the function because then exec will replace every process created by fork(), but it's not advised to run fork() in loop because your program may crash when there are no more resource available.
So replace your doWho function as
void doWho(void)
{
char entry[10] = {0};
int ret, i;
for(; ;) {
/** who command will be executed when ever condition is true **/
ret = read(0, entry, 10);
__fpurge(stdin);//to clear stdin buffer everytime
if (*entry == 'u') {
if(fork()==0)//only this newly created process will be replaces by execl not one was in main()
execl("/usr/bin/who","who",NULL);
else
;// this parents does nothing
}
}
}
I hope it helps.

C - meaning of wait(NULL) when executing fork() in parallel

In the code below, do the forks actually run in parallel or one after another?
What is the meaning of wait(NULL) ?
(The program creates an n number of child processes, n is supplied via command line)
int main ( int argc, char *argv[] ) {
int i, pid;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
exit(0);
} else {
wait(NULL);
}
}
}
They do run in parallel, up until the point that one of them waits.
wait(NULL) or more accurately wait(0) means wait until a state change in the child process. To find out about Unix / Linux C api calls, type man <function Name> on the command line. You'll need to get used to reading those pages, so better start now.
In your case
man wait
would have given you what you needed.
Since you've only fork(...)ed once, you have only one child. The parent waits until it changes state, and since the child's state during the fork is the same as the parent's state prior to the fork (that of running), the likely outcome is that the parent waits until the child dies. Then the parent will continue executing, but since it doesn't have much to do after the wait(...) call, it will quickly exit too.

whether a function returned in the child process can be captured in the parent process

I'm currently implementing the && function in a shell using C. For example, if we input cmd1 && cmd2, then cmd2 executes only when cmd1 exits successfully. I'm thinking about:
int main() {
int i;
char **args;
while(1) {
printf("yongfeng's shell:~$ ");
args = get_line();
if (strcmp(args[0], "exit") == 0) exit(0); /* if it's built-in command exit, exit the shell */
if('&&') parse_out_two_commands: cmd1, cmd2;
if (execute(cmd1) != -1) /* if cmd1 successfully executed */
execute(cmd2); /* then execute the second cmd */
}
}
int execute(char **args){
int pid;
int status; /* location to store the termination status of the terminated process */
char **cmd; /* pure command without special charactors */
if(pid=fork() < 0){ //fork a child process, if pid<0, fork fails
perror("Error: forking failed");
return -1;
}
/* child */
else if(pid==0){ /* child process, in which command is going to be executed */
cmd = parse_out(args);
/* codes handleing I/O redirection */
if(execvp(*cmd, cmd) < 0){ /* execute command */
perror("execution error");
return -1;
}
return 0;
}
/* parent */
else{ /* parent process is going to wait for child or not, depends on whether there's '&' at the end of the command */
if(strcmp(args[sizeof(args)],'&') == 0){
/* handle signals */
}
else if (pid = waitpid(pid, &status, 0) == -1) perror("wait error");
}
}
So I'm using another function int execute(char ** args) to do the actual work. Its return type is int because I wan to know whether the command exits successfully. But I'm not sure here whether the parent process can get the return value from the child since they're two different processes.
Or should I decide whether to execute the second command in the child process, by forking another process to run it? Thanks a lot.
Change:
if(pid=fork() < 0){ //fork a child process, if pid<0, fork fails
to:
if((pid=fork()) < 0){ //fork a child process, if pid<0, fork fails
You're setting pid to the result of fork() < 0, not setting it to the PID of the child. So unless there's an error in fork(), this sets pid to 0 in both the parent and child, so they both think they're the child.
Regarding the return value of the execute() function: It will return in both the parent and child. In each process, it will return whatever was specified in the return statement in the corresponding branch of the if in execute(). Note that it execve() is successful, the child never returns, because it's no longer running this program, it's running the program that was exec'ed.
If the child wants to send success or failure information to the parent, it does this using its exit status, by calling exit(0) to indicate success, and exit(some-nonzero-value) to indicate failure. The parent can get the exit status using waitpid, and then return a success or failure indication from execute().

how to correctly use fork, exec, wait

The shell i'm writing needs to execute a program given to it by the user. Here's the very shortened simplified version of my program
int main()
{
pid_t pid = getpid(); // this is the parents pid
char *user_input = NULL;
size_t line_sz = 0;
ssize_t line_ct = 0;
line_ct = getline(&user_input, &line_sz, stdin); //so get user input, store in user_input
for (;;)
{
pid_t child_pid = fork(); //fork a duplicate process
pid_t child_ppid = getppid(); //get the child's parent pid
if (child_ppid == pid) //if the current process is a child of the main process
{
exec(); //here I need to execute whatever program was given to user_input
exit(1); //making sure to avoid fork bomb
}
wait(); //so if it's the parent process we need to wait for the child process to finish, right?
}
}
Have I forked the new process & checked to see if it's a child process correctly
What exec could I use here for what I'm trying to do? What is the most simple way
What are my arguments to wait? the documentation I'm looking at isn't helping much
Assume the user might input something like ls, ps, pwd
Thanks.
Edit:
const char* hold = strdup(input_line);
char* argv[2];
argv[0] = input_line;
argv[1] = NULL;
char* envp[1];
envp[0] = NULL;
execve(hold, argv, envp);
Here's a simple, readable solution:
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
// we are the child
execve(...);
_exit(EXIT_FAILURE); // exec never returns
}
The child can use the stored value parent if it needs to know the parent's PID (though I don't in this example). The parent simply waits for the child to finish. Effectively, the child runs "synchronously" inside the parent, and there is no parallelism. The parent can query status to see in what manner the child exited (successfully, unsuccessfully, or with a signal).

Resources