[squeak-dev] The Inbox: KernelTests-jar.433.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Jun 7 16:25:00 UTC 2022
A new version of KernelTests was added to project The Inbox:
http://source.squeak.org/inbox/KernelTests-jar.433.mcz
==================== Summary ====================
Name: KernelTests-jar.433
Author: jar
Time: 7 June 2022, 6:24:58.053964 pm
UUID: b2a35851-6470-a643-9f6f-e939501100b6
Ancestors: KernelTests-mt.425
Bundle together all new Process and Semaphore tests from:
KernelTests-jar.431, 432 (multiple termination and NLR)
KernelTests-jar.429, 430 (unwind errors test)
KernelTests-jar.428 (more tests)
KernelTests-jar.426, 427 (priority before suspendedContext)
Complements Kernel-jar.1476 (updated terminate with sync) and Kernel-jar.1473 (priority set before suspendedContext).
Please remove the individual changesets from the Inbox.
=============== Diff against KernelTests-mt.425 ===============
Item was added:
+ ----- Method: ProcessTest>>testPrioritySetBeforeSuspendedContext (in category 'tests') -----
+ testPrioritySetBeforeSuspendedContext
+ "Test whether priority is set before suspendedContext during process creation."
+
+ "Setting priority after causes an endless stream of error windows when debugging e.g.
+ [] newProcess
+ when Process Browser is open with auto-update on.
+
+ Once the suspendedContext is set, the new process is no longer considered terminated
+ and Process Browser will try to place it in its list of processes but encounters a nil error
+ when reading its priority because it has not been set yet."
+
+ | p inside |
+ inside := false.
+ p := [inside := true. [] newProcess] newProcess.
+ p runUntil: [:ctx | inside].
+ p runUntil: [:ctx | ctx selectorToSendOrSelf = #suspendedContext:].
+ "Now p is before assigning suspendedContext in Process class >> forContext:priority:
+ tempAt: 3 is the local variable 'newProcess' representing the newly created process;
+ verify whether the new process's priority has already been set."
+ self assert: (p suspendedContext tempAt: 3) priority notNil!
Item was added:
+ ----- Method: ProcessTest>>testTerminateByHighestPriorityProcess (in category 'tests') -----
+ testTerminateByHighestPriorityProcess
+ "Test temination by a highest priority process."
+
+ "Note: in case #terminate elevates the priority of the terminating
+ process it has to make sure it doesn't exceed the highest priority.
+ Workspace example:
+ q := [Semaphore new wait] fork.
+ p := [q terminate] forkAt: Processor highestPriority.
+ q isTerminated
+
+ We have to catch the 'Invalid priority' error via the 'error' variable
+ because #shouldnt:raise: doesn't work between two processes."
+
+ | p q error |
+ p := [Semaphore new wait] fork.
+ Processor yield.
+ self assert: p isBlocked.
+ error := false.
+ q := [[p terminate] on: Error do: [error := true]] newProcess.
+ q priority: Processor highestPriority.
+ q resume.
+ self deny: error.
+ self assert: p isTerminated.
+ self assert: q isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateEnsureOnTopOfEnsure (in category 'tests') -----
+ testTerminateEnsureOnTopOfEnsure
+ "Test two ensure contexts on top of each other unwind correctly,
+ that both their unwind blocks get executed."
+
+ | beenHere beenHereToo bottom p top |
+ beenHere := beenHereToo := false.
+ bottom := Context contextEnsure: [beenHereToo := true].
+ top := Context contextEnsure: [Processor activeProcess suspend. beenHere := true].
+ top privSender: bottom.
+ p := Process forContext: top priority: Processor activeProcess priority.
+ p resume.
+ Processor yield.
+ self assert: p isSuspended.
+ p terminate.
+ self assert: beenHere & beenHereToo.
+ self assert: p isTerminated
+
+ !
Item was added:
+ ----- Method: ProcessTest>>testTerminateHandlingUnwindError (in category 'tests') -----
+ testTerminateHandlingUnwindError
+ "Test an error inside an unwind block is handled correctly."
+
+ "Workspace example:
+ [ [[Processor activeProcess terminate] ensure: [1/0]] on: ZeroDivide do: [] ] fork
+
+ ZeroDivide error should get caught by the handler without opening the Debugger.
+
+ To model this example as a test case we have to keep in mind that an error signal
+ in one thread cannot be caught in a different thread: if process 'p' signals an error
+ it won't be searching for a handler in the thread that sent 'p terminate' message.
+ So we can't do something like:
+ p := [ [ [Semaphore new wait] ensure: [1/0] ] on: ZeroDivide do: [] ] fork.
+ Processor yield.
+ self shouldnt: [p terminate] raise: Error
+ Instead, in order to catch the situation the ZeroDivide error is not caught within 'p',
+ we try to catch the UnhandledError raised in 'p' indicating the ZeroDivide has been
+ missed. "
+
+ | p error unwindBlock |
+ unwindBlock := [[1/0] on: UnhandledError do: [error := true]].
+ p := [ [ [Semaphore new wait] ensure: unwindBlock ] on: ZeroDivide do: [] ] fork.
+ Processor yield.
+ self assert: p isBlocked.
+ error := false.
+ p terminate.
+ self deny: error.
+ self assert: p isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateHighestPriorityProcess (in category 'tests') -----
+ testTerminateHighestPriorityProcess
+ "Test termination of a highest priority process."
+
+ | p |
+ p := [Semaphore new wait] forkAt: Processor highestPriority.
+ Processor yield.
+ self assert: p isBlocked.
+ p terminate.
+ self assert: p isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateNiledSuspendedContextProcess (in category 'tests') -----
+ testTerminateNiledSuspendedContextProcess
+ "Test a process with niled suspendedContext terminates correctly."
+
+ | p |
+ p := [] newProcess.
+ self assert: p isSuspended.
+ p suspendedContext: nil.
+ p terminate.
+ self assert: p isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateSingleEnsure (in category 'tests') -----
+ testTerminateSingleEnsure
+ "Test a stack consisting of a single ensure context unwinds correctly."
+
+ | beenHere p singleton |
+ beenHere := false.
+ singleton := Context contextEnsure: [beenHere := true].
+ p := Process forContext: singleton priority: Processor activeProcess priority.
+ self assert: p isSuspended.
+ self assert: p suspendedContext sender isNil.
+ p terminate.
+ self assert: beenHere.
+ self assert: p isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateTerminatingProcessAfterUnwindStarted (in category 'tests') -----
+ testTerminateTerminatingProcessAfterUnwindStarted
+ "Terminating a terminatee process after the terminator process restarted the terminatee
+ process should unwind the terminatee process and let the terminator process terminate."
+
+ "Such a situation may occur e.g. when a terminating process encounters an error and
+ opens a debugger (or calls another recovery machinery). In such case it's legitimate
+ to terminate the terminating process again (by closing the debugger or as a termination
+ by another recovery tool).
+
+ Note: this is a different situation than in 'testTerminateTerminatingProcess' where
+ the second termination is invoked 'too early' and may cause unpredictable outcome."
+
+ | terminator terminatee unwound unwindBlock |
+ unwound := false.
+ unwindBlock := [Processor activeProcess suspend. unwound := true].
+ terminatee := [[Semaphore new wait] ensure: unwindBlock] fork.
+ Processor yield.
+ terminator := [terminatee terminate] newProcess.
+ self assert: terminatee isBlocked.
+ self assert: terminator isSuspended.
+ terminator resume.
+ Processor yield.
+ "terminator starts terminatee's unwind"
+ Processor yield.
+ "terminatee resumes and stops at unwindBlock's #suspend"
+ self assert: terminatee isSuspended.
+ terminatee terminate.
+ self assert: terminatee isTerminated.
+ self assert: unwound.
+ Processor yield.
+ self assert: terminator isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateTerminatingProcessInUnwindTo (in category 'tests') -----
+ testTerminateTerminatingProcessInUnwindTo
+ "Terminating a terminatee process after the terminator process restarted the terminatee
+ process should unwind the terminatee process and let the terminator process terminate."
+
+ | terminator terminatee unwound |
+ unwound := false.
+ terminatee := [[Semaphore new wait] ensure: [unwound := true]] fork.
+ Processor yield.
+ terminator := [terminatee terminate] newProcess.
+ self assert: terminatee isBlocked.
+ self assert: terminator isSuspended.
+ terminator runUntil: [:ctx | ctx selectorToSendOrSelf = #resume].
+ "terminator steps until terminatee's unwind context is set"
+ terminator suspendedContext nextInstruction. "skip terminatee resume instruction"
+ terminator resume. "and run until parked at wait"
+ terminatee runUntil: [:ctx | ctx selectorToSendOrSelf = #unwindTo:].
+ "terminatee steps until at #unwindTo:"
+ self assert: terminatee isSuspended.
+ terminatee terminate.
+ self assert: terminatee isTerminated.
+ self assert: unwound.
+ Processor yield.
+ self assert: terminator isTerminated!
Item was added:
+ ----- Method: ProcessTest>>testTerminateWithDelayInUnwind (in category 'tests') -----
+ testTerminateWithDelayInUnwind
+ "Test the process that invoked the termination of another process waits
+ for the other process to finish unwinding."
+
+ "Insert delay into the unwind block to force rescheduling; alternatively,
+ 'Processor yield' could be used instead of 'delay wait'."
+
+ | delay p |
+ delay := Delay forMilliseconds: 10.
+ p := [[Processor activeProcess suspend] ensure: [delay wait]] fork.
+ Processor yield.
+ self assert: p isSuspended.
+ p terminate.
+ self assert: p isTerminated!
Item was added:
+ ----- Method: ProcessUnwindTest>>testTerminateNestedEnsureWithReturn1 (in category 'tests') -----
+ testTerminateNestedEnsureWithReturn1
+ "Terminate suspended process.
+ Test all nested unwind blocks are correctly executed;
+ all unwind blocks halfway through their execution should be completed."
+
+ "While testTerminateInNestedEnsureWithReturn1 to 8 start unwinding
+ from inside a halfways through unwind block, this test (and the next) start
+ the unwind from outside any ensure argument (aka unwind) block, testing
+ the second half of the #unwindTo:safely: method."
+
+ | p x1 x2 x3 x4 x5 |
+ x1 := x2 := x3 := x4 := x5 := false.
+ p :=
+ [
+ [:return |
+ [ Processor activeProcess suspend.
+ [ ] ensure: [
+ [ ] ensure: [
+ x1 := true].
+ x2 := true]
+ ] ensure: [
+ return value.
+ x3 := true].
+ x4 := true.
+ ] valueWithExit.
+ x5 := true.
+ ] newProcess.
+ p resume.
+ Processor yield.
+ "make sure p is suspended and none of the unwind blocks has finished yet"
+ self assert: p isSuspended.
+ self deny: x1 | x2 | x3 | x4 | x5.
+ "now terminate the process and make sure all unwind blocks have finished"
+ p terminate.
+ self assert: p isTerminated.
+ self deny: x1 & x2 & x3 & x4 & x5!
Item was added:
+ ----- Method: ProcessUnwindTest>>testTerminateNestedEnsureWithReturn2 (in category 'tests') -----
+ testTerminateNestedEnsureWithReturn2
+ "Terminate suspended process.
+ Test all nested unwind blocks are correctly executed;
+ all unwind blocks halfway through their execution should be completed."
+
+ | p x1 x2 x3 x4 x5 |
+ x1 := x2 := x3 := x4 := x5 := false.
+ p :=
+ [
+ [:return |
+ [
+ [Processor activeProcess suspend] ensure: [
+ [ ] ensure: [
+ x1 := true].
+ return value.
+ x2 := true]
+ ] ensure: [
+ x3 := true].
+ x4 := true.
+ ] valueWithExit.
+ x5 := true.
+ ] newProcess.
+ p resume.
+ Processor yield.
+ "make sure p is suspended and none of the unwind blocks has finished yet"
+ self assert: p isSuspended.
+ self deny: x1 | x2 | x3 | x4 | x5.
+ "now terminate the process and make sure all unwind blocks have finished"
+ p terminate.
+ self assert: p isTerminated.
+ self deny: x1 & x2 & x3 & x4 & x5!
Item was added:
+ ----- Method: SemaphoreTest>>testSemaAfterCriticalWaitSuspended (in category 'tests') -----
+ testSemaAfterCriticalWaitSuspended "self run: #testSemaAfterCriticalWaitSuspended"
+ "This tests whether a semaphore that has just left the wait in Semaphore>>critical: but
+ has been suspended before termination, leaves it with signaling the associated semaphore."
+ | s p |
+ s := Semaphore new.
+ p := [s critical:[]] forkAt: Processor activePriority-1.
+ "wait until p entered the critical section"
+ [p suspendingList == s] whileFalse:[(Delay forMilliseconds: 10) wait].
+ "Now that p entered it, signal the semaphore. p now 'owns' the semaphore
+ but since we are running at higher priority than p it will not get to do
+ anything."
+ s signal.
+ self assert: p suspendingList class == LinkedList.
+ p suspend.
+ self assert: p suspendingList == nil.
+ p terminate.
+ self assert: 1 equals: s excessSignals!
More information about the Squeak-dev
mailing list
|