There's only one way in Unix to start a user process - the fork(2)
system call. It creates an exact replica of the calling process, the difference being the return value of the call - process id (pid
) of the new process in the parent/caller, zero in the child. The OS maintains this parent-child relationship through parent process id property (see, for example, output of ps -f
).
What happens behind the scene is that the OS kernel duplicates the whole virtual memory space of the caller (there are more details here, google for Copy-On-Write page mapping and vfork
). There's no direct access from one address space to the other unless specifically setup via a shared memory mechanism like mmap(2)
. The parent process can wait(2)
for its children to terminate.
I'm not going to go into process groups, sessions and controlling terminals. That needs a good picture. Look into, say, APUE book for thorough explanation.
The execve(2)
system call replaces current process image with one of some executable from a file.
Now the shell has its stdin
, stdout
, and stderr
connected to a terminal emulator, inherited from login(1)
process on the console, or dynamically allocated by a network daemon like sshd
, or a window manager (X). When you type, say, vi
in the shell, it fork
s and then exec
s /bin/vi
program, then wait
s for it. The new process inherits open file descriptors and ia able to manipulate the terminal pseudo-device through them via ioctl(2)
.
The fun actually starts with pipelines, when you type something like ps -ef|grep bash
- that is left as an exercise for the reader :)
I glossed over many interesting details here, but hope this can help a bit as a brief introduction.