Midterm exam
Oct. 15, 1998.
Instructions
createProcess(char *prog, char *arg1, char *arg2, ... (char *) NULL)
This function creates a process with the text of the program specified by the first argument and begins execution by supplying the remaining arguments. Explain the justification for this new function, specifically, what inefficiency does it address? Then, argue against this function and explain why we would not want it to replace the fork() and execlp() calls.
The inefficiency of fork() is that it must copy the entire
address space of the parent into a new area of memory allocated to
the child. In the case that the child simply goes on to execlp()
a new process, this effort is wasted, as the address space will be replaced
by the execlp() call. However, as we learned from
the readings, the point of keeping these two calls separate is that
the child often needs to manipulate file descriptors inhereted from the parent
before replacing the process image,
for instance, opening as stdin a file created by the parent.
A simple example illustrates this:
...
datafd=open("datafile", O_RDWR|O_CREAT, 0644);
...
/* Some data is written by the parent to the file */
...
if (fork()==0)
{
close(STDIN_FILENO); /* Only child's stdin is closed */
open("datafile", O_RDONLY);
execlp("sed", "sed", (char *)0);
perror("sed");
}
which, of course, is more elegantly handled using the dup2() call.
exit RUNNING -----------> EXITED ^ | \ | | \______ request dispatch | |timeout \_____ | | \ admit | v complete v NEW ----------> READY <----------- BLOCKED ^ | ^ | | | activate | |susp activate | | susp | | | | | | | v complete | v SUSP READY <-------- SUSP BLOCKEDThe suspend-blocked state is used when the address space of a process is copied from the more valuable (and in high demand) main memory to external storage while it waits on a resource request. Once the request is satisfied, the process can be moved to the suspend-ready state with minimal overhead. Differentiating these two states permits the scheduler to swap back to main memory (activate) a process that is known to be ready for the CPU rather than one that is still blocked on a resource request.
The suspend and activate transitions between blocked and suspend-blocked permit a parent process to control the operation of a child through requests to the process manager, regardless of whether the child is blocked on a resource request. If the child is blocked and suspended, the parent may still swap it back to main memory (activate it), thus allowing the child to continue once the resource request is satisfied.
1 #include <stdio.h> 2 #define LINE_LEN 50 3 main (int argc, char *argv[]) { 4 int i, n, child_pid, c2p[2]; 5 int nbytes, total_bytes_read; 6 char buf[LINE_LEN]; 7 n = argv[0]; 8 total_bytes_read = 0; /* initialize variable */ 9 for (i = 0; i <= n; i++) { 10 child_pid = fork(); 11 if (!child_pid) { 12 /* I am the child: create a pipe to parent */ 13 pipe (c2p); 14 /* fill buf with string of form: */ 15 /* "Fib(13) = 377" */ 16 Fibonacci (buf, i); 17 nbytes = write (c2p, (void *)buf, strlen(buf)); 18 } 19 else { 20 /* I am the parent: read from child */ 21 nbytes = read (c2p, (void *)buf, LINE_LEN); 22 printf ("%s\n", buf); 23 } 24 total_bytes_read += nbytes; 25 } 26 printf ("I read a total of %d bytes\n", total_bytes_read); 27 }Problems are as follows:
void ContextSwitch () { SAVE_REGS(); /* save all registers on the stack */ SAVE_CONTEXT(); /* save PC (%i7) and SP (%i6) of invoking proc. */ QueueInsert(Active, ReadyQueue); Active = QueueDelete( ReadyQueue ) ; Active->inqueue = NULL ; RESTORE_CONTEXT(); /* set subroutine return address (PC of caller) * and current frame pointer (SP of caller) * from newly selected Active thread */ RESTORE_REGS(); /* load 'in' and 'local' regs from stack */ return; }There are two serious problems with this implementation. First, restoring all the 'in' and 'local' registers from the stack after RESTORE_CONTEXT() means that the register values set by RESTORE_CONTEXT() (i.e., %i7 and %i6) will be overwritten immediately. Thus, this version of ContextSwitch() will not perform a context switch at all!
Simply reversing the order of RESTORE_CONTEXT() and RESTORE_REGS() will work, but is dangerous. If any local variables are declared within the function (they aren't here, but they could conceivably be introduced), their values are likely to be incorrect. Remember, the actual context switch doesn't occur until the function returns, thus replacing PC and SP with the values saved in %i7 and %i6 by RESTORE_CONTEXT(). If RESTORE_REGS() is invoked any time prior to the return statement, the register values that will be restored are the same ones that were just saved above the current stack pointer, not those of the new Active thread. Remember, the stack pointer itself doesn't get updated until the function returns.
The correct solution requires that SAVE_REGS() and RESTORE_REGS() be performed in the calling function, as follows. This ensures that the local register values are restored from the correct stack pointer at the right time. Note that the in registers of CallingFunction() are already restored by the return from ContextSwitch(), so RESTORE_REGS() could be simplified to avoid this redundancy if it were only needed by this one function.
CallingFunction() { ... SAVE_REGS(); /* save all registers on the stack */ ContextSwitch(); RESTORE_REGS(); /* load 'in' and 'local' regs from stack */ ... } void ContextSwitch () { SAVE_CONTEXT(); /* save PC (%i7) and SP (%i6) of invoking proc. */ QueueInsert(Active, ReadyQueue); Active = QueueDelete( ReadyQueue ) ; Active->inqueue = NULL ; RESTORE_CONTEXT(); /* set subroutine return address (PC of caller) * and current frame pointer (SP of caller) * from newly selected Active thread */ return; }
Ken Starr arranges for Linda Tripp to pay a visit to Ms. Lewinsky, and while there, she surreptitiously presses the toggle buttons on all 100 listening devices. However, the independent council is worried that Tripp might have missed some of the buttons, so he sends in a second agent, who toggles every second listening device, i.e., numbered 2, 4, 6, .. 98, 100.
Obviously, this backfires. With only half of the devices now working, Starr misses portions of Monica's better conversations. Worried that this may affect the commercial success of his planned RealAudio web site release of the transcripts, he sends in a third agent, who toggles every third listening device, i.e., numbered 3, 6, 9, ... 96, 99, then another agent, who toggles every fourth device, i.e., 4, 8, 12, ... 96, 100, and so on and so on, until the final, hundredth agent, simply toggles the 100th listening device.
Assuming that Ms. Lewinsky conducts most of her intimate conversations with the president on a telephone covered by listening devices 70 through 80 (inclusive), will Ken Starr's web site be a success?
The answer to this question was actually discussed in class in relation to the largest divisor needed to verify primality of a candidate prime. Hint: Take a number and write out its list of factors. Then consider how the number of factors relates to whether or note the listening device will be turned on.