Three possibilities can happen to the creator during process
creation:
- The child process is created and runs concurrently with the parent.
In this case, as soon as process creation is successful, the process manager
replies to the parent, and the child is made READY. If it's
the parent's turn to run, then the first thing it does is return
from the process-creation function. This may not be the case
if the child process was created at a higher priority than the
parent (in which case the child will run before the parent gets
to run again).
This is how fork(), forkpty(),
popen(), and spawn() work. This is also how the
spawn*() family of functions work when you specify a mode of
P_NOWAIT or P_NOWAITO.
- The child replaces the parent. In fact, they're not really parent
and child, because the image of the given process simply replaces that of
the caller. Many things will change, but those things that uniquely
identify a process (such as the process ID) will remain the same.
This is typically referred to as execing, since usually the
exec*() functions are used.
Many things will remain the same (including the
process ID, parent process ID, and file descriptors) with the exception
of file descriptors that had the FD_CLOEXEC flag set using
fcntl(). See the exec*() functions for more
on what will and will not be the same across the exec.
The login command serves as a good example of execing. Once
the login is successful, the login command execs into a shell.
Functions you can use for this type of process creation are
the exec*() and spawn*() families of functions, with mode passed as
P_OVERLAY.
- The calling thread in the parent waits until the child terminates.
You can make this happen by passing the mode as P_WAIT when you call one of
the spawn*() functions.
Note that what is going on underneath the covers
in this case is that spawn() is called as in the first possibility above.
Then, after it returns, waitpid() is called in order
to wait for the child to terminate. This means that you can use any of the
functions mentioned in our first possibility above to achieve the same
thing if you follow them by a call to one of the wait*()
functions (e.g., wait() or waitpid()).
Note:
Many programmers coming from the Unix world are familiar
with the technique of using a call to fork()
followed by a call to one of the exec*()
functions in order to create a process that's different from
the caller. In QNX Neutrino, you can usually achieve the same
thing more efficiently with a single call to one of the posix_spawn*()
or spawn*() functions.