Homework 1 Solutions

22C:116, Fall 1998

Douglas W. Jones
  1. What is your E-mail address?
    The answer depends on who you are!

  2. The Problem: Write code in C or C++, using the C standard library routines setjmp() and longjmp() to demonstrate the construction of an exception handler in C or C++ ...
    There are many answers to this question; the key is that caller of a function that might raise the exception must be able to determine what handler is to be used, and at any level in the program, a function must be able to determine a local handler. Here is one solution:
    	jmp_buf exception; /* declared globally */
    
    	void might_raise_exception()
    	{
    	    ...
    	    if (trouble) longjmp( exception, 1 );
    	    ...
    	}
    
    	void handles_exception()
    	{
    	    jmp_buf exception_save;
    	    memcpy( exception_save, exception, sizeof( jmp_buf ) );
    	    if (setjmp( exception ) == 0) {
    		...
    		MightRaiseException();
    		...
    	    } else {
    	        ... code to handle exception ...
    	    }
    	    memcpy( exception, exception_save, sizeof( jmp_buf ) );
    	}
    
    Notice that this particular solution does not package the code to handle the exception as a function; this was necessary in the Pascal solution because Pascal forced the use of function parameters to establish a dynamic exception scope because Pascal does not allow "label variables" -- that is, pointers to locations in the code. In the C solution given above, the global jump buffer is a label variable that can be adjusted so that it always points to the current exception handler.

  3. The Problem: Given what you have learned about setjmp() and longjmp(), suggest how they might be implemented.
    One possible implementation is a complete context switch! If a jump buffer were an image of the user program's CPU state, where setjmp() saves the registers and longjmp() restores them, the semantics would be correct.

    Alternatively, setjmp() could save just the stack pointer and return address that were passed to it, so that longjmp() would patch this information into its own activation record before returning. This would work if the compiler's code generator does not keep any variables in registers during a function call, where the called function would be responsible for saving and resturing them.

  4. Write a short paragraph that distinguishes between the notion of processor state, as the term is conventionally used in discussions of machine architecture, and process state, as the term is conventionally used in discussions of operating systems.
    The phrase "processor state" typically refers to the contents of all of the registers in the CPU; thus, it includes the program counter, the condition codes, the general registers, and any special registers that might be present in the CPU. Sometimes, discussion will focus on a specific register or even on a specific bit in a register, for example when we talk about the processor having two states, privileged and unprivileged, but the definition always applies to registers or bits in the CPU.

    The phrase "process state" refers to the state of a process -- that is, to the state of a thread of control within an executing program. Some large part of the process state must be loaded in the CPU to run the program, so the process state typically includes fields corresponding to some or all of the registers making up the processor state, but some parts of the process state are not represented in the CPU state. Among these are such things as whether the process is blocked, ready or running, and such things as the user ID.

  5. What hardware features must a processor include if it is to support interrupts?
    There must be some way for an external event to initiate a control transfer to an interrupt service routine, and there must be some way for the interrupt service routine to access and manipulate the state of the program that was interrupted. Finally, there must be a way to restore the state of the interrupted program and return from interrupt.

    Note that there is no required division of labor between hardware and software when an interrupt occurs. The hardware may save the entire CPU state as it transfers control to the interrupt service routine, or it may save very little, leaving most of the work of saving the processor state to the prologue of the interrupt service routine. Similarly, the hardware may provide a return from interrupt instruction that restores the entire CPU state, or the epilogue on the interrupt service routine may restore the state piece by piece, ending with a jump to the appropriate location in the interrupted program.