CreateProcess takes the following steps:
- Create and initialize the process control block (PCB) in the kernel.
- Create and initialize a new address space.
- Load the program prog into the address space.
- Copy arguments args into memory in the address space.
- Initialize the hardware context to start execution at “start”.
- Inform the scheduler that the new process is ready to run.
Unix's fork takes the following steps:
- Create and initialize the process control block (PCB) in the kernel
- Create a new address space
- Initialize the address space with a copy of the entire contents of
the address space of the parent
- Inherit the execution context of the parent (e.g., any open files)
- Inform the scheduler that the new process is ready to run
It creates a complete copy of the parent process, and the parent doesn't set up the runtime environment for the child, because the parent process trusts its own set up. The child is a complete copy of the parent except for its process id (what fork returns). A forked process continues to run the same program as its parent until it performs an explicit exec. When the child calls exec which, the new executable image into memory and runs.
How is it efficient to make a complete copy? copy-on-write. It really only copies the virtual memory map. All of the segments in the segment table are read only. If the parent or child edits the data in a segment, an exception is thrown and the kernel creates a full memory copy of that. This is explained nicely in this answer
There are several benefits to shared resources between parent and child:
- intuitively, resource management: less memory is needed to maintain the states of the processes
- Cache resources are shared means greater temporal locality of data when data is not over written, which improves performance because retrieving data from larger caches/disk is time consuming.
Disadvantages to shared resources:
- when writes are common, it puts the data in an invalid state for the other process, and this leads to coherency misses which is costly if the child process is running on a separate core, because the changes will have to propagate up to the L3 cache.
In general though, programs read a heck of a lot more than writes, typically the child/parent will only need to make writes to its stack, and that's a small portion of the their program block.
Additionally Unix fork is different because it returns twice, once in the parent (the process id of its child), once in the child (0, congrats you're a new baby process), which is how we distinguish in our code if we are the child or parent.
Unix Exec does the following:
- Load the program prog into the current address space.
- Copy arguments args into memory in the address space.
- Initialize the hardware context to start execution at “start.”
the parent has the option to wait for the child to finish. When the child finishes, when exit is called is when the parent's wait is notified.