Reputation: 175
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t child_pid = vfork();
if(child_pid < 0)
{
printf("vfork() error\n");
exit(-1);
}
if(child_pid != 0)
{
printf("Hey I am parent %d\nMy child is %d\n",getpid(),child_pid);
wait(NULL);
}
else
{
printf("Hey I am child %d\nMy parent is %d\n",getpid(),getppid());
execl("/bin/echo","echo","hello",NULL);
exit(0);
}
return 0;
}
output:
Hey I am child 4
My parent is 3
Hey I am parent 3
My child is 4
hello
My question : Why is "hello" printed after the execution of parent process? I have started learning about vfork(). Could anyone please help me with this?
Upvotes: 3
Views: 1391
Reputation:
A piece of advice first: Don't use vfork()
. On a modern system, the advantages of using vfork()
over fork()
are tiny. The code you show can never work properly with vfork()
because it invokes undefined behavior:
POSIX.1:
The
vfork()
function has the same effect asfork()
, except that the behavior is undefined if the process created byvfork()
either modifies any data other than a variable of typepid_t
used to store the return value fromvfork()
, or returns from the function in whichvfork()
was called, or calls any other function before successfully calling_exit()
or one of theexec()
family of functions.
So by calling printf()
in your child code, your code is already undefined. Note that even a call to exit()
would lead to undefined behavior, only _exit()
is allowed.
I assume you try this on Linux, which defines the behavior of vfork()
a bit more and in a way that explains what you observe:
From the linux vfork()
manual page:
vfork()
differs fromfork(2)
in that the calling thread is suspended until the child terminates (either normally, by calling_exit(2)
, or abnormally, after delivery of a fatal signal), or it makes a call toexecve(2)
. Until that point, the child shares all memory with its parent, including the stack.
So on Linux, you can be sure that the child created by vfork()
is executed first and only by your call to execl()
(which calls execve()
internally), the parent process is allowed to continue running. That's the reason you see the parent's output after your child's output. Once the parent calls wait()
, it waits until the child finishes -- at this point, the child is replaced by echo
.
Relying on this behavior makes your program non-portable to different implementations of vfork()
. The call to printf()
is fine because Linux suspends the parent process, and the wrong call to exit()
doesn't matter here by luck: anything after an exec*()
call is unreachable anyways (those functions never return, they replace the running program)!
Because of its weird semantics and the huge risk of bugs, vfork()
was removed from POSIX in POSIX.1-2008. A safe and modern POSIX replacement for the typical usecase of a vfork()
directly followed by a exec*()
is posix_spawn()
.
All in all, you really shouldn't use vfork()
. Use fork()
instead. Remove the unreachable call to exit()
as well and your program looks fine.
Upvotes: 2
Reputation: 80914
After the parent process is executed, it goes to wait(NULL);
which blocks the parent process until the child process calls execl()
or exit
.
Therefore the child process when the parent is blocked is calling the execl()
and thus hello
is being printed in the end of the output.
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t child_pid = vfork();
if(child_pid < 0)
{
printf("vfork() error\n");
exit(-1);
}
if(child_pid != 0)
{
printf("Hey I am parent %d\nMy child is %d\n",getpid(),child_pid);
wait(NULL);
}
else
{
printf("Hey I am child %d\nMy parent is %d\n",getpid(),getppid());
execl("/bin/echo","echo","hello",NULL);
exit(0);
}
return 0;
}
If you remove execl()
the child process will go to the exit(0)
and hello
wont be printed.
Also, after execl()
is being executed it is creating a new process thus any code you write after execl()
wont be executed.
According to the man page:-
The exec() family of functions replaces the current process image with a new process image. The functions described in this manual page are front-ends for execve(2). (See the manual page for execve(2) for further details about the replacement of the current process image.)
Upvotes: 2