CS444 Class 7

Handout: hw1 expected script using testio.sh, an mtip shell script

Short demo: running testio.sh to see the automated input happening.

 

Two kinds of code: program-level code and interrupt handler code

Hw1: one interrupt handler, assembly + C parts, makes up interrupt handler code, rest is program-level code.

 

The interrupt handler code is special because it can execute between any two instructions of the program-level code.

 

However, both kinds of code see the same CPU. The CPU doesn’t even remember it’s in an interrupt handler. It just sets IF=0, saves crucial registers on the stack, etc., and starts the interrupt handler.

 

Interrupt Handler Coding Points

 

 

Debugging Points

 

Use kprintf generously to report what’s happening.

 

Common Problem: system “goes away”, after printing some of your kprintf messages.

 

~r gets you going again, but memory info is lost.

 

 

Use kprintf generously to report what’s happening, blow by blow.  kprintf is your spy—it runs in between any two program lines, and runs immediately, no delay like we’re putting into write(). 

 

Another idea is to use the debugger, remote gdb.   It works within interrupt handlers as well as in ttyread and ttywrite.  

 

Dataflow picture, also on handout:

 

 

read     ttyread : “program” code, dequeues from input Q

                    

                                                    

               input Q

                    

                    

         input interrupt handler: enqueues into input Q and echo Q

        

        

 write     ttywrite: “program” code, enqueues to output Q

                    

                    

               output Q              echo Q

                    

                    

         output interrupt handler: dequeues from output Q (or echo queue)

 

 

Note: “program” code will become syscall code in hw2. Now it’s just the non-interrupt-handler code of our program.

 

Echoes

How about echoes?  They are generated when a char is processed in the input interrupt handler.  One copy of the char is enqueued in the input Q and another in an output echo Q, separate from the ordinary output Q.  If we put the above pictures next to each other we can draw in the echo Q next to the output Q and an arrow from the input int handler to the echo Q, and another arrow from the echo Q to the output int handler.

 

When the output int handler runs, it should first look in the echo Q, and output a char from there, or if there are no chars there, output one from the ordinary output Q.  This way users see echoes as soon as possible.

 

What if TX interrupts are off when we generate an echo—should we turn on transmitter ints then? 

Answer: Yes, there needs to be code in the receiver interrupt handler for this.

 

Note: the UART has only one IRQ for transmitter and receiver interrupts.  That means there is one interrupt handler that has to handle both input and output interrupts.  You can check for receiver data-ready, and if that’s on, do the input interrupt handling, and then, if the transmitter is ready, do the output interrupt handling.

 

 

 

Not covered in class but may be useful for hw1:

Note: don’t confuse & and &&.  When we’re working with bits we need &, the bit-wise AND, and also |, the bit-wise OR.  These operators works the same in C and Java, but are not as commonly used in Java.  Reread K&R, pp. 48-49 and 52-53 if you need review on this.

One interrupt handler: how do we tell which kind of interrupt is happening?

 

The simple-UART treatment expected in hw1 uses the LSR to discriminate between receiver and transmitter interrupts.  After all, the UART is interrupting to tell us it’s data-ready (DR on) or transmit-ready (THRE on), where DR and THRE are bits in the LSR.

 

            if (inpt(COM2_BASE + UART_LSR) & UART_LSR_DR) … receiver int case, COM2

 

Of course, in tty.c you need to use a variable for the base register.  Also note that this action does not acknowledge the interrupt, so you need to read the char in (DR on), or if THRE is on, transmit another char or turn off transmit interrupts.

 

 

 

Back to Tanenbaum to finish Chap 1.

 

UNIX system calls—we looked at write and exit earlier, now look at

fork(), the amazing parameterless UNIX process-creation system call.

 

Here is a trivial fork program, using the return value from fork to tell the parent and child apart:  The parent gets the child pid (always !=0) from fork, while the child gets back 0.

 

int main()

{

     if (fork())

printf(“hello from parent\n”);

     else printf(“hello from child\n”);

}

When you run this program, you will see one message and then the other, in either order.  Each terminates by executing the exit syscall in the startup module.

 

<Drawing of one address space, then copied second address space for the child process.>

 

After fork, while both processes exist, there is a parent-child relationship between them.  If the parent exits first, the child is an orphan, and gets assigned to process 1 as a child.  Being an orphan doesn’t affect how it runs, only how it gets cleaned up at the end.

 

Fork clones the whole process image, even the stack, so we can put in local variables and they will be copied:

 

int x_ext = 2;  /* external var, in data segment */

int main()

{

    int x_loc=6;  /* local (automatic) var, on stack */

 

   if (fork()) {

       x_loc++;

       x_ext++;

 printf(“hello from parent, x_loc=%d, x_ext = %d\n”, x_loc, x_ext);

}

else printf(“hello from child, x_loc=%d, x_ext = %d\n”, x_loc, x_ext); 

}

 

<Drawing of one address space, then copied second address space for the child process.>

<x_ext is in the data segment, x_loc is on the stack>

 

Here x_loc, a local or automatic variable, will be on the stack, = 6 in the original program image, and thus =6 in the copied image as well.  In the parent, x_loc will be incremented to 7, but this has no effect on the child. 

 

Similarly, x_ext is an external variable = 2 at the fork, so still 2 in the child’s report.

 

So you will see “hello from parent, x_loc=7, x_ext=3\n” and “hello from child, x_loc=6, x_ext=2\n” output, in either order.

 

Next time: exec system call, UNIX vs Windows system calls. Start on Chap. 2