problem debugging <Over> - correctly sequencing debug of multi-threaded code per process priorities
I'm not sure if I'm doing the wrong thing, or if I've bumped into a problem with step <Over>. I'm trying to add some debugging support into multi-threaded code to help properly sequence debugging different priority processes. I've extracted a little demo... TestCase subclass: #Example instanceVariableNames: 'doCycle debug highPriorityProcess' classVariableNames: '' package: 'KernelX-DelayScheduler' Example >> highPriorityCycle debug ifTrue: [ self halt ]. Transcript show: 'H'. Example >> highPriorityRunLoop doCycle := Semaphore new. ^[ [ doCycle wait. self highPriorityCycle ] repeat. ] forkAt: 45 named: 'Example high side' Process >> isWaiting ^myList isKindOf: Semaphore Example >> wakeHighPriorityLoop doCycle signal. debug ifTrue: [ "wait until high priority process is sleeping" [ highPriorityProcess isWaiting & highPriorityProcess isTerminated not] whileFalse: [ Transcript show: '.'. 100 milliSeconds wait ]. self halt ]. Example >> testUserPriority debug := true. highPriorityProcess := self highPriorityRunLoop. Transcript cr. debug ifTrue: [self halt]. 3 timesRepeat: [ Transcript crShow: 'U'. self wakeHighPriorityLoop.]. highPriorityProcess terminate. Running #testUserPriority, on Transcript you'll see.... UH UH UH _______________ Changing "debug := true" and run #testUserPriority and the UI will lockup, until "TestTookTooMuchTime" appears. But it works with the following change... ClyRunTestsFromMethodsCommand >> runTest: testSelector of: testClass [ | testResult | testResult := testClass debug: testSelector. self notifyUserAboutResults: testResult with: 'Method: ' , testClass asString , '>>#' , testSelector asString ] forkNamed: 'TESTING ' , testClass asString , '>>#' , testSelector asString Now running #testUserPriority and pressing <Proceed> at each pre-debug window gives the following result... U................H U..............H U............H It also works properly to run #testUserPriority and debug <Into> #wakeHighPriorityLoop initially ignoring the #highPriorityCycle pre-debug that pops up to step around the #whileFalse: loop a few times. Then <Proceed>ing the #highPriorityCycle pre-debug and stepping until out of #wakeHighPriorityLoop. Works fine. However running #testUserPriority, debugging into #wakeHighPriorityLoop but stepping <Over> #wakeHighPriorityLoop locks up the UI, and I can't tell why. Can anyone advise? cheers -ben P.S. What I'm trying to do it make it easier for others to trace the operation of the delay scheduler to understand its unit tests.
On 13 June 2018 at 11:46, Ben Coman <btc@openinworld.com> wrote:
I'm not sure if I'm doing the wrong thing, or if I've bumped into a problem with step <Over>. I'm trying to add some debugging support into multi-threaded code to help properly sequence debugging different priority processes. I've extracted a little demo...
TestCase subclass: #Example instanceVariableNames: 'doCycle debug highPriorityProcess' classVariableNames: '' package: 'KernelX-DelayScheduler'
Example >> highPriorityCycle debug ifTrue: [ self halt ]. Transcript show: 'H'.
Example >> highPriorityRunLoop doCycle := Semaphore new. ^[ [ doCycle wait. self highPriorityCycle ] repeat. ] forkAt: 45 named: 'Example high side'
Process >> isWaiting ^myList isKindOf: Semaphore
Example >> wakeHighPriorityLoop doCycle signal. debug ifTrue: [ "wait until high priority process is sleeping" [ highPriorityProcess isWaiting & highPriorityProcess isTerminated not] whileFalse: [ Transcript show: '.'. 100 milliSeconds wait ]. self halt ].
Example >> testUserPriority debug := true.
Sorry, the above line should have been "debug := false" and this stage of the post. cheers -ben
highPriorityProcess := self highPriorityRunLoop. Transcript cr. debug ifTrue: [self halt]. 3 timesRepeat: [ Transcript crShow: 'U'. self wakeHighPriorityLoop.]. highPriorityProcess terminate.
Running #testUserPriority, on Transcript you'll see.... UH UH UH
_______________ Changing "debug := true" and run #testUserPriority and the UI will lockup, until "TestTookTooMuchTime" appears. But it works with the following change...
ClyRunTestsFromMethodsCommand >> runTest: testSelector of: testClass [ | testResult | testResult := testClass debug: testSelector. self notifyUserAboutResults: testResult with: 'Method: ' , testClass asString , '>>#' , testSelector asString ] forkNamed: 'TESTING ' , testClass asString , '>>#' , testSelector asString
Now running #testUserPriority and pressing <Proceed> at each pre-debug window gives the following result...
U................H U..............H U............H
It also works properly to run #testUserPriority and debug <Into> #wakeHighPriorityLoop initially ignoring the #highPriorityCycle pre-debug that pops up to step around the #whileFalse: loop a few times. Then <Proceed>ing the #highPriorityCycle pre-debug and stepping until out of #wakeHighPriorityLoop. Works fine.
However running #testUserPriority, debugging into #wakeHighPriorityLoop but stepping <Over> #wakeHighPriorityLoop locks up the UI, and I can't tell why.
Can anyone advise?
cheers -ben
P.S. What I'm trying to do it make it easier for others to trace the operation of the delay scheduler to understand its unit tests.
On 13 June 2018 at 11:46, Ben Coman <btc@openinworld.com> wrote:
I'm not sure if I'm doing the wrong thing, or if I've bumped into a problem with step <Over>. I'm trying to add some debugging support into multi-threaded code to help properly sequence debugging different priority processes. I've extracted a little demo...
TestCase subclass: #Example instanceVariableNames: 'doCycle debug highPriorityProcess' classVariableNames: '' package: 'KernelX-DelayScheduler'
Example >> highPriorityCycle debug ifTrue: [ self halt ]. Transcript show: 'H'.
Example >> highPriorityRunLoop doCycle := Semaphore new. ^[ [ doCycle wait. self highPriorityCycle ] repeat. ] forkAt: 45 named: 'Example high side'
Process >> isWaiting ^myList isKindOf: Semaphore
Example >> wakeHighPriorityLoop doCycle signal. debug ifTrue: [ "wait until high priority process is sleeping" [ highPriorityProcess isWaiting & highPriorityProcess isTerminated not] whileFalse: [ Transcript show: '.'. 100 milliSeconds wait ]. self halt ].
To make this example simpler, I changed this method to... Example >> wakeHighPriorityLoop |count| count := 0. [ Transcript show: '.'. count := count + 1. count > 10 ifTrue: [^self]. 200 milliSeconds wait. ] repeat.
Example >> testUserPriority debug := true. highPriorityProcess := self highPriorityRunLoop. Transcript cr. debug ifTrue: [self halt]. 3 timesRepeat: [ Transcript crShow: 'U'. self wakeHighPriorityLoop.]. highPriorityProcess terminate.
and this method to... Example >> testUserPriority [ 3 timesRepeat: [ Transcript crShow: 'U'. self halt. self wakeHighPriorityLoop.]. ] forkAt: 39 named: 'testUserPriority'. self halt. highPriorityProcess terminate. So there should be no way that the 39-priority thread should block the 40-priority UI thread. But when I run #testUserPriority and step <Over> #wakeHighPriorityLoop the UI blocks for two seconds and then all of a sudden "U..........." appears in full on the Transcript shows. I'd expect to see the dots slowly appearing one-by-one. I really don't understand the behaviour I'm seeing. cheers -ben
participants (1)
-
Ben Coman