CS644 Midterm Review

Note: some discussion at the start of class is in the notes for last class.

Handout: Practice Midterm. Solution will be posted Sunday.

Fork example, like problem on practice midterm:

char *s = “abc”;

int main()

{

   int pid;

   if (pid = fork()) {

      *s = ‘A’;   /* change a to A */

      printf(s);

   }

   printf(pid = %d, s = %s\n”);

   return 0;

}

 

Here

·         s is an external/global variable, held in the data area, along with the string “abc”.

·         pid is a local variable, held on the stack.

 

At the fork, the whole address space is copied to make the child (in effect, anyway). Only the parent changes a to A in its copy of the string in the data area. We cannot be sure which process runs first (or with multiple CPUs, whether they run at the same time on two CPUs.)

 

Output, assuming the child pid is 4036 and each output from write comes out intact (this is a simplifying assumption so that we don’t have to discuss too many different forms):

 

If parent runs first, then child:

Abcpid=4036, s = Abc

pid=0, s = abc

 

If child runs first, then parent:

pid=0, s = abc

Abcpid=4036, s = Abc

 

If parent runs, and the child runs soon enough to output between the two parent outputs:

Abcpid=0, s = abc

pid=4036, s = Abc

 

Question: could the parent or child block during their write?

Answer: not with this tiny amount of output. The OS has a buffer, so it can accept maybe 128 bytes before needing to block the write syscall (while it drains the buffer by a sequence of interrupt handler runs).

 

Book coverage:

Comer: Chap 1, Chap 6 pp. 81-82, 86-87, Chap 8 to 8.3: note that getmem() is used in hw2 solution, like malloc would be used in a UNIX program, Chap 11 to 11.3 i/o abstract operations.

Love: Chap 1, Chap 5, Chap 6 to pg. 77, summary pg. 92, Chap.  10 through pg. 161, pg. 260

Review by Topics

I.                    Above the OS: the virtual machine

Definition of process: program in execution

Each process is given a virtual machine, with

·         one or more virtual CPUs (multiple CPUs in use requires use of threads)

·         a flat address space

·         access to system services via syscalls, often via library functions (the C library and other libraries exist as part of the user virtual machine)

Flat address space: each byte of memory usable by the process has an address unique to the process, a 32-bit address on a 32-bit platform, or a 64-bit address on a 64-bit platform. These addresses occur in sequences, creating areas of virtual memory.

Note: these addresses are not unique across processes. For example, address 0x10000 may easily be in use by many different processes running on the system. Only one user process is current on a CPU at a particular point in time, however.

 

 

                Memory Layout: Look at hw1 (solution is online), Love, pg. 260. hw1 also has proof that a syscall executes as a single instruction in the user code.

                Process creation, blocking, coordination:

o    Compare Xinu create and UNIX* fork

o    Blocking: a process waiting but not using CPU, compare to “busy-waiting”, looping in place

o    Unblocking: the event that the process was waiting for has happened, and the OS knows about it (often because of an interrupt), and unblocks the process.

o    Process coordination: to get work done with multiple processes, we often need a process to block until something is available for it. Major examples of producer-consumer (bounded buffer) and mutex.

o    We studied semaphores as an example of syscalls providing process coordination services.

o    Xinu semaphores: simplest API: screate, wait, signal, .... Should understand prod-cons.c and mutex as in hw2.

o    UNIX* POSIX semaphores: same functionality, different API, count range. Should understand producer-consumer and mutex as in hw2.

 

II.                  Below OS: Hardware

general hardware: how a register holds bits

x86 hardware we covered: UARTs, timer 0, PIC, CPU

 

UARTs: has registers: RX, TX, LSR (with DR and THRE bits), IER, all 8-bit registers.

·         has ports assigned: COM2 (Tutor console under mtip) has baseport 0x2f8, and interrupts on IRQ3

·         we assume Tutor does initialization for us

·         mystery of ports and device registers: RX and TX are both accessed via port 2f8: how can this be?

o    answer: we can only read RX, and inb from 2f8 reads RX register

o    we can only write TX, and outb to 2f8 writes TX register

o    (the device can easily tell a read bus cycle from a write bus cycle)

·         remember that in a receiver interrupt handler, we must read RX even if we don’t want the character, because the receiver device needs the acknowledgement to allow it to go on to handle the next char.

 

Is there another case like this, where we must acknowledge the hardware to get it go on to the next event?

Yes—the PIC must be acknowledged by sending it an EOI command in the interrupt handler, so that it can go on to handle the next interrupt to be sent in to the CPU.

Timer 0: 8-bit count port, 8-bit control register and port for it.

The timer contains a 16-bit counter, and is always down-counting it from some initial count. When it hits 0, it generates an interrupt that is IRQ0, the highest priority interrupt. The initial down-count can be programmed in the timer, and determines the length of the tick (interval between timer 0 interrupts), up to 55 ms.

Mystery: how can we set the 16-bit initial count using an 8-bit port (plus the control register)?

Answer: by a little hardware protocol: outb command, then outb one half, then other half of 16-bit initial count to the count port. The timer assembles the halves into a 16-bit holding register before loading the main timer.

III.               System Calls: very recent, see notes.