[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

FW: Poison

The Poison mechanism is sometimes elegant but sometimes a complex

Marcel already noticed the problem with shared channels. There is at
least one process that needs to know how many processes are on the
reader (sending n tokens) or writer side (reading n tokens) of the
shared channel. 

Other problems with the Poison mechanism are:
-	An additional Poison channel and an extra ALT is needed for
those processes that originally have no input channels and do not
initiate Poison tokens. 
-	The Poison mechanism is intertwined with the regular code.
-	Broadcasting exceptions is time consuming.

These problems add an amount of (unnecessary?) complexity (or

Exception handling takes usually a different discipline and I prefer
exception handling to be orthogonal to the regular code. Therefore, the
try-catch clause in Java/C++ is a nice concept that is orthogonal to the
regular code.

An idea

Currently, the CTJ channels (and JCSP channels) can throw io-exceptions
if something goes wrong in the underlying link driver. The try-catch
clause catches the exception and deals with the problem. This mechanism
can be used for poisoning processes in the following way:

Instead of poisoning processes via channels, processes could terminate
(or interrupt) channels. If a process reads or writes on a terminated
channel then a 'poison' exception is thrown and the try-catch clause
catches the exception. 
For example, a terminated shared channel terminates (poisons) all
participating processes when they read or write on the channel. This is
similar to broadcasting poison tokens without knowing how many processes
share the channel. A terminated channel will release all blocked
processes on that channel. 
A terminated channel could also be reinitiated for reuse after the
problem has been recovered.  

Channel methods:

channel.terminate (or Channel.interrupt, or .?)
channel.recover (or Channel.reinit, or .?)

Another idea

In CSP there is this interrupt operator P * Q. Here, * is the interrupt
symbol (I don't know the ASCII character for this operator). This
process behaves as P and until Q can engage in an interrupt event it
will behave as Q. Process P will be preempted and terminates
immediately. This requires a special PRIPAR implementation . say INTPAR.


Process Q could represent an exception handler. Process Q is orthogonal
to process P. This way we could terminate a group of processes at once,
for example:

(P || R || S || T) * Q



Implementing the interrupt operator could be difficult, I don't know
yet. Hmmm .... in the previous try-catch mechanism the interrupt
operator could be represented as

try {
} catch (Exception e)

The throw-statement causes the interrupt event which involves a
communication event. Semantically this is close but not precise to the
interrupt operator.

Processes could throw exception through their run() methods to higher
hierarchal levels. If P is a parallel construct then it can only throw a
'poison' exception if all child processes have been terminated and at
least one child process has thrown a 'poison' exception.

In case of an ALT, I guess, the guarded process catches the exception
and passes the exception to the ALT via its run() method. Hmm, this may
not be the complete picture?

Thus, the PAR, ALT, SEQ, PRIPAR, PRIALT can throw 'child' exceptions to
higher hierarchal levels.  Or perhaps only 'poison' exceptions?

How about this? 


PS. CTJ included the Poison class in earlier revisions :)

> -----Original Message-----
> From: M_Boosten [mailto:mboosten@xxxxxxxxxxxxxxxxxxx]
> Sent: donderdag 19 juli 2001 10:04
> To: java-threads@xxxxxxxxx; occam-com@xxxxxxxxx; P.H.Welch@xxxxxxxxx
> Subject: Re: Poiso
> Peter,
> > Marcel:
> > > I expect that POISON will make the code more complex.
> > [Peter wrote:]
> > Not half!  That's why I asked my question: although the POISON
> > solution is trivial (e.g. it can be mechanically 
> retrofitted over an
> > existing network), is there a better way?  Or should we
> just build a
> > tool to do that retrofitting?
> > In Java/JCSP/CTJ, a better way may be to use exceptions.
> The channel
> > read method could always look out for the POISON object being sent
> > and, if spotted, throw an (unchecked) Poisoned exception.  
> That way,
> > user process code that doesn't need to terminate is unchanged.  For
> > those that do, the Poisoned exception handler code does not mess up 
> > the code operating the normal behaviour of the process - 
> which is the
> > whole point of exceptions.
> > I think I like this.  It's a bit like Java's
> InterruptedException but,
> > I think, cleaner - there's no mysterious Poisoned status to check
> > (that can be changed behind the back of a thread by any 
> other thread
> > with a handle on it).  My caution is that occam doesn't have an
> > exception mechanism for, maybe, good reasons.  I remember Geoff 
> > Barrett arguing about it when deigning occam3.  He chose 
> not to go for
> > it for, I think, semantic reasons ... are you there Geoff?
> The main danger of a general exception mechanism is its
> EXISTENCE.  Because it exists, people start using it, and in 
> 95% of the cases it is used for situations which, in fact, 
> are non-exceptional, but just another standard alternative.  
> In many cases, exception handling makes it extremely 
> difficult to write correct and readable code.
> I think I would NOT introduce a general exception mechanism in Occam; 
> in stead, I would introduce a specific RESET or POISON mechanism.  
> Such a mechanism is missing; I do not think there is a need for a 
> general exception mechanism.
> In my opinion, the same holds for Java/JCSP/CTJ: the RESET or
> POISON mechanism can nicely be implemented using exception 
> handlers; however, I would not advertise the use of the 
> exception handling mechanism in general.
> A solution in JCSP/CTJ would be like:
>      {
>         ...normal code of the process...
>      } catch(Poison(poisenedChannel)) {
>         unpoisenedInputChannels = allInputChannels - 
> poisenedChannel;     
>         forAll (c : allOutputChannels) {
>            c!POISON;
>         }
>         while (unpoisenedInputChannels != emptySet) {
>            c = ALT(unpoisenedInputChannels);
>            c?x;
>            if (x == POISON) {
>               unpoisenedInputChannels -= c;
>            }
>         }
>         exit;
>      }
> You need some means to identify sets of input, output, and
> poisened channels.  The normal code of the process does not 
> even need to be checked for Poison compatibility.
> However, the result is a clear "kill -9", it is pretty much
> impossible to place code in the exception handler that 
> performs some more standard communication to partner 
> processes to achieve a stable state.  In general, I think 
> "Graceful Termination" sounds a bit too promissing, I think 
> simple "Termination" is much more graceful terminology.
> Furthermore, I have been wondering about the many-to-one
> channel.  The rule is probably: on reception of POISON via a 
> N-to-one channel, one has to wait for another N-1 POISON 
> tokens during the graceful exit.
> What about an N-toOneOf-M channel?
> In fact, a N-toOneOf-M channel has got N+M users.  Each of
> them has to indicate its non-interest in the channel.  
> Actually, then, you are building a shared data release 
> machanism using access counting...  there are definitely 
> strong similarities...
> Cheers,
> 	Marcel