[squeak-dev] Re: Process bug introduced in 3.10

Igor Stasenko siguctua at gmail.com
Sun Apr 27 20:26:14 UTC 2008


2008/4/27  <bryce at kampjes.demon.co.uk>:
>
>  Good point, but I can reproduce the bug without using MessageTally
>  or any class variables. ExuperyProfiler doesn't use class variables.
>
>  The following will reproduce it:
>    TestProfiler>>spyOn: aBlock
>         | myDelay millisecs timer |
>         millisecs := 1.
>         (aBlock isMemberOf: BlockContext) ifFalse:
>             [self error: 'spy needs a block here'].
>         myDelay := Delay forMilliseconds: millisecs.
>         timer := [[true] whileTrue:
>                                         [myDelay wait].
>                          nil] newProcess.
>         timer priority: Processor userInterruptPriority.
>         "activate the probe and evaluate the block"
>         timer resume.
>         aBlock ensure: [timer terminate].
>         ^ self
>

Ok, here we see a scheduler stress test. Given that infinite loop
running at higher priority, and you having 10 concurrent loops, there
is a good chance that processes with lower priorities will starve
forever (never gain control to evaluate anything).

Lets analyze why it can be. The Delay interrupt watcher uses single
semaphore and single primitive to tell VM when to signal it.
So, whenever this semaphore get signaled, a #timerInterruptWatcher
gains control, takes active delay and signals delay's semaphore.
Then it takes another delay and if its not yet elapsed, waits for it
.. and so on.

So, what we having :
- 10 processes with highest priority, each waiting for 1 msec delay
-  1 process with highest priority (a #timerInterruptWatcher)
- 10 processes with user priority each waiting 500 msec delay.

Squeak's scheduler never passing control to lower priority process if
there are higher priority process waiting to be executed, right?
To have a chance for process at user priority to be executed, we
should have 10+1 processes waiting for semaphore at some point of
time, which is very unlikely (consider time, which interpreter need to
spend to switch processes and reschedule 10 delays - it may be more
than 1 msec), so this leads to an infinite loop which bounces between
11 topmost priority processes.

In ideal environment, where all processes running in parallel, your
code SHOULD work. But we not in ideal environment, and squeak's
scheduler design having own limits in this regard :)

>   100 timesRepeat:
>         [processes := (1 to: 10) collect: [:each| [[(TestProfiler new spyOn: [(Delay forMilliseconds: 500) wait]) ] repeat] fork ].
>         (Delay forSeconds: 1) wait.
>         processes do: [:each| each terminate]]
>
>  TestProfiler is a new subclass of Object without any variables or
>  any other methods.
>
>  I'm not convinced this is a new bug with 3.10. It feels similar to
>  something I've encountered earlier. It is happening frequently in
>  3.10 but not in 3.9.
>
>  Bryce
>
>



-- 
Best regards,
Igor Stasenko AKA sig.



More information about the Squeak-dev mailing list