Next: Virtual
Memory Up: Experience
With Nachos Assignments Previous: Synchronization
Multiprogramming
-
The Nachos Fork and Exec routines have completely different
semantic from the Unix system calls. In particular, the Nachos system calls
do the following:
-
Exec
-
Creates a new address space, reads a binary program into it, and then creates
a new thread (via Thread::Fork) to run it. Note that in Unix separate
fork
and exec system calls are needed to achieve the same result.
-
Fork
-
Creates a new thread of control executing in an existing address space.
This is a non-trivial system call to implement (for reasons discussed later).
-
When a Nachos program issues an Exec system call, the parent process
is executing the code associated with the Exec call. At some point
during the Exec call, the parent will need to invoke Thread::Fork
to create the new thread that executes the child process. Careful thought
is required in deciding at what point the Fork operation should
be done. Specifically, after Fork, the (new) child thread can no
longer access variables associated with the parent process. For example,
if the parent copies the name of the new file to be executed into a variable,
then issues a Fork, expecting the child to open that file, a race
condition exists. If the child runs after the parent, the parent
may already have deleted (or changed) the variable holding that file name.
The above race condition appears in a number of similar contexts where
two processes exchange data. The problem is that the parent and child threads
need to synchronize with each other, so that the parent doesn't reclaim
or reuse memory before the child is finished accessing it.
-
When the MIPS simulator ``traps'' to Nachos via the RaiseException
routine, the program counter (PCReg) points point to the instruction that
caused the trap. That is, the PCReg will not have been updated to point
to the next instruction. This is the correct behavior. When the fault is
due to (say) a page missing, for example, the faulting instruction will
need be re-executed after the missing page is brought into memory. If PCReg
had already been updated, there would be no way of knowing which instruction
to re-execute.
On the other hand, when a user program invokes a system call via the
``syscall'' instruction, re-executing that instruction after returning
from the system call leads to an infinite system call loop. Thus, as part
of executing a system call, the exception handler code in Nachos needs
to update PCReg to point to the instruction following the ``syscall'' instruction.
Updating PCReg is not as trivial as first seems, however, due to the possibility
of delayed branches. The following code properly updates the program counter.
In particular, not properly updating NextPCReg can lead to improper execution.
pc = machine->ReadRegister(PCReg);
machine->WriteRegister(PrevPCReg, pc);
pc = machine->ReadRegister(NextPCReg);
machine->WriteRegister(PCReg, pc);
pc += 4;
machine->WriteRegister(NextPCReg, pc);
Use of the following test programs greatly helped convince me that my implementation
was (finally) correct:
-
ConsoleA
-
Simple program that simply loops, writing the character 'A' to the console.
Likewise, ConsoleB loops, printing the character 'B'.
-
shell
-
The provided shell starts a process and then issues a ``Join'' to wait
for it to terminate. This test multiprogramming in a very rudimentary fashion
only, because the shell and the invoked program rarely execute concurrently
in practice.
Modify the shell so that it can run jobs in background. For example,
if the first character of the file is an ``&'', start the process as
normal, but don't invoke a ``Join.'' Instead, prompt the user for the next
command.
With the modified shell, run the ConsoleA and ConsoleB
programs concurrently.
|
Nachos
Tutorials
Roadmap
Source Code
Introduction
Threads
Interrupts
Synchronization
System Calls
Exception Handling
Multiprogramming
File System
Networking
Tutorials
Lab 1 Tutorial
Lab 2 Tutorial
Lab 3 Tutorial
Lab 4 Tutorial
Lab 5 Tutorial
|