[squeak-dev] The Inbox: Kernel-jar.1500.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Feb 2 21:05:01 UTC 2023


A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-jar.1500.mcz

==================== Summary ====================

Name: Kernel-jar.1500
Author: jar
Time: 2 February 2023, 10:04:57.541211 pm
UUID: 8add6e35-4849-624a-94f8-0722d7ef8c07
Ancestors: Kernel-tpr.1497

Fix #terminateAggressively and #runUntilErrorOrReturnFrom: bugs. Both bugs combined cause the Debugger MNU in this situation:

Run this in the Workspace:
p := [ [Semaphore new wait] ensure: [1/0] ] fork

Then terminate it like this:
[p terminate] fork

And then just press Abandon and get the MNU error.

=============== Diff against Kernel-tpr.1497 ===============

Item was changed:
  ----- Method: Context>>runUntilErrorOrReturnFrom: (in category 'controlling') -----
  runUntilErrorOrReturnFrom: aSender 
  	"ASSUMES aSender is a sender of self.  Execute self's stack until aSender returns or an unhandled exception is raised.  Return a pair containing the new top context and a possibly nil exception.  The exception is not nil if it was raised before aSender returned and it was not handled.  The exception is returned rather than openning the debugger, giving the caller the choice of how to handle it."
  	"Self is run by jumping directly to it (the active process abandons thisContext and executes self).  However, before jumping to self we insert an ensure block under aSender that jumps back to thisContext when evaluated.  We also insert an exception handler under aSender that jumps back to thisContext when an unhandled exception is raised.  In either case, the inserted ensure and exception handler are removed once control jumps back to thisContext."
  
  	| error ctxt here topContext |
  	here := thisContext.
  
  	"Insert ensure and exception handler contexts under aSender"
  	error := nil.
  	ctxt := aSender insertSender: (Context
  		contextOn: UnhandledError do: [:ex |
  			error ifNil: [
  				error := ex exception.
  				topContext := thisContext.
  				ex resumeUnchecked: here jump]
  			ifNotNil: [ex pass]
  		]).
  	ctxt := ctxt insertSender: (Context
  		contextEnsure: [error ifNil: [
  				topContext := thisContext.
  				here jump]
  		]).
  	self jump.  "Control jumps to self"
  
  	"Control resumes here once above ensure block or exception handler is executed"
  	^ error ifNil: [
  		"No error was raised, remove ensure context by stepping until popped"
+ 		[ctxt isDead or: [topContext isNil]] whileFalse: [topContext := topContext stepToCallee].
- 		[ctxt isDead] whileFalse: [topContext := topContext stepToCallee].
  		{topContext. nil}
  
  	] ifNotNil: [
  		"Error was raised, remove inserted above contexts then return signaler context"
  		aSender terminateTo: ctxt sender.  "remove above ensure and handler contexts"
  		{topContext. error}
  	]!

Item was changed:
  ----- Method: Process>>terminateAggressively (in category 'changing process state') -----
  terminateAggressively
  	"Stop the receiver forever.
  	Run all unwind contexts (#ensure:/#ifCurtailed: blocks) on the stack that have not yet been started. If the process is in the middle of an unwind block, then that unwind block will not be completed, but subsequent unwind blocks will be run. If even those unwind contexts should be continued, send #terminate instead.
  	Note that ill unwind contexts are theoretically able to stall the termination (for instance, by placing a non-local return in an unwind block); however, this is a disrecommended practice.
  	If the process is in the middle of a critical: critical section, release it properly."
  
  	| oldList bottom tombstone |
  	self isActiveProcess ifTrue: [
  		"If terminating the active process, suspend it first and terminate it as a suspended process."
  		[self terminate] fork.
  		^self suspend].
  	
  	"Always suspend the process first so it doesn't accidentally get woken up.
  	N.B.: If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al., then the process is blocked."
  	oldList := self suspend.
  	suspendedContext ifNil: [^ self "Process is already terminated"].
  	
  	"Release any method marked with the <criticalSection> pragma. The argument is whether the process is runnable."
  	self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]).
  	
  	bottom := suspendedContext bottomContext.
  	tombstone := bottom insertSender: [self suspend "terminated"] asContext.
  	suspendedContext := self
  		activateReturn: bottom
  		value: nil.
  	self complete: tombstone ifError: [:ex |
+ 		(suspendedContext ifNil: [^self]) privRefresh. "Restart the handler context of UnhandledError so that when the receiver is resumed, its #defaultAction will be reached. See implementation details in #runUntilErrorOrReturnFrom:."
- 		suspendedContext privRefresh. "Restart the handler context of UnhandledError so that when the receiver is resumed, its #defaultAction will be reached. See implementation details in #runUntilErrorOrReturnFrom:."
  		"We're not yet done, resume the receiver to spawn a new debugger on the error."
  		self resume].!



More information about the Squeak-dev mailing list