Creating a child process WITHOUT fork() - c

Is there a way to start a child process without fork(), using execvp() exclusively?

The pedantic answer to your question is no. The only system call that creates a new process is fork. The system call underlying execvp (called execve) loads a new program into an existing process, which is a different thing.
Some species of Unix have additional system calls besides fork (e.g. vfork, rfork, clone) that create a new process, but they are only small variations on fork itself, and none of them are part of the POSIX standard that specifies the functionality you can count on on anything that calls itself a Unix.
The slightly more helpful answer is that you might be looking for posix_spawn, which is a library routine wrapping fork and exec into a single operation, but I find it more troublesome to use that correctly than to write my own fork+exec subroutine. YMMV.

posix_spawn is the only posix compliant way to create a child process without calling fork directly. I say 'directly' because historically posix_spawn would itself just call fork, or vfork. However, that is no longer the case in GNU/linux. posix_spawn itself may be more efficient than fork, in addition to perhaps being a stronger fit conceptually when code is attempting to run a different executable.
If you aren't worried about portability, you can abandon posix and couple yourself directly to the kernel you are targeting. On linux the system call to create a child process is clone. At the time of this answer the manual page provides documentation for three variants, including the relatively new clone3.
I believe you can take the example from the manual page and add an execvp call to childFunc. I have not tried it yet, though!

Unlike Windows systems, where creating a new process and executing a new process image happen in a single step, Linux and other UNIX-like systems do them as two distinct steps.
The fork function makes an exact duplicate of the calling process and actually returns twice, once to the parent process and once to the child process. The execvp function (and other functions in the exec family) executes a new process image in the same process, overwriting the existing process image.
You can call execvp without calling fork first. If so, that just means the currently running program goes away and is replaced with the given program. However, fork is the way to create a new process.

As user zwol has already explained, execve() does not fork a new process. Rather, it replaces the address space and CPU state of current process,
loads the new address space from the executable filename and starts it from
main() with argument list argv and environment variable list envp.
It keeps pid and open files.
int execve(const char *filename,char *const argv [],char *const envp[]);
filename: name of executable file to run
argv: Command line arguments
envp: environment variable settings (e.g., $PATH, $HOME, etc.)

posix_spawn. But it ignores failures of execvp() -- potentially because implementing this was regarded as too complicated.

Related

Linux: write() not working after execlp() in C [duplicate]

the man page says that "The exec() family of functions replaces the current process image with a new process image." but I am not quite understand the meaning of "replaces the current process image with a new process image". For example, if exec succeed, perror would not be reached
execl("/bin/ls", /* Remaining items sent to ls*/ "/bin/ls", ".", (char *) NULL);
perror("exec failed");
Correct. If the exec works, the perror will not be called, simply because the call to perror no longer exists.
I find it's sometimes easier when educating newcomers to these concepts, to think of the UNIX execution model as being comprised of processes, programs and program instances.
Programs are executable files such as /bin/ls or /sbin/fdisk (note that this doesn't include things like bash or Python scripts since, in that case, the actual executable would be the bash or python interpreter, not the script).
Program instances are programs that have been loaded into memory and are basically running. While there is only one program like /bin/ls, there may be multiple instances of it running at any given time if, for example, both you and I run it concurrently.
That "loaded into memory" phrase is where processes come into the picture. Processes are just "containers" in which instances of programs can run.
So, when you fork a process, you end up with two distinct processes but they're still each running distinct instances of the same program. The fork call is often referred to as one which one process calls but two processes return from.
Likewise, exec will not have an effect on the process itself but it will discard the current program instance in that process and start a new instance of the requested program.
This discard in a successful exec call is what dictates that the code following it (perror in this case) will not be called.
It means your current process becomes the new process instead of what it was. You stop doing what you're doing and start doing,really being, something else instead, never to rebecome what that process once was.
Instead of starting a whole new process, however, your current pid and environment become the new process instead. That let's you setup things the way the new process will need it before doing the exec
You are correct. perror will not be called unless the execl fails. The exec functions are the means for starting new processes in a POSIX compliant OS (typically combined with a fork call). Maybe an example will help. Suppose your program, call it programX, is running. It then calls one of the exec functions like the one you have above. programX will no longer exist as a running process. Instead, ls will be running. It will have the same exact PID as programX, but pretty much be a whole new process otherwise.

why the exec() family of functions doesn't execute the code after exec()?

the man page says that "The exec() family of functions replaces the current process image with a new process image." but I am not quite understand the meaning of "replaces the current process image with a new process image". For example, if exec succeed, perror would not be reached
execl("/bin/ls", /* Remaining items sent to ls*/ "/bin/ls", ".", (char *) NULL);
perror("exec failed");
Correct. If the exec works, the perror will not be called, simply because the call to perror no longer exists.
I find it's sometimes easier when educating newcomers to these concepts, to think of the UNIX execution model as being comprised of processes, programs and program instances.
Programs are executable files such as /bin/ls or /sbin/fdisk (note that this doesn't include things like bash or Python scripts since, in that case, the actual executable would be the bash or python interpreter, not the script).
Program instances are programs that have been loaded into memory and are basically running. While there is only one program like /bin/ls, there may be multiple instances of it running at any given time if, for example, both you and I run it concurrently.
That "loaded into memory" phrase is where processes come into the picture. Processes are just "containers" in which instances of programs can run.
So, when you fork a process, you end up with two distinct processes but they're still each running distinct instances of the same program. The fork call is often referred to as one which one process calls but two processes return from.
Likewise, exec will not have an effect on the process itself but it will discard the current program instance in that process and start a new instance of the requested program.
This discard in a successful exec call is what dictates that the code following it (perror in this case) will not be called.
It means your current process becomes the new process instead of what it was. You stop doing what you're doing and start doing,really being, something else instead, never to rebecome what that process once was.
Instead of starting a whole new process, however, your current pid and environment become the new process instead. That let's you setup things the way the new process will need it before doing the exec
You are correct. perror will not be called unless the execl fails. The exec functions are the means for starting new processes in a POSIX compliant OS (typically combined with a fork call). Maybe an example will help. Suppose your program, call it programX, is running. It then calls one of the exec functions like the one you have above. programX will no longer exist as a running process. Instead, ls will be running. It will have the same exact PID as programX, but pretty much be a whole new process otherwise.

how many ways we can create a process in linux using c

I have confusion in creating a process in Linux. Up to now I thought that we can create the process by calling the following system calls.
system()
exec() family of system call
fork() system call
but:
system(): But as "system" system call executing the input executable on shell and shell is creating a child process for the execution of input .here shell is calling child process then we can say that fork is creating process for this.
exec family of system call: As this family of system call over write the current running process with new process.So it is also creating a new process but using same address space. As I think it is also calling call fork for creating the process.
I am confused with the fact all the above is possible way of creating a new process or only fork system.
exec family of system call does not call fork, neither it creates a new process.
It only overwrites the existing process with the new binary.
In linux user programs, fork is the only function to create new process. Though fork internally calls clone and other system calls.
In other hands, system is only a wrapper to fork and exec. The actual task of creating a process is done by fork in system. So system is not a way to create new process.
fork() creates a copy of your process. This is where you actually create a process in a POSIX environment like Linux. To precisely answer your question title, fork() is the only way to create a process.
What exec() does for you is then to replace a process (for example the process you just created with fork()) by another process, so exec() doesn't itself create a process but is often accompanied with fork(), since you usually want to create another process that is different from your current one.
Underneath the system() call, there's just a fork() followed by an exec(), so it's not a new way of creating a process.
In POSIX environment, You can create a process though fork system call without any exception. Fork will create a process.
exec family of function just load binary of other program to the address space of current process(which call the exec() system call).
In system() it is internally use fork() followed by exec()system call.
There is only two ways to create a new process: the system calls fork and clone.
The other functions mentioned, fall into two categories:
exec() family: These replace the contents of a process with some other program. Usually exec() is used right after a call to fork or clone to turn one of the resulting processes into a process of the desired application. When a bash executes a gcc command, for instance, it first forks itself, then it makes one of the two resulting bash processes into a gcc process using the exec() family.
system() family: These encapsulate a fork/clone system call and a corresponding exec() call, possibly doing fancy stuff like connecting stdin and stdout, etc.
Note that all of these functions fork(), clone(), exec(), system(), etc. are system call wrappers defined by the standard C library (which is always present), not the system calls themselves. As such, counterintuitively, fork() is a wrapper for the clone system call on current systems. Not that it matters much. However, the C library functions are standardized, the system calls are not.
Historically, fork is the older system call. While it is very easy to define and use its semantics, it always suffered from its performance implications: The entire process environment needs to be (at least logically) copied, however, most of this work is for nothing, as one of the resulting processes is usually completely overwritten by an exec call. Also, the fork semantics do not allow for thread creation. Due to these shortcomings, the clone call was introduced, which allows fine grained control on what is copied, and what is shared between the two processes, allowing pthreads to be implemented in terms of clone.
In addition of all the other answers, and to be picky, processes are created by fork(2) (or the obsolete vfork(2)...) and clone(2) syscalls (and no, the execve(2) syscall don't create a process, but overwrite its address space and state by starting a new program in the same process), but some processes are "magically" created by the kernel, notably:
/sbin/init is started by the kernel at startup (if not found, some other programs are tried, even /bin/sh ....); this is the process of pid 1 at is is started quite early...
Some kernel processes (or kernel threads) are started by the kernel, like kswapd, kworker (see this question), etc... I have more than 50 kernel processes or tasks
The Linux kernel is also sometimes starting user processes from kernel land, notably hotplug(8), modprobe, etc... See also udev etc...
Almost all processes are started by fork (or clone ...) and are descendants of /sbin/init (or the process of pid 1). (But modprobe or hotplug could be started by the kernel, and they usually fork other processes).
Process creation (thru fork etc....) is quite efficient. A shell is forking almost every command (except the builtin ones, like cd or ulimit...); clone is necessary for multi-threading (but can be used as a replacement of fork...)
Notice that system(3), popen(3) are library functions (not system calls, which are listed in syscalls(2) ...) calling both fork and execve (on /bin/sh ...) and that daemon(3) is a library function calling fork (twice) etc...
Use strace(1) (to find out which syscalls a program is executing) and read Advanced Linux Programming
These days, recent Libc are using clone more than fork (and some are not calling the fork syscall any more but only clone); you can have several libc, eg MUSL libc in addition (or in replacement) of GNU libc

Process tree, how to find if a said process is the root one?

I have a directory monitoring application which works recursively by launching new processes.
I'd like to know if I'm the "root" process in this tree. I thought about trying to get the name of the caller process and check if it's the same as argv[0].
Is there a smarter way of doing this? Keep in mind, this is a Linux app.
Keep in mind, I don't have much time for this and I'm but a student, so a simple solution would be great.
Thanks for your time.
If you use fork() to create new processes, you can have a local variable initially set at zero that each child sets to 1 immediately after forking. Only the root process would still have it set at zero after a fork.
You could even increase it after each fork, which would let you know how deep in your process tree each process is.
EDIT:
If you cannot use this (e.g. because you do an exec() after fork), you can use any of the common ways that shells use to pass information to the programs that you launch:
Environment variables: call setenv() after fork() but before exec() - or add it in the environment when calling exec().
Use a special command line argument.
Use a special value for argv[0] when doing exec().
Have you the possibility to add an argument meaning "I'm not the root"? That seems the simplest approach.
If you are calling exec, add a special argument, or environment variable called "I_AM_NOT_THE_ROOT" which the child processes get, but the parent does not.
I recently used a command-line argument for this, but env variables might be more convenient.

In a process using lots of memory, how can I spawn a shell without a memory-hungry fork()?

On an embedded platform (with no swap partition), I have an application whose main process occupies most of the available physical memory. The problem is that I want to launch an external shell script from my application, but using fork() requires that there be enough memory for 2x my original process before the child process (which will ultimately execl itself to something much smaller) can be created.
So is there any way to invoke a shell script from a C program without incurring the memory overhead of a fork()?
I've considered workarounds such as having a secondary smaller process which is responsible for creating shells, or having a "watcher" script which I signal by touching a file or somesuch, but I'd much rather have something simpler.
Some UNIX implementations will give you a vfork (part of the Single UNIX spec) which is exactly like fork except that it shares all the stuff with the parent.
With vfork, there are a very limited number of things you can do in the child before calling exec to overwrite the address space with another process - that's basically what vfork was built for, a minimal copy version of fork for the fork/exec sequence.
If your system has an MMU, then usually fork() is implemented using copy-on-write, which doesn't actually allocate more memory at the time fork() is called. Additional memory would only be allocated if you write to any of the pages shared with the parent process. An exec() would then discard those pages.
If you know you don't have an MMU, then perhaps fork() is indeed implemented using an actual copy. Another approach might be to have a helper process that is responsible for spawning subshells, which you communicate with using a pipe.
I see you've already accepted an answer, but you may want to read about posix_spawn and use if it if it's available on your target:
http://www.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html
It sounds as if the prudent move in this case is to port your shell script (if possible) to C, and executing it within the process; so you don't have to fork at all.
Then again; I don't know what you are actually trying to do.
Instead of forking your process to spawn a shell, launch a shell within your process (in foreground) then fork it within the shell.
system("/bin/ash /scripts/bgtask");
with /scripts/bgtask being:
/bin/ash /scripts/propertask &
This way you double only the memory used by the shell, not by the main program. Your main program goes busy for duration of spawning the two shells: original to start bgtask and the background clone launched by it, then the memory allocated by the first shell is free again.

Resources