[squeak-dev] Re: [Pharo-project] #ensure: issues

Andreas Raab andreas.raab at gmx.de
Thu Mar 4 01:07:26 UTC 2010


What do you guys think about this? It behaves no worse than the current 
implementation if it encountered a problematic ensure: block in 
#terminate but it does try to complete one when it finds it. I think 
that short of changing the overall terminate semantics this is pretty 
close to as good as it gets. The test illustrates the problem.

Eliot - could you check that my usage of findContextSuchThat / closures 
/ runUntilErrorOrReturn: looks reasonable? I'm still relatively new to 
closure land in these areas.

Cheers,
   - Andreas

-------------- next part --------------
'From Squeak3.11alpha of 3 March 2010 [latest update: #9572] on 3 March 2010 at 5:01:04 pm'!

!ProcessTerminateBug methodsFor: 'tests' stamp: 'ar 3/3/2010 17:00'!
testTerminationDuringUnwind
	"An illustration of the issue of process termination during unwind"
	| unwindStarted unwindFinished p |
	unwindStarted := unwindFinished := false.
	p := [[] ensure:[
			unwindStarted := true.
			Processor activeProcess suspend.
			unwindFinished := true.
		]] fork.
	self deny: unwindStarted.
	Processor yield.
	self assert: unwindStarted.
	self deny: unwindFinished.
	p terminate.
	self assert: unwindFinished.
	! !
-------------- next part --------------
'From Squeak3.11alpha of 3 March 2010 [latest update: #9572] on 3 March 2010 at 5:02:58 pm'!

!Process methodsFor: 'changing process state' stamp: 'ar 3/3/2010 17:02'!
terminate 
	"Stop the process that the receiver represents forever.  Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."

	| ctxt unwindBlock oldList |
	self isActiveProcess ifTrue: [
		ctxt := thisContext.
		[	ctxt := ctxt findNextUnwindContextUpTo: nil.
			ctxt isNil
		] whileFalse: [
			(ctxt tempAt: 2) ifNil:[
				ctxt tempAt: 2 put: nil.
				unwindBlock := ctxt tempAt: 1.
				thisContext terminateTo: ctxt.
				unwindBlock value].
		].
		thisContext terminateTo: nil.
		self suspend.
	] ifFalse:[
		"Always suspend the process first so it doesn't accidentally get woken up"
		oldList := self suspend.
		suspendedContext ifNotNil:[
			"Figure out if we are terminating the process while waiting in Semaphore>>critical:
			In this case, pop the suspendedContext so that we leave the ensure: block inside
			Semaphore>>critical: without signaling the semaphore."
			(oldList class == Semaphore and:[
				suspendedContext method == (Semaphore compiledMethodAt: #critical:)]) ifTrue:[
					suspendedContext := suspendedContext home.
			].
			"If we are terminating a process halfways through an unwind, try
			to complete that unwind block first."
			(suspendedContext findNextUnwindContextUpTo: nil) ifNotNil:[:outer|
				(suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil:[:inner|
					"This is an unwind block currently under evaluation"
					suspendedContext runUntilErrorOrReturnFrom: inner. 
				].
			].
			ctxt := self popTo: suspendedContext bottomContext.
			ctxt == suspendedContext bottomContext ifFalse: [
				self debug: ctxt title: 'Unwind error during termination']].
	].
! !


More information about the Squeak-dev mailing list