[comp.lang.modula2] TRANSFER

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