Wednesday, September 8, 1993 Today: More on processes (chapter 4) ------------------------------------------------------------------------------- Process Control Block (PCB) see last time's notes Process table: collection of all process control blocks for all processes. E.g., fixed size array in Unix. --- Process creation: Brand new process: - load code and data into memory - create (empty) call stack - create (or assign) and initialize PCB - make process known to dispatcher [Dispatcher: that portion of OS that manages the running of processes (more later) run process for a while; save environment; load another process ...] --- Second approach, fork (as in Unix) - make sure process isn't running and has information saved in PCB - Make *copy* of exisiting process (except pid, ppid, locks, pending interrupts etc.). Copies code, data, stack - copy PCB of source into new process - make process known to dispatcher But how do you distinguish parent and child actions? Don't want to just duplicate everything! if(childpid=fork()) { /* parent's code */ } else { /* child's code */ } Further options: parent executes concurrently with child (as in this example) parent waits for all children to terminate (wait() call) Both are running duplicate of code. Unix permits new executable image with (e.g.) execve(path,argv,envp) system call [envp==environment pointer, i.e., shell variables] Shell is example of this. Fork process, exec new command for child. Resource questions: does child share resources with parent or get new allocation [e.g., CPU time, memory, files, I/O devices] In Unix, child shares I/O descriptors initially (gets own copy) but for most resources competes with other processes equally (e.g., memory) --- Process termination: - Due to either process' own volition or system call from parent or root (abort) [resource allocation exceeded, task no longer required, etc.] - To do this parent needs to know identity of children and to be able to inspect their state (fork returns child's pid and waitpid() to inspect state in Unix) - On termination resources returned to system or parent (depending on allocation scheme) - Cascading termination: parent termination causes all children to terminate - Orphan processes (if not cascading; in Unix, parent becomes pid 1) - Zombie processes (parent waiting for blocked children to terminate) ------------------------------------------------------------------------------- When process isn't running, information about it must be saved in the PCB. Save anything the next process might need to reuse (or might damage) - Program counter - Processor status word (PSW) [condition codes, etc.] - Registers How about memory? three of many alternatives: (1) trust next process; (2) world swap (move everything to disk as in Alto); (3) Rely on memory protection (other process uses different segment) Note that these mechanisms have to be careful because don't want to trash the information they want to save (e.g., registers) ------------------------------------------------------------------------------- Independent process: cannot affect or be affected by the other processes executing in the system - no shared state with other processes (e.g., file system) - execution is deterministic; depends only on input state so execution is reproducible (given same input) so execution can be stopped and restarted without ill effects Cooperating process: process can affect or be affected by other processes executing in system - state shared among other processes - result of execution cannot be predicted in advance because it depends on relative execution sequence - result of execution is nondeterministic: can vary with same input ------------------------------------------------------------------------------- Next: process scheduling