[ENH] inter-process signaling
Stephen Pair
stephen at pairhome.net
Fri Sep 19 23:03:47 UTC 2003
The attached file-out is an improved inter-process signaling mechanism.
It adds a method #signal: to Process that accepts an exception as its
argument. It will signal the exception in the context of the receiver.
If the receiver is currently suspended (i.e. not on a list), the
exception will not get signaled until the process is resumed. If the
receiver is currently blocking on a Semaphore, this method will return
the receiver to a non-blocked state and the process will resume with the
exception being signaled. If that exception is handled and resumed, the
process will return to a blocked state if the semaphore does not have
any excess signals.
So, as Ned pointed out, you could use this to timeout a process that is
waiting on a Semaphore with an exception. It might look something like
this.
| sem proc |
sem := Semaphore new.
proc := [sem wait] newProcess.
proc resume.
(Delay forSeconds: 5) wait.
proc signal: (Error new messageText: 'hey wake up!'; yourself).
I think this has the potential for a multitude of uses. I can imagine
extending the process browser such that you can right click and send a
variety of common signals to a process.
- Stephen
Stephen Pair wrote:
> Ned Konz wrote:
>
>> On Friday 19 September 2003 11:56 am, Stephen Pair wrote:
>>
>>
>>> One of the things that crossed my mind not too long ago is that it
>>> would be nice if we could signal exceptions in another process. For
>>> example:
>>>
>>> Error new messageText: 'some error message'; signalProcess:
>>> someProcess
>>>
>>> Or,
>>>
>>> someProcess signal: (Error new messageText: 'some error message';
>>> yourself)
>>>
>>> This could be useful for graceful termination of processes (among
>>> many other things)...unwind actions could always happen in the
>>> process where they were defined. The default action of a Terminate
>>> exception would be to terminate the active process. Here's the
>>> method that seems to do the trick:
>>>
>>> Process>>signal: anException
>>>
>>> Processor activeProcess == self ifTrue: [^anException signal].
>>> suspendedContext := MethodContext
>>> sender: suspendedContext
>>> receiver: self
>>> method: thisContext method
>>> arguments: (Array with: anException).
>>>
>>>
>>
>>
>> Thanks!
>>
>> I've asked for this several times and no one has come up with it yet.
>>
>> One obvious use of this is to provide Semaphore>>wait methods that
>> raise an exception on a timeout.
>>
>
> Of course, if your process happens to be waiting on a Semaphore,
> sending #signal: to the process will not wake it up (nothing will
> happen until the semaphore gets signaled)...you could add a line to
> the end of that method to suspend and resume (ie. "self suspend;
> resume") and that will wake it up...but, what I'd really like is a way
> of waking it up to process the exception and when you resume the
> exception have the process go back into a state where it's still
> waiting on the original semaphore (if it hadn't been signaled in the
> interim). I had a solution for that, but it seems to have a tendency
> to crash the VM. ;)
>
> - Stephen
>
>
>
-------------- next part --------------
'From Squeak3.6gamma of ''11 September 2003'' [latest update: #5420] on 19 September 2003 at 6:47:58 pm'!
!Process methodsFor: 'signaling' stamp: 'svp 9/19/2003 18:41'!
pvtSignal: anException list: aList
"Private. This method is used to signal an exception from another
process...the receiver must be the active process. If the receiver
was previously waiting on a Semaphore, then return the process
to the waiting state after signaling the exception and if the Semaphore
has not been signaled in the interim"
"Since this method is not called in a normal way, we need to take care
that it doesn't directly return to the caller (because I believe that could
have the potential to push an unwanted object on the caller's stack)."
| blocker |
self isActiveProcess ifFalse: [^self].
anException signal.
blocker := Semaphore new.
[self suspend.
suspendedContext := suspendedContext swapSender: nil.
aList class == Semaphore
ifTrue:
[aList isSignaled
ifTrue:
[aList wait. "Consume the signal that would have restarted the receiver"
self resume]
ifFalse:
["Add us back to the Semaphore's list (and remain blocked)"
myList := aList.
aList add: self]]
ifFalse: [self resume]] fork.
blocker wait.
! !
!Process methodsFor: 'signaling' stamp: 'svp 9/19/2003 18:42'!
signal: anException
"Signal an exception in the receiver process...if the receiver is currently
suspended, the exception will get signaled when the receiver is resumed. If
the receiver is blocked on a Semaphore, it will be immediately re-awakened
and the exception will be signaled; if the exception is resumed, then the receiver
will return to a blocked state unless the blocking Semaphore has excess signals"
"If we are the active process, go ahead and signal the exception"
self isActiveProcess ifTrue: [^anException signal].
"Add a new method context to the stack that will signal the exception"
suspendedContext := MethodContext
sender: suspendedContext
receiver: self
method: (self class methodDict at: #pvtSignal:list:)
arguments: (Array with: anException with: myList).
"If we are on a list to run, then suspend and restart the receiver
(this lets the receiver run if it is currently blocked on a semaphore). If
we are not on a list to be run (i.e. this process is suspended), then when the
process is resumed, it will signal the exception"
myList ifNotNil: [self suspend; resume].! !
More information about the Squeak-dev
mailing list
|