[comp.lang.smalltalk] Time Slicing

rb@otter.hpl.hp.com (Richard Brown) (05/16/91)

Does anyone have any code to do some simple time slicing. I want to
ensure that a user background task that I have running is guaranteed
at least 75% of the cpu time. In particular, I want to guard against locking
the background task out by the user constantly moving the mouse.

I have tried a few things but I keep locking up the user interface and then 
am forced to hit ^C.

Any help is welcome.

Richard Brown

rb@otter.hpl.hp.com (Richard Brown) (05/23/91)

Well I have had no response to this question so far, but this is the
solution that I have implemented. I am still having a few problems
with it. It seems that when the time slicer is running (-ie when I an
running a back ground task but still want the user interface to run),
if I then start another activity using fork, the user interface
occasionally locks up. The background tasks continue to run to
completion and attempt to display their results, but the
ScheduledWindow which is popped up remains blank. It is not until I
type ^C that all returns to normal. It seems that something was
waiting on a Semaphore. The problem seems to be minimised if I fork at
user background priority always. If I fork at userScheduling priority,
then the problem occurs more often.

I know this explanation is probably not too clear but it is quite
complicated. If anyone has a better and more resilient time slicing
mechanism, I would love to hear about it. Perhaps put your solution on
this note.

(This is for Smalltalk Rel4 running on an HP9000/375 work station).

------------------------------------------------------------------------------

Object subclass: #TimeSlicer
	instanceVariableNames: 'evaluationBlocks timeSlicerProcess timeSlicerEnabled uiDelay processDelay '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Time Slicing'!


!TimeSlicer methodsFor: 'time slicing'!

disableTimeSlicing

	^timeSlicerEnabled := false.!

enableTimeSlicing

	^timeSlicerEnabled := true.!

startTimeSlicer

	"Continue to time slice whilst we have blocks to evaluate.

	 Time slicing is achieved by stopping the user interface for periods of time (uiDelay) and then allowing it
	 to run again for a period of time (processDelay). The reason we have implemented a time slicer because
	 it is possible to lock out low priority processes simply by continually moving the mouse. This mechanism
	 guarantees the user process a proportion of the cpu time."

	timeSlicerProcess notNil ifTrue: [^nil].

	timeSlicerProcess := [
		[(evaluationBlocks isEmpty not) & timeSlicerEnabled]
		whileTrue: [
			evaluationBlocks do:
				[:block |
					block notNil
					ifTrue: [
						block value
						ifFalse: [evaluationBlocks remove: block]
						ifTrue: [
							| ioProcess |
							ioProcess := ScheduledControllers activeControllerProcess.
							ioProcess suspend.
							Cursor execute show.
							uiDelay wait.
							ioProcess resume.
							Cursor normal show.
							processDelay wait.]]]].

		timeSlicerProcess := nil] forkAt: (Processor userInterruptPriority).!

timeSliceWhile: aBlock

	evaluationBlocks add: aBlock.
	self startTimeSlicer.! !

!TimeSlicer methodsFor: 'accessing'!

timeSlicerEnabled

	^timeSlicerEnabled.!

timeSlicerEnabled: aBoolean

	^timeSlicerEnabled := aBoolean.! !

!TimeSlicer methodsFor: 'initialization'!

initialize

	evaluationBlocks := OrderedCollection new.
	timeSlicerProcess := nil.
	timeSlicerEnabled := true.
	uiDelay := Delay forMilliseconds: 200.
	processDelay := Delay forMilliseconds: 200.! !