Execution when using fork in a program - linux

I was reading about fork() when I tried out the following program. I could not understand the output of the following command but I could figure out what it does if I remove the second fork() call. Please explain me the flow of the following program.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char const *argv[])
{
pid_t pid;
int returnvalue;
pid = fork();
pid = fork();
if (!pid) cout<< "In the child"<<endl;
else cout<< "In parent"<<endl;
cout<< (&returnvalue)<<endl;
switch(pid)
{
case -1:
perror("fork");
return 0;
case 0:
cout<< "Child Process with pid: " <<getpid()<<endl;
cout<< "Parent's pid is: "<<getppid()<<endl;
cout<< "Exiting"<<endl;
returnvalue=2;
return returnvalue;
default:
cout<< "Parent process with pid: "<<getpid()<<endl;
cout<< "Child's pid: "<<pid<<endl;
cout<< "Waiting for child to exit"<<endl;
wait(&returnvalue);
cout<< "Child's exit status: "<<WEXITSTATUS(returnvalue)<<endl;
cout<< "Exiting!"<<endl;
}
return 0;
}
Why does it print "In parent" and "In the child" twice each?
Also, I read that every child process gets its own copy of variables. Shouldn't address of "returnvalue" be printed different?
Output:
In parent
0x7fff2d536428
Parent process with pid: 5487
Child's pid: 5489
Waiting for child to exit
In the child
0x7fff2d536428
Child Process with pid: 5489
Parent's pid is: 5487
Exiting
Child's exit status: 2
Exiting!
In parent
0x7fff2d536428
Parent process with pid: 5488
Child's pid: 5490
Waiting for child to exit
In the child
0x7fff2d536428
Child Process with pid: 5490
Parent's pid is: 5488
Exiting
Child's exit status: 2
Exiting!

Well you do have 2 calls to fork() will will result in 4 processes.
1st fork in P1 --> new process P2
2nd fork in P1 --> new process P3
2nd fork in P2 --> new process P4
the pid will be different based on the result following the 2nd fork() for sake of the explanation, I'll just say that P1 is the parent and remains the parent, P2 is a child of P1, but is a parent of P4, so its pid will be non zero, both P3 and P4 will have pid equal to 0. All 4 processes will enter the switch statement with a pid that will classify them as a parent or child, so since 2 have pid = 0 and 2 have pid != 0, 2 will be reported as parents and 2 will be reported as children.
P1 pid != 0 (classify parent)
P2 pid != 0 (classify parent)
P3 pid == 0 (classify child)
P4 pid == 0 (classify child)
It is true that P1 is created before P2 is created before P3 is created before P4, however when they enter into the switch statement and when they print out their messages is controlled by the scheduler. Consider the possibility that creating a process takes a lot of time (more then just printing stuff). So P1 creates P2 and then turns around and creates P3 meanwhile P2 is busy creating P4. P3 get created and prints stuff while P2 is still stuck creating P4.

Related

Understanding fork()

i have a question about this Code:
int id = fork();
if (id != 0)
fork();
printf("FORK: %d\n PID: %d\n PPID:%d\n", id, getpid(), getppid());
}
This is an example Output:
FORK: 5888
PID: 5887
PPID:5239
FORK: 0
PID: 5888
PPID:5887
FORK: 5888
PID: 5889
PPID:5887
I understand the code like this:
The parent process creates with int id = fork(); another process.
The parent process thus has the process ID of the child process as the return value in id and the child process has a value of 0.
With the condition if (id != 0) { fork (); } A child process WILL be created again in the parent process.
Thus, the parent process has two "children".
What confuses me about the output:
Shouldn't two of the three processes (with the PID 5888 and 5889) have a value of 0 in the fork() since both are child processes?
Also, the process with ID 5889 in the fork() has the process id 5888, but wouldn't that mean that 5888 is a child of 5889?
I probably just don't quite understand the principle of fork(), but I would still be grateful for any help.
They should both have id = 0 but you didn't assign the id in the second fork.
For the second question the pids do not have a particular order of assignment and are managed entirely by the kernel.

Using execvp to read command line arguments as commands error

pretty new to Linux and im trying to read in command line arguments in a Linux operating system. I want to be able to execute the commands i give as command line arguments programatically. Here is what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int counter;
for(counter = 1; counter < argc; counter++){
pid_t pid = fork();
if(pid < 0)
{
perror("Forking failed");
exit(1);
}
else if(pid == 0)
{
char *args[] = {argv[counter], NULL};
printf("Argument to be passed: %s \n", argv[counter]);
execvp(args[0], args);
perror("Command failed.");
exit(0);
}
printf("Process %s completed successfully.\n", argv[counter]);
}
exit(0);
}
My output on terminal:
darren#darren-VirtualBox:~/Desktop$ ./cmdarguments /home/darren/Desktop/fullpathdoc1 /home/darren/Desktop/fullpathdoc2
Process /home/darren/Desktop/fullpathdoc1 completed successfully.
Process /home/darren/Desktop/fullpathdoc2 completed successfully.
darren#darren-VirtualBox:~/Desktop$ Argument to be passed: /home/darren/Desktop/fullpathdoc2
This is the second program that simply prints this statement.
Argument to be passed: /home/darren/Desktop/fullpathdoc1
This is the first program that simply prints this statement.
I want to be able to print out the process name, and say process completed after each command line argument has been successfully executed. For some reason, my output results in everything seeming to execute backwards, with my process completed messages coming up first as well as reading in the command lines from right to left. Can someone please help with my code and how I can rectify this?
When there are multiple processes, which process get to run first is totally up to your operating system(Linux)'s decision.
Broadly, the parent process -- that's where fork() returns > 0 -- needs to wait for the child process to complete. Bear in mind that the three calls to execvp() result in three, concurrent, processes. So if you don't monitor them, they'll proceed in their own merry way. There is already a discussion of this issue on SO:
how to correctly use fork, exec, wait

C Programming Fork Example

How many processes are created when running the following program ? I can not solve. I would appreciate if you help
int main()
{
int i;
for (i=fork(); i<2; i++ )
fork();
}
fork() creates a child process, creating an another instance of the parent process. It returns 0 to the child and PID of the child to the parent.
In this case, when i = fork() is executed,
The parent gets i assigned as the PID of the child process, which is most likely greater than 1. The for loop in the parent will run not run even once as i < 2 will fail. At this point of time there are two processes P and C1 (Child)
After the fork is executed by parent, child gets a 0 as return value, i = 0. This means the condition i < 2 is successful. Child executes the fork() in the loop body, creating C2. Value of i in both C1 and C2 are 0. i gets incremented to 1.
C1 and C2 execute i < 2, This condition is successful. Fork is executed by both. C3 is spawned off by C1 and C4 by C2.
i's value gets incremented to 2. i < 2 fails. All of them get out of the loop
To summarise, there are 4 child processes created in this program. You can try this with the following program where you will see 5 PIDs getting printed.
#include <stdio.h>
main()
{
int i = 0;
for (i = fork(); i < 2; i++)
fork();
printf("Hello World i %d\n", getpid());
}

Process wait using linux system call wait

I am trying to create a process using fork system call and then wait on the child process. I have used the following:
waitpid (pid, &status, 0);
1) The first problem is that the status is 8 bit shifted to the left e.g., if the child process returns 1, the waitpid function returns the value of the status in the status variable to be 256. Please let me know why it is doing that.
2) According to the manual, the waitpid waits for the child process to change state. but then it also says:
"The wait() system call suspends execution of the calling process until
one of its children terminates. The call wait(&status) is equivalent
to:
waitpid(-1, &status, 0);"
I am a bit confused here whether the waitpid and the wait calls wait for state change or for child process termination. Kindly clearify this point.
What does the zero in the third arguement specifies?
3) If i put the child process in sleep state, doesn't the state of the child process changes to be in waiting state by waiting for e.g., 5 secs?
Following is my program:
int main(int argc, char ** argv)
{
pid_t pid = fork();
pid_t ppp;
if (pid==0)
{
sleep(8);
printf ("\n I am the first child and my id is %d \n", getpid());
printf ("The first child process is now exiting now exiting\n\n");
exit (1);
}
else {
int status = 13;
printf ("\nI am now waiting for the child process %d\n", pid);
waitpid (pid, &status, 0);
printf ("\n the status returned by the exiting child is %d\n", status>>8);
}
printf("\nI am now exiting");
exit(0);
}
Thanks
The status parameter encodes more than just the exit code of the child. From man waitpid:
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should only be employed if WIFEXITED returned true.
main waitpid explains what the third parameter does.
The value of options is an OR of zero or more of the following constants:
WNOHANG
return immediately if no child has exited.
WUNTRACED
also return if a child has stopped (but not traced via ptrace(2)). Status for traced children which have stopped is provided even if this option is not specified.
WCONTINUED (since Linux 2.6.10)
also return if a stopped child has been resumed by delivery of SIGCONT.
State change is very precisely and narrowly defined. From man waitpid:
A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal.
Going to sleep is not a state change. Being stopped by SIGSTOP/SIGTSTP is.

Return code when OS kills your process

I've wanted to test if with multiply processes I'm able to use more than 4GB of ram on 32bit O.S (mine: Ubuntu with 1GB ram).
So I've written a small program that mallocs slightly less then 1GB, and do some action on that array, and ran 5 instances of this program vie forks.
The thing is, that I suspect that O.S killed 4 of them, and only one survived and displayed it's "PID: I've finished").
(I've tried it with small arrays and got 5 printing, also when I look at the running processes with TOP, I see only one instance..)
The weird thing is this - I've received return code 0 (success?) in ALL of the instances, including the ones that were allegedly killed by O.S.
I didn't get any massage stating that processes were killed.
Is this return code normal for this situation?
(If so, it reduces my trust in 'return codes'...)
thanks.
Edit: some of the answers suggested possible errors in the small program, so here it is. the larger program that forks and saves return codes is larger, and I have trouble uploading it here, but I think (and hope) it's fine.
Also I've noticed that if instead of running it with my forking program, I run it with terminal using './a.out & ./a.out & ./a.out & ./a.out &' (when ./a.out is the binary of the small program attached)
I do see some 'Killed' messages.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define SMALL_SIZE 10000
#define BIG_SIZE 1000000000
#define SIZE BIG_SIZE
#define REAPETS 1
int
main()
{
pid_t my_pid = getpid();
char * x = malloc(SIZE*sizeof(char));
if (x == NULL)
{
printf("Malloc failed!");
return(EXIT_FAILURE);
}
int x2=0;
for(x2=0;x2<REAPETS;++x2)
{
int y;
for(y=0;y<SIZE;++y)
x[y] = (y+my_pid)%256;
}
printf("%d: I'm over.\n",my_pid);
return(EXIT_SUCCESS);
}
Well, if your process is unable to malloc() the 1GB of memory, the OS will not kill the process. All that happens is that malloc() returns NULL. So depending on how you wrote your code, it's possible that the process could return 0 anyway - if you wanted it to return an error code when a memory allocation fails (which is generally good practice), you'd have to program that behavior into it.
What signal was used to kill the processes?
Exit codes between 0 and 127, inclusive, can be used freely, and codes above 128 indicate that the process was terminated by a signal, where the exit code is
128 + the number of the signal used
A process' return status (as returned by wait, waitpid and system) contains more or less the following:
Exit code, only applies if process terminated normally
whether normal/abnormal termination occured
Termination signal, only applies if process was terminated by a signal
The exit code is utterly meaningless if your process was killed by the OOM killer (which will apparently send you a SIGKILL signal)
for more information, see the man page for the wait command.
This code shows how to get the termination status of a child:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main (void)
{
pid_t pid = fork();
if (pid == -1)
{
perror("fork()");
}
/* parent */
else if (pid > 0)
{
int status;
printf("Child has pid %ld\n", (long)pid);
if (wait(&status) == -1)
{
perror("wait()");
}
else
{
/* did the child terminate normally? */
if(WIFEXITED(status))
{
printf("%ld exited with return code %d\n",
(long)pid, WEXITSTATUS(status));
}
/* was the child terminated by a signal? */
else if (WIFSIGNALED(status))
{
printf("%ld terminated because it didn't catch signal number %d\n",
(long)pid, WTERMSIG(status));
}
}
}
/* child */
else
{
sleep(10);
exit(0);
}
return 0;
}
Have you checked the return value from fork()? There's a good chance that if fork() can't allocate enough memory for the new process' address space, then it will return an error (-1). A typical way to call fork() is:
pid_t pid;
switch(pid = fork())
{
case 0:
// I'm the child process
break;
case -1:
// Error -- check errno
fprintf(stderr, "fork: %s\n", strerror(errno));
break;
default:
// I'm the parent process
}
Exit code is only "valid" when WIFEXITED macro evaluates to true. See man waitpid(2).
You can use WIFSIGNALED macro to see if your program has been signaled.

Resources