[squeak-dev] The Inbox: Kernel-jar.1487.mcz
commits at source.squeak.org
commits at source.squeak.org
Mon Jul 11 13:00:37 UTC 2022
A new version of Kernel was added to project The Inbox:
==================== Summary ====================
Time: 11 July 2022, 3:00:32.776972 pm
Add a stronger guard to deal with concurrent terminations.
The current weakness showed in this Workspace example:
p1 := [Smalltalk installLowSpaceWatcher] fork.
p2 := [Smalltalk installLowSpaceWatcher] fork
Instead of terminating both LowSpaceProcesses and unblocking p1 and p2, one of them gets stuck on a semaphore.
Complemented with KernelTests-jar.437 with a modified test (testTerminateTerminatingProcessInUnwindTo) to cover this situation.
=============== Diff against Kernel-eem.1486 ===============
Item was added:
+ ----- Method: Context>>unwindAndStop: (in category 'private') -----
+ unwindAndStop: aProcess
+ "I'm a helper method to #terminate; I create and answer
+ a helper stack for a terminating process to unwind itself from."
+ ^(Context contextEnsure: [self unwindTo: nil])
+ privSender: [aProcess suspend] asContext
Item was changed:
----- Method: Process>>terminate (in category 'changing process state') -----
"Stop the process that the receiver represents forever.
Unwind to execute pending #ensure:/#ifCurtailed: blocks before terminating;
allow all unwind blocks to run; if they are currently in progress, let them finish."
"This is the kind of behavior we expect when terminating a healthy process.
See further comments in #terminateAggressively and #destroy methods dealing
with process termination when closing the debugger or after a catastrophic failure.
If terminating the active process, create a new stack and run unwinds from there.
If terminating a suspended process (including runnable and blocked), always
suspend the terminating process first so it doesn't accidentally get woken up.
Equally important is the side effect of the suspension: In 2022 a new suspend
semantics has been introduced: the revised #suspend backs up a process waiting
on a conditional variable to the send that invoked the wait state, while the previous
#suspend simply removed the process from the conditional variable's list it was
previously waiting on; see #suspend and #suspendAndUnblock comments.
If the process is in the middle of a #critical: critical section, release it properly.
To allow a suspended process to unwind itself, create a new stack for the process
being terminated and resume the suspended process to complete its termination
from the new parallel stack. Use a semaphore to make the process that invoked
the termination wait for self's completion. Execute the termination in the ensure
argument block to ensure it completes even if the terminator process itself gets
terminated before it's finished; see testTerminateInTerminate and others."
- | context |
self isActiveProcess ifTrue: [
+ ^(thisContext unwindAndStop: self) jump].
- context := thisContext.
- ^[ ensure: [context unwindTo: nil]. self suspend] asContext jump].
 ensure: [ | terminator |
+ suspendedContext ifNil: [^self].
- context := suspendedContext ifNil: [^self].
terminator := Semaphore new.
+ suspendedContext bottomContext insertSender: (Context contextEnsure: [terminator signal]).
+ self suspendedContext: (suspendedContext unwindAndStop: self);
- context bottomContext insertSender: (Context contextEnsure: [terminator signal]).
- self suspendedContext: [ ensure: [context unwindTo: nil]. self suspend] asContext;
priority: Processor activePriority;
More information about the Squeak-dev