Reputation: 121
What exactly happens when you use exec() without calling fork(), and what are the implications and possible caveats when doing so ?
My understanding reading through the man pages is that doing exec() essentially terminates the calling process when replacing it with the new (blank) process image. The question is, whether terminating the calling process this way is a viable alternative to the regular way of using exit()
?
Maybe my google-fu is out of shape, but searching for this mostly lead to answers related to the much more common "fork() without exec()" paradigm, not the "exec() without fork()" I'm looking for.
I want to terminate the current process and execute another process.
Regular ways of doing this:
fork()
, and then immediately exec()
on the child and exit()
on the parent.
fork() is slow and as I'm exiting from the parent process immediately, I definitely do not want to duplicate the calling process before executing the callee.
vfork()
, and then immediately exec()
on the child and exit()
on the parent.
vfork() is the lighweight alternative to fork(), which can be used to create a (essentially) blank process image without unnecessarily duplicating the parent process, much akin to the CreateProcess call in Windows world. This is a much better option and would suit most use-cases.
I want to terminate the current process, then execute another process.
If I'm in extremely memory-starved conditions where even vfork()
fails, I opted for a third option of calling exec()
without a fork()
which essentially terminates the parent process by replacing it with the new one.
Let's say I have two programs, a shell script called "other" and my main program called "program". "other" is located within my PATH
, so execlp()
is used specifically and "other" called without a full path.
program.c
void bye(void) {
while(1) {
execlp("other", "other", NULL);
pause(); // we will never reach here when execlp is successful
}
}
/bin/other
!/bin/sh
echo "Do other stuff here"
In practice this seems to work fine.
However this is something I conjured up myself and I haven't seen any recommendations for spawning a process like this nor any examples of others doing so, and it leads me to believe that there might be something intrinsically "wrong" to terminate a process in this way which I've missed.
Yes, I know I could "free memory somewhere else before executing vfork() so it doesn't fail", but that wasn't the question.
Upvotes: 0
Views: 872
Reputation: 1843
exec()
doesn't terminate process, it replaces current image of process with new one. Most of process attributes are preserved in new image except attibutes listed in section Effect on process attributes in execve() manual page.
Some programs do exec()
without fork()
for modifying environment in which new program must be executed. For example nohup.
Upvotes: 1
Reputation: 5613
So fork/vfork creates a new process, then exec runs a new executable using that process id. it is up to the fork parent process to wait() for program exit to consume the zombie state of the child program.
The difference in startup times between fork and vfork is minimal with VM. On systems without VM vfork is significantly faster, but it is possible to inadvertently damage the parent process when setting up pipes, etc.
If you want to daemonise a program, then fork/exec and don't wait. You might also want to change the terminal session process group if you want the program to survive closing the terminal session.
If you exec directly, then the new executable runs in the same process ID as the launching program, and the launching program is no more. If there was a parent process waiting for this launcher program to die, it is unaware of the change of executable, and blindly continues to wait for this new executable to exit.
This is used often, for example bash -c ls
will launch bash, which will immediately execute ls, itself expiring. The parent shell will wait for this to complete, unaware that it is now waiting for /bin/ls
.
Upvotes: 0