MIME-Version: 1.0 Server: CERN/3.0 Date: Monday, 16-Dec-96 22:00:28 GMT Content-Type: text/html Content-Length: 11344 Last-Modified: Wednesday, 25-Oct-95 13:37:15 GMT CS415 Questions and Answers

Phase 1


Question: We're having difficulty understanding the abstraction for process queues which we're asked to implement for phase one of the project for cs415. We don't understand what removeProc is supposed to do. The specification says, "Remove the first element from the process queue whose tail-pointer (not tail) is pointed to by tp." Are we to scan down procTable for the first element which has a tail-pointer (by which we assume you mean the element p_next of some structure of type proc_t) identical to (*tp)?

Answer: Function RemoveProc should do precisely what the spec says. Consider a queue q (A queue is a FIFO list with a "head" element and a "tail" element). Consider a pointer to the tail element of q. Let that pointer be p. Consider now a pointer to p. Let's call it tp. RemoveProc assumes that you know tp. Your goal is to remove from q the head element of q. How you do it (namely, how you devise a "smart" and efficient implementation of the queue data structure that makes this task easy) it is up to you... :-)
Question: I cannot read files types.h and const.h . In particular, if I try to access directory ~cs415/hoca/h I get back "Permission Denied". What should I do?
Answer: Don't try to cd to the directory -- you won't be able to do that. Instead, just use the UNIX "cp" command to copy the files from ~cs415/hoca/h to your directory. The following will work, as I have just tried it on dahlia in the SunLab:
  dahlia% cd
  dahlia% cp ~cs415/hoca/h/types.h types.h
  dahlia% cp ~cs415/hoca/h/const.h const.h

Question: I believe the function on pg 10 should be outBlocked(semAdd,p) NOT outBlocked(p) as listed
Answer: No, outBlocked really takes only p as a parameter. As you point out, however, you do need to know the address of the semaphore, if any, on which p is blocked. Maybe this is an instance in which adding fields to the given data structures is a good idea...
Question: The assignment says that we can add to the fields of proc_t, semd_t to make them more efficient. But since we are abstracting them in our module, how close to this implementation to we have to have? I ask this because the "queue" implementation only has a pointer to the tail, not both the head and tail, as usual. Thus removeProc() will involve a search along the whole list. Does the "tail pointer" have to point to something of type proc_t, or can it point to an intermediate type which points to the head and tail of the queue?
Answer: Yes, you can add fields to the proc_t and semd_t structures. However, you should try to resist the temptation to add fields without having first thought if a simpler and more efficient solution exists that will not require you to do so. Implementing the queue abstraction, and taking care of function removeProc(), happens to be an instance in which adding fields to the structures would probably only serve to make things more complex and less efficient. To be specific, removeProc() *can* be efficiently implemented with the structure fields that you have already without involving a search along the whole list, as you suggest. Also, the tail pointer (which by the way must point to the last element in the queue) does have to point to an element of type proc_t.
Question: Is the C that pcc compiles for the "old-style" C? What does it expect for function declarations in export files? pcc keeps giving a core dump when we try to compile our export file.
Answer: Indeed, pcc uses the "old" C syntax. As far as how to set up extern declarations in a .e file, you can refer to the example in Appendix 1 of the HOCA documentation. (file Queue.e).
Question: Hi! We compiled our modules with gcc first (along with our own tester module), so that we could use the awesome debugging power of gdb before moving on to the graphically pleasing but somewhat less powerful CHIP simulator. We just thought others might benefit from this strategy, and we wonder
Question: ed if you might pass it on via the Web.
Answer: Using gcc to compile and debug your modules is a good idea, if you know how to use gdb. However, keep in mind that:
PHASE 2
Question: Is there an instruction called STIT in CHIP? If not, does that mean that we can't read the value stored in IT?
Answer: No, there is no instruction named STIT. You can infer what the value of IT is by comparing the current time of day with the time of day of the last time you loaded IT.
Question: Does sys6 return total CPU time(t1+t2) used by the process or the currently used cpu-time(t2)? that is
Process 1:   |-----t1-----|         |-----t2-----|
process 2:                |---------|            |
                                                 |
                                                 |<-sys6 is called at here.
Answer: SYS6 returns t1+t2
Question: Interrupt priority 0 is higher(or lower) than priority 5 ?
Answer: I believe 5 is higher. But why do you care?
Question: To set the initial "running" area for the nucleus, we use STST at some point. How do we guarantee the processor will be in kernel mode before that?
Answer: Your program runs by default in kernel mode. So you can use STST with no problems.
Question: Could you please tell me how to get the value in the status register and that in the length register for an IO device? There is a table on page 17 of the CHIP documentation, but that doesn't seem to help much. Actually, when does the value in the length register need to be retrieved? Furthermore, how am I supposed to pass those two values to the appropriate process when necessary? Do I just save them in the corresponding entry in the process table?
Answer: First of all when a device completes i/o the values for the status and length register are returned in the device registers for that device. The device registers are located in CHIP's memory just below the interrupt area. As far as accessing that area, if you look in const.h you will find the following definition:
#define BEGINDEVREG     01400   /* beginning of device registers */
that should be what you are looking for. The value in the lenght register need to be retrieved for the Terminal and Printer devices. (see sections 8.3 and 8.4) You are going to pass these values as follows: if there is a process waiting on the i/o semaphore for the device that returned the values, then you can simply copy the values in the registers 2 and 3 of the process that is waiting. (you should also unblock the process) if there is no process waiting, you should copy the returned value in the buffer dedicated to the device (the one that you declared at initialization time). The process which initiated i/o will eventually retrieve the values from there.
Question: Why do we need to distinguish between caller and running inside a trap handler? What does really mean "passing up" a trap? And what is SYS5 doing, anyway?
Answer: Let me answer the question is reverse order.

* What is SYS5 doing, anyway? 

SYS5 is called to initialize the old and new trap areas that are kept by each process (as opposed to the trap areas kept by the nucleus in the low memory addresses). It is not your job (at least for now) to decide *how* to initialize those areas: you can just assume that they are initialized through the values passed in registers 2, 3, and 4. You can look at an example of initialization browsing through the test program.
* What does really mean to "pass up" a trap?

Passing up a trap really means invoking a trap handler that is not located in the nucleus, but rather in a higher layer of the operating system. Before a trap can be passed up, the appropriate old and new trap areas for the calling process must be initialized (calling SYS5). If an attempt to pass up a trap is made before SYS5 for the invoked trap type has been executed, the calling process must be terminated. Passing up the trap involves copying the state of the calling process into the old area, and copying the state contained in the new trap area in the calling process' state as it is maintained in the process table. A possible implementation of the "passing up mechanism" would call MOVBLK twice. The first time to copy running->p_s in the old trap area. The second time to copy the state stored in the new trap area into running->p_s. As you can see, to "load" the new state we are not using LDST. Rather, we just modify the state of the running process in the proc table. With this implementation when the nucleus trap handler finishes, and the calling process gets to run again, it will actually run the higher level trap handler.

* Why do we need to distinguish between caller and running process?*

You may or may not, depending on your implementation. In mine, the reason why the caller may be different from the running process is easy to see if we consider the SYS trap handler, and we concentrate on SYS4, As a result of the P operation, the calling process may be blocked, and a new process elected to be the next to run. Using the caller vs running trick one can figure out withn the SYS trap handler if such an event has taken place, and load the IT for the new running process with an appropriate value. It is less clear why the caller/running trick may be useful for prog, MM, or even SYS traps for SYS instructions greater than 8. After all, these traps are "passed up", a new state is loaded, and any instruction after a call to passup will never be executed (this was the question that Nesheet asked today in class). In my implementation, the check that the trap areas have been initialized (i.e. the right SYS5 has been executed) is done within the call to passup. If the caller process has not executed SYS5, the caller will be terminated, and a new process will be designated as the next to run. In this case, control will indeed reach the code after passup, and the "caller!=running" check will allow to correctly reload the interval timer.