Processes

Friday, September 10, 2004

Processes in Unix

A program is just a file to Unix.  In other words, when a user creates a source program and then compiles it, the program resides on disk as an executable file.  The term process is used to describe a program that is actually running within the purview of Unix.  For example, when a user requests that a program be run in Unix, Unix must load the program from the executable file on disk where it resides, build appropriate data structures to keep track of that program as it runs, and then start it running.  To Unix, then, a process is just a (fairly complex) data structure in which Unix keeps all of the information about the status of the program that is running.

Process Creation in Unix:  The fork System Call

In order to begin understanding how Unix deals with processes, one must learn how Unix creates processes in the first place.  That is, how does Unix start a program (an executable file on disk) running?  We used the following two examples to discuss this.

 

In this example of Figure 1.3 we see how a program must call various functions in order to do tasks that require accessing hardware and are therefore only available through services provided by the operating system.  the printf, exit, and open are all examples of such calls.  Internally the functions accessed by these calls must have, in their machine language form, the equivalent of a TRAP instruction, which does the actual call to the Unix system service in question.

In Figure 1.4 we see an example of the fork() system call.  The fork call accesses the fork service in Unix, which

bullet

creates a new complete copy of program main, including all of its data and code areas as they exist right now as the current process for main is running.  That is, if the current process that is the code for main is P25 (the parent process), then a new process, say, P50 (the child process) is created which looks exactly like P25 right now (all of the registers, data values, etc. are the same...this is not a fresh copy of main but a copy of this process as it now is).

bullet

sets up the call stack for the newly created child process P50 to make it appear that P50 has been executed into the fork() call and is about to return from fork() with a return value of zero

bullet

sets up the call stack for the parent process P25 to have a return value that is not zero from fork()

bullet

allows either the child process or the parent process to run, putting the other on the ready to run queue.

When the child process, P50, starts running it does so by returning from the call to fork() with a return value of zero.  This means that it executes the exec1 system call, which

bullet

replaces the program and data areas of P50 with a new program (program copy in this case)

bullet

starts the new program running (copy)

When the parent process, P25,  resumes running it does so by returning from the call to fork() with a nonzero return value.  This means that P25 executes the wait system call.  This again causes a Unix service to be accessed which "puts this process to sleep" by putting its data structure into a wait queue.  When the child process (P50) finishes executing, Unix will wake up any process (including P25) that was waiting for P50 to finish and put the data structure for that process (e.g., P25) on the ready to run queue.