Hello guys,

Yesterday I had this problem that at startup a pharo image has several
process running at priority 40. The problem is that my tests (run from
command line) trigger #valueWithin:onTimeout: and the protected block (the
block calling #valueWithin:onTimeout:) would always timed out for the first
test as resuming the watchdog in #valueWithin:onTimeout: allows another
runnable process at the same priority as the active process to be run.

Example:

Here we have two process at the activePriority, the second process takes
100ms to be run and as the transcript shows, the protected block always
times out because this other process is started after the watchdog so
during the protected block activation.

| p endTime |
p := Processor activeProcess priority.
[ 'Process2Start' logCr.
endTime := Time millisecondClockValue + 100.
 [ Time millisecondClockValue > endTime ] whileFalse: [ 1 + 2 + 3 ].
'Process2End' logCr. ] forkAt: p.
[ 'protected' logCr] valueWithin: 0.05 second onTimeout: [ 'timeout' logCr
].

Transcript displays:
'Process2Start'
'Process2End'
'timeout'

I'm not very familiar with Pharo's process framework nor with processes in
general so I would like to discuss the problem.

*Question 1: Is it a bug ?*


I fixed it by adding a Processor yield just before resuming the watchdog in
#valueWithin:onTimeout: to allow other runnable process at the
activePriority to be run before the protected block and therefore
forbidding other process started outside of the protected block to trigger
the time out. No process can be started in between the Processor yield and
watchdog resume.

*Question 2: Can someone tell me if this code looks ok ? I've just added
Processor yield.*

valueWithin: aDuration onTimeout: timeoutBlock
"Evaluate the receiver.
 If the evaluation does not complete in less than aDuration evaluate the
timeoutBlock instead"

| theProcess delay watchdog tag |

aDuration <= Duration zero ifTrue: [^ timeoutBlock value ].

"the block will be executed in the current process"
 theProcess := Processor activeProcess.
delay := aDuration asDelay.
tag := self.

"make a watchdog process"
watchdog := [
delay wait. "wait for timeout or completion"
 theProcess ifNotNil:[ theProcess signalException: (TimedOut new tag: tag)]
] newProcess.

 "Watchdog needs to run at high priority to do its job (but not at timing
priority)"
watchdog priority: Processor timingPriority-1.

*Processor yield.*

"catch the timeout signal"
^ [ watchdog resume. "start up the watchdog"
 self ensure:[ "evaluate the receiver"
theProcess := nil. "it has completed, so ..."
 delay delaySemaphore signal. "arrange for the watchdog to exit"
]] on: TimedOut do: [ :e |
 e tag == tag
ifTrue:[ timeoutBlock value ]
ifFalse:[ e pass]].

Reply via email to