A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-jar.1412.mcz ==================== Summary ==================== Name: Kernel-jar.1412 Author: jar Time: 24 May 2021, 11:06:42.045885 pm UUID: a5554c88-2df6-dc43-ad89-8b128c719dcd Ancestors: Kernel-jar.1411 Fix an issue when a process terminating another process is terminated in the middle of the unwind. As a result the original process won't finish unwinding and will leave either a suspended process or a chain of unfinished contexts behind (to be GC'd). This is an update of Kernel-jar.1411 (not replacement). Complemented by a test: KernelTests-jar.406 =============== Diff against Kernel-jar.1411 =============== Item was changed: ----- Method: Process>>terminate (in category 'changing process state') ----- terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | oldList top ctxt outerMost newTop unwindBlock | "If terminating the active process, suspend it first and terminate it as a suspended process." self isActiveProcess ifTrue: [ [self terminate] fork. ^self suspend]. + [] ensure: [ "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, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNil: [^self]. "self 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]). top := suspendedContext. suspendedContext := nil. "disable this process while running its stack in active process below" "If terminating a process halfways through an unwind, try to complete that unwind block first; if there are multiple such nested unwind blocks, try to complete the outer-most one; nested unwind blocks will be completed in the process. Halfway-through blocks have already set the complete variable (tempAt: 2) in their defining #ensure:/#ifCurtailed contexts from nil to true. Note: #findNextUnwindContextUpTo: starts searching from the receiver's sender but the receiver itself may be an unwind context." ctxt := top. ctxt isUnwindContext ifFalse: [ctxt := ctxt findNextUnwindContextUpTo: nil]. [ctxt isNil] whileFalse: [ (ctxt tempAt:2) ifNotNil: [ outerMost := ctxt]. ctxt := ctxt findNextUnwindContextUpTo: nil]. outerMost ifNotNil: [newTop := self complete: top to: outerMost]. "By now no halfway-through unwind blocks are on the stack. Create a new top context for each pending unwind block (tempAt: 1) and execute it on the unwind block's stack. Note: using #value instead of #complete:to: would lead to incorrect evaluation of non-local returns. Note: newTop sender points to the former outerMost sender, i.e. the next unexplored context." ctxt := newTop ifNil: [top] ifNotNil: [newTop sender]. ctxt isUnwindContext ifFalse: [ctxt := ctxt findNextUnwindContextUpTo: nil]. [ctxt isNil] whileFalse: [ (ctxt tempAt: 2) ifNil: [ ctxt tempAt: 2 put: true. unwindBlock := ctxt tempAt: 1. top := unwindBlock asContextWithSender: ctxt. self complete: top to: top]. + ctxt := ctxt findNextUnwindContextUpTo: nil] + ]! - ctxt := ctxt findNextUnwindContextUpTo: nil]! |
Free forum by Nabble | Edit this page |