[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