BR.SJE@forsythe.stanford.edu (Steve Eastman) (09/26/89)
Remember, in M2 things of type PROCESS must function in a certain way, else the thing you've got isn't M2. If the thing you've got isn't M2, you won't be able to use any one else's modules in a program of your own. Hereafter I will call Modula-2 processes "threads". This term may help reduce the confusion that I think exists for UNIX programmers that use M2. Usually a thing called a "process" has its own address space and communicates with other processes in a way that coordinates both processes at the time of the communication--when data transfer takes place. Threads on the other hand are low overhead, low level, things. They have nothing to do with processes (except they me be used as part of the implementation of processes). In the definition of Modula-2 a thread (or as Wirth calls them "process") must be sequential. That is, they must not be mutually preemptive. The exception is that an interrupt service routines (ISR) thread may preempt another thread of lower priority. A monitor (priority module) must protect its shared variables against alteration during its execution. When a monitor contains an ISR a very interesting state of affairs develops. All ISRs have at least one shared variable which they alter. This variable is passed to it when an interrupt occurs--the thing pointed to by the pointer that is the second parameter to the IOTRANSFER procedure--the interrupted thread. The way in which the variable is altered is that it is changed to the "not running" state. When the ISR is done it will change the state of the interrupted thread back to "running" via IOTRANSFER. It can only make this second change with impunity because it knows the thread was in the "running" state in the beginning and has protected it from alteration through out its execution. Therefore, all ISRs must execute in such a way that the state of the interrupted thread is not altered in any way, then execute the interrupted thread. The only way to make sure of this is to (A) not transfer to any other thread, or (B) transfer only to threads in the same priority module as the ISR such that the priority level never is lowered. The reason for this is that if the thread being transferred to is of a lower priority, then the owner of the interrupted thread could come back into control and change the state of the interrupted thread to "not running" or destroy it altogether. Then, when the ISR comes back into control, the ISR would, believing the thread to be runnable as a matter of course, IOTRANSFER to it. Thus, it would have transferred to and made "running" a thread which its owner believes to be "blocked" or nonexistent. This conflict as to the state of an interrupted process probably will have tragic consequences on the execution of a program. Until I discovered the above described tangle of threads, my multi-threaded system had some very weird bugs: threads running when they were "blocked", programs running away, etc..
BR.SJE@forsythe.stanford.edu (Steve Eastman) (09/26/89)
PLEASE IGNORE THE PREVIOUS SIMILAR MESSAGE. I MADE A MISTAKE. Remember, in M2 things of type PROCESS must function in a certain way, else the thing you've got isn't M2. If the thing you've got isn't M2, you won't be able to use any one else's modules in a program of your own. Hereafter I will call Modula-2 processes "threads". This term may help reduce the confusion that I think exists for UNIX programmers that use M2. Usually a thing called a "process" has its own address space and communicates with other processes in a way that coordinates both processes at the time of the communication--when data transfer takes place. Threads on the other hand are low overhead, low level, things. They have nothing to do with processes (except they me be used as part of the implementation of processes). In the definition of Modula-2 a thread (or, unfortunately, as Wirth calls it "process") must be sequential. That is, they must not be mutually preemptive. The exception is that an interrupt service routine's (ISR) thread may preempt another thread of lower priority (created in a module of lower priority). A monitor (priority module) must protect its shared variables against alteration during its execution. When a monitor contains an ISR a very interesting state of affairs develops. All ISRs have at least one shared variable which they alter. This variable is passed to it when an interrupt occurs--the thing pointed to by the pointer that is the second parameter to the IOTRANSFER procedure--the interrupted thread. The way in which the variable is altered is that it is changed to the "not running" state. When the ISR is done it will change the state of the interrupted thread back to "running" via IOTRANSFER. It can only make this second change with impunity because it knows the thread was in the "running" state in the beginning and has protected it from alteration through out its execution. Therefore, all ISRs must execute in such a way that the state of the interrupted thread is not altered in any way, then execute the interrupted thread. The only way to make sure of this is to (A) not transfer to any other thread, or (B) transfer only to threads in the same priority module as the ISR such that the priority level never is lowered. You may think that you could write a module that could be called by your ISRs to manage the interrupted threads. This won't work because off-the-shelf modules that create threads wont have been written to call this module. The reason for this protection is that if the thread being transferred to is of a lower priority, then the owner of the interrupted thread could come back into control and change the state of the interrupted thread to "not running" or destroy it altogether. Then, when the ISR comes back into control, the ISR would, believing the thread to be runnable, IOTRANSFER to it. Thus, it would have transferred to and made "running" a thread which its owner believes to be "blocked" or nonexistent. This conflict as to the state of an interrupted process probably will have tragic consequences on the execution of a program. Until I realized this, my multi-threaded system had some very weird bugs: threads running when they were "blocked", programs running away, unpredictable crashes, etc.. Finally, you cannot use TRANSFER in a clock tick ISR to get mutually preemptive threads for 2 reasons: (1) such things are not allowed by the language definition, and (2) your thread manager/owner/creators would get all tangled up. Note well: The foregoing does not mean that mutually preemptive threads cannot be implemented in Modula-2; it means that such things cannot be simply thrown into an implementation of M2 nor found in the language definition. But then, of course, you can do anything you want. Sincerely, Steve Eastman BR.SJE@RLG.STANFORD.EDU