Understanding how the child process executes in this code - c

I was given this starter code for a project, but am having difficulty understanding how the child process executes.
int pid ;
int child_info = -1;
if ( argv[0] == NULL ) /* nothing succeeds */
return 0;
if( (pid= fork()==-1)
perror("fork");
else if ( pid == 0 ){
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
execvp(argv[0], argv);
perror("cannot execute command");
exit(1);
}
else { //check if wait error or print out exit status
if ( wait(&child_info) == -1 )
perror("wait");
else {
printf("Exit status: %d, %d\n", child_info>>8, child_info&0377);
}
}
return child_info;
}
Looking at the code, the current process forks and in this case, the child inherits all of the relevant properties of the parent process, since there are no timers, signals or anything involved. However, the pid values of the new processes are in the 18000 range, so how can execvp(argv[0], argv) be executed since in this case, pid != 0.

From the fine manual for fork:
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process.
The first branch of the if is an error condition and will be executed in the parent process if there was an error. The second branch (pid == 0) is executed in the child process, the child does a bit of signal housekeeping and does the exec. The third branch is in the parent when there was no error.
In the parent, pid will be non-zero but in the new child process, pid will be zero.

It gets executed in the child process, where pid will be 0.
http://linux.die.net/man/2/fork

Fork returns the pid of the child to the parent process and 0 to the child process. so when asking for pid == 0 means "is this the child process?". If so, it executes the program passed through command line arguments.

There's only one new process created; the child.
fork() in the child process returns 0, which is what you're checking for.
fork() in the parent process (your original process) returns the child process' pid.
By checking the return of fork() for 0 you know if you're the parent or child; you're the child if it's 0.

Related

Parameters of the waitpid()

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int status;
int pid = fork();assigned to variable "pid"
if(pid == 0)
{
printf("I am the child with pid = %d\n", getpid());
}
else
{
printf("I am the parent with pid = %d\n", getpid());
waitpid(pid, &status, 0); // line 51
}
return 0;
}
In line number 51, please clarify the "pid" parameter. what will this process wait for?
fork returns 0 for the child process, -1 on error, and something else for the parent process. The else begins the part for the parent process, that means pid in waitpid contains the child's PID.
Citing man wait:
The waitpid() system call suspends execution of the calling
process
until a child specified by pid argument has changed state. By default,
waitpid() waits only for terminated children, but this behavior is mod-
ifiable via the options argument [...]
In short, waitpid waits for the child process to terminate.
If the fork is successful, fork returns 0 to the child, and returns to the parent the (positive) pid of the newly forked child process. In this statement, the parent waits the child's termination.
on success fork will return child id to parent and 0 to child,
waitpid(pid, &status, 0);
parameter.. ) pid - particular child ID.
parameter.. ) &status - exit status that will send to parent by child
parameter.. ) option
0 - option is indicated that
parent will wait till child is terminated.

How to get child PID in C?

I'm creating child processes in a for-loop. Inside the child process, I can retrieve the child PID with getpid().
However, for some reason when I try to store the value of getpid() into a variable declared by the parent process, the change is nullified when I check for it in the parent process. I'm assuming this has to do with some sort of process variable scope. Not really familiar with C, so can't be too sure.
Anyhow what is a way of storing the result of getpid() of a child PID (when called from the child process) into a variable in the parent process?
Or maybe another approach is storing fork() into a variable in the parent and calling some function on that variable to retrieve the child's PID? I don't know how to do this either, so if this is the better way, how would you do this?
fork already returns the child's pid. Just store the return value.
look at man 2 fork:
RETURN VALUES
Upon successful completion, fork() returns a value of 0 to the child process and
returns the process ID of the child process to the parent process. Otherwise, a
value of -1 is returned to the parent process, no child process is created, and
the global variable errno is set to indicate the error.
As mentioned in previous answer that "fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent process." So, the code can be written in this way:
pid = fork(); /* call fork() from parent process*/
if (0 == pid)
{
/* fork returned 0. This part will be executed by child process*/
/* getpid() will give child process id here */
}
else
{
/* fork returned child pid which is non zero. This part will be executed by parent process*/
/* getpid() will give parent process id here */
}
This link is very helpful and explains in detail.
if fork() is successfully created then it returns 0 value in the child process.
int main(void)
{
int id;
id= fork();
if(id==0)
{
printf("I am child process my ID is = %d\n" , getpid());
}
}
If you are calling fork in the following way:
pid = fork()
Then pid is in fact your child PID. So you can print it out from the parent.
Yes, the child process's pid is already returned with fork(), fork() is called once but return twice, different return value in parent and child process, so you can do this:
pid_t pid, pid_c;
pid = fork();
if (pid == -1) { // error
perror("Falied to fork");
} else if(pid == 0) { // execute in child process
// you can get child's pid by getpid() in child process:
pid_t tmp_pid_c = getpid();
execl("bin/ls", "ls", "./", NULL);
} else {
// you can also get child's pid that already returned by fork() in parent process
pid_c = pid;
}
There are two main functions to get the process id of parent process and child. getpid() and getppid()

using fork to do something while the child is running

So basically what i need is:
pid = fork();
if (pid == -1)
exit(1);
if (pid == 0)
{
// do stuff in child
}
else
{
// ONLY do stuff while child is running
}
would I need to create a tmp file right before the child exits saying that it is no longer running so the parent knows the child has exited when that file exists, or is there a simpler way to do this?
You can use waitpid to know if a child process is still running:
int status;
if (waitpid(pid, &status, WNOHANG) == 0) {
// still running
}
With WNOHANG, waitpid returns immediately so that the program can do something else.
When you have nothing to do other than waiting for the child process to terminate, call waitpid without WNOHANG.
The standard way to know that the child has terminated (and get its exit code) is to use the waitpid() system call.
Check wait () and waitpid () : http://linux.die.net/man/2/wait
Here is some more resource: http://users.actcom.co.il/~choo/lupg/tutorials/multi-process/multi-process.html#child_death_wait_syscall
There's a bunch of ways to do it. If you don't need to do anything with the child output, you can set a SIGCHLD handler to reap the child when it exits, and then forget about it in your main thread of execution. You can use the SIGCHLD handler to flag the exit of the child process via an IPC mechanism.
Or you can add a while loop that checks waitpid in your else clause. You would be doing discrete units of work between polls of the child state and you wouldn't get interrupted immediately on child exit.
Use the system wait() call if you just need to check if the child has stopped running.
int pid;
int status;
while (true)
{
pid = wait(&status);
if (pid < 0)
//keep waiting
else if (pid == 0)
//child is done
}

What exactly does fork return?

On success, the PID of the child
process is returned in the parent’s
thread of execution, and a 0 is
returned in the child’s thread of execution.
p = fork();
I'm confused at its manual page,is p equal to 0 or PID?
I'm not sure how the manual can be any clearer! fork() creates a new process, so you now have two identical processes. To distinguish between them, the return value of fork() differs. In the original process, you get the PID of the child process. In the child process, you get 0.
So a canonical use is as follows:
p = fork();
if (0 == p)
{
// We're the child process
}
else if (p > 0)
{
// We're the parent process
}
else
{
// We're the parent process, but child couldn't be created
}
p = fork();
/* assume no errors */
/* you now have two */
/* programs running */
--------------------
if (p > 0) { | if (p == 0) {
printf("parent\n"); | printf("child\n");
... | ...
Processes are structured in a directed tree where you only know your single-parent (getppid()). In short, fork() returns -1 on error like many other system functions, non-zero value is useful for initiator of the fork call (the parent) to know its new-child pid.
Nothing is as good as example:
/* fork/getpid test */
#include <sys/types.h>
#include <unistd.h> /* fork(), getpid() */
#include <stdio.h>
int main(int argc, char* argv[])
{
int pid;
printf("Entry point: my pid is %d, parent pid is %d\n",
getpid(), getppid());
pid = fork();
if (pid == 0) {
printf("Child: my pid is %d, parent pid is %d\n",
getpid(), getppid());
}
else if (pid > 0) {
printf("Parent: my pid is %d, parent pid is %d, my child pid is %d\n",
getpid(), getppid(), pid);
}
else {
printf("Parent: oops! can not create a child (my pid is %d)\n",
getpid());
}
return 0;
}
And the result (bash is pid 2249, in this case):
Entry point: my pid is 16051, parent pid is 2249
Parent: my pid is 16051, parent pid is 2249, my child pid is 16052
Child: my pid is 16052, parent pid is 16051
If you need to share some resources (files, parent pid, etc.) between parent and child, look at clone() (for GNU C library, and maybe others)
Once fork is executed, you have two processes. The call returns different values to each process.
If you do something like this
int f;
f = fork();
if (f == 0) {
printf("I am the child\n");
} else {
printf("I am the parent and the childs pid is %d\n",f);
}
You will see both the messages printed. They're being printed by two separate processes. This is they way you can differentiate between the two processes created.
This is the cool part. It's equal to BOTH.
Well, not really. But once fork returns, you now have two copies of your program running! Two processes. You can sort of think of them as alternate universes. In one, the return value is 0. In the other, it's the ID of the new process!
Usually you will have something like this:
p = fork();
if (p == 0){
printf("I am a child process!\n");
//Do child things
}
else {
printf("I am the parent process! Child is number %d\n", p);
//Do parenty things
}
In this case, both strings will get printed, but by different processes!
fork() is invoked in the parent process. Then a child process is spawned. By the time the child process spawns, fork() has finished its execution.
At this point, fork() is ready to return, but it returns a different value depending on whether it's in the parent or child. In the child process, it returns 0, and in the parent process/thread, it returns the child's process ID.
Fork creates a duplicate process and a new process context. When it returns a 0 value it means that a child process is running, but when it returns another value that means a parent process is running. We usually use wait statement so that a child process completes and parent process starts executing.
I think that it works like this:
when pid = fork(), the code should be executed two times, one is in current process, one is in child process.
So it explains why if/else both execute.
And the order is, first current process, and then execute the child.

Waiting for execvp in main

int main()
{
...
if(!fork())
{
execvp(cmdName,cmdParam);
}
printf("In main()...");
return(0);
}
Assuming I have correctly passed the cmdName & cmdParam arguments, how do I wait for the process created by execvp to finish, before resuming the execution of main()?
Does the execvp() create a process which is a child of the newly fork()ed process?
In the parent process, fork returns the PID of the child process, so you can store that in a variable, and then use waitpid to wait for the child process to terminate.
Not really - the new child process created by fork is a duplicate of the parent, and execvp then replaces its process image with a new image. Effectively you initially have two 'copies' of the parent, one of which then 'becomes' the new program.
As noted you need to save the value of the fork call. You should really use more than an if on the fork. There are three cases:
0: you're the child process
0: you're the parent and got a child PID back
-1: something horrible happened and fork failed
You really want to know about case 3, it'll ruin your whole day. (also the exec call)
int main() {
int pid = fork();
if(-1 == pid) {
fprintf(stderr, "Big problems forking %s\n", strerror(errno);
exit(-1);//or whatever
}
else if (0 == pid) {
if (-1 == execvp(cmdName,cmdParam)) {
//like above, get some output about what happened
}
}
//no need to else here, execvp shouldn't return
// if it does you've taken care of it above
waitpid(pid, NULL, 0);
printf("Resuming main()...");
}
return(0);
}
For your first question:
Use waitpid(2) like this:
int pid = fork();
if (!pid)
{
execvp(cmdName, cmdParam);
}
waitpid(pid, NULL, 0);
printf("Resuming main()...\n");
For the second part: all exec function calls take the process over (none of them return)
You need to store the return value of fork(), which returns a different value to each executable (0 if you are the child PID if you are the parent), and then you need to do a waitpid

Resources