'From Cuis 1.0 of 4 September 2009 [latest update: #290] on 22 September 2009 at 11:07:46 am'!

!BlockContext methodsFor: 'private' stamp: 'jmv 9/22/2009 10:15'!
grabProcessorFor: milliseconds onTimeout: timeoutBlock
	"Evaluate the receiver (block), without the possibility of preemption by regular priority processes.
	If not finished after milliseconds, restore original priority and evaluate timeoutBlock.
	Use with care!!"
	"Based on #valueUnpreemptively"
	
	| activeProcess oldPriority result done |
	activeProcess _ Processor activeProcess.
	oldPriority _ activeProcess priority.
	done _ false.
	
	activeProcess priority: Processor highIOPriority + Processor lowIOPriority // 2.
	milliseconds notNil ifTrue: [
		[
			(Delay forMilliseconds: milliseconds) wait.
			done ifFalse: [
				activeProcess
					suspend;
					priority: oldPriority;
					resume.
				timeoutBlock value ]
		] forkAt: Processor highIOPriority ].

	result _ self ensure: [
		done _ true.
		activeProcess priority: oldPriority].
	
	"Yield after restoring priority to give the preempted processes a chance to run"
	Processor yield.
	^result! !


!TestCase methodsFor: 'Printing' stamp: 'jmv 9/22/2009 09:00'!
printOn: aStream

	aStream
		nextPutAll: self class printString;
		nextPutAll: '>>#';
		nextPutAll: (testSelector ifNil: [ 'unknown' ])
			! !


!ProcessorTest methodsFor: 'as yet unclassified' stamp: 'jmv 9/22/2009 11:00'!
testGrabProcessor
	| done consistentState tries updates observations timeForAThousand iterationsFor50MSecs semaphore waitStart waited totalWait |
	timeForAThousand _ [ self wasteTime: 1000 ] timeToRun.
	iterationsFor50MSecs _ 50 * 1000 // timeForAThousand.
	consistentState _ true.
	tries _ 50.
	updates _ 0.
	done _ false.
	semaphore _ Semaphore new.
	[
		tries timesRepeat: [
			semaphore wait.
			[
				consistentState _ false.
				self wasteTime: iterationsFor50MSecs atRandom.	"process for some time between 0 and 50 mSecs"
				updates _ updates + 1.
				consistentState _ true
			] grabProcessor
		].
		done _ true
	] forkAt: Processor activeProcess priority -1.

	observations _ 0.
	totalWait _ 0.
	[ done ] whileFalse: [
		semaphore signal.
		waitStart _ Time millisecondClockValue.
		(Delay forMilliseconds: 25) wait.
		waited _ Time millisecondClockValue - waitStart.
		totalWait _ totalWait + waited.
		observations _ observations + 1.
		self assert: consistentState description: 'The low priority process was preempted in inconsistent state!!'.
	].

	self
		assert: updates = tries
		description: 'Too few updates done. It seems as if the low priority process was not allowed to finish processing'.
	self
		assert: observations = tries
		description: 'Too few observations done. It seems as if the low priority process was was never suspended'.
	self
		assert: (1.0 * totalWait / observations) < 40	"Mean value should be around 32"
		description: 'The low priority process was not preempted at the end of #grabProcessor'! !

!ProcessorTest methodsFor: 'as yet unclassified' stamp: 'jmv 9/22/2009 11:01'!
testGrabProcessorOnlyForNoTimeout
	| done consistentState tries updates observations timeForAThousand iterationsFor50MSecs semaphore waitStart waited totalWait |
	timeForAThousand _ [ self wasteTime: 1000 ] timeToRun.
	iterationsFor50MSecs _ 50 * 1000 // timeForAThousand.
	consistentState _ true.
	tries _ 50.
	updates _ 0.
	done _ false.
	semaphore _ Semaphore new.
	[
		tries timesRepeat: [
			semaphore wait.
			[
				consistentState _ false.
				self wasteTime: iterationsFor50MSecs atRandom.	"process for some time between 0 and 50 mSecs"
				updates _ updates + 1.
				consistentState _ true
			] grabProcessorOnlyFor: 1000
		].
		done _ true
	] forkAt: Processor activeProcess priority -1.

	observations _ 0.
	totalWait _ 0.
	[ done ] whileFalse: [
		semaphore signal.
		waitStart _ Time millisecondClockValue.
		(Delay forMilliseconds: 25) wait.
		waited _ Time millisecondClockValue - waitStart.
		totalWait _ totalWait + waited.
		observations _ observations + 1.
		self assert: consistentState description: 'The low priority process was preempted in inconsistent state!!'.
	].

	self
		assert: updates = tries
		description: 'Too few updates done. It seems as if the low priority process was not allowed to finish processing'.
	self
		assert: observations = tries
		description: 'Too few observations done. It seems as if the low priority process was was never suspended'.
	self
		assert: (1.0 * totalWait / observations) < 40	"Mean value should be around 32"
		description: 'The low priority process was not preempted at the end of #grabProcessor'! !

!ProcessorTest methodsFor: 'as yet unclassified' stamp: 'jmv 9/22/2009 11:07'!
testGrabProcessorOnlyForTimeout
	| done consistentState tries updates observations timeForAThousand iterationsFor50MSecs semaphore waitStart waited totalWait consistentCount inconsistentCount |
	timeForAThousand _ [ self wasteTime: 1000 ] timeToRun.
	iterationsFor50MSecs _ 50 * 1000 // timeForAThousand.
	consistentState _ true.
	tries _ 50.
	updates _ 0.
	consistentCount _ 0.
	inconsistentCount _ 0.
	done _ false.
	semaphore _ Semaphore new.
	[
		tries timesRepeat: [
			semaphore wait.
			[
				consistentState _ false.
				self wasteTime: iterationsFor50MSecs atRandom.	"process for some time between 0 and 50 mSecs"
				updates _ updates + 1.
				consistentState _ true
			] grabProcessorOnlyFor: 25
		].
		done _ true
	] forkAt: Processor activeProcess priority -1.

	observations _ 0.
	totalWait _ 0.
	[ done ] whileFalse: [
		semaphore signal.
		waitStart _ Time millisecondClockValue.
		(Delay forMilliseconds: 15) wait.
		waited _ Time millisecondClockValue - waitStart.
		totalWait _ totalWait + waited.
		observations _ observations + 1.
		consistentState
			ifTrue: [ consistentCount _ consistentCount + 1 ]
			ifFalse: [ inconsistentCount _ inconsistentCount + 1 ].
		"If it needs time to finish, at low priority, allow for it."
		[ consistentState ] whileFalse: [ (Delay forMilliseconds: 2) wait ].
	].
	self
		assert: updates = tries
		description: 'Too few updates done. It seems as if the low priority process was not allowed to finish processing'.
	self
		assert: observations = tries
		description: 'Too few observations done. It seems as if the low priority process was was never suspended'.
	self
		assert: (1.0 * totalWait / observations) < 30	"Mean value should be around 25"
		description: 'The low priority process was not preempted at the tiemout'.
	self
		assert: consistentCount > 10
		description: 'It seems the low priority process was preempted before the timeout'.
	self
		assert: inconsistentCount > 10
		description: 'It seems the low priority process was not preempted at the timeout'! !

!ProcessorTest methodsFor: 'as yet unclassified' stamp: 'jmv 9/22/2009 11:01'!
testValueUnpreemptively
	| done consistentState tries updates observations timeForAThousand iterationsFor50MSecs semaphore waitStart waited totalWait |
	timeForAThousand _ [ self wasteTime: 1000 ] timeToRun.
	iterationsFor50MSecs _ 50 * 1000 // timeForAThousand.
	consistentState _ true.
	tries _ 50.
	updates _ 0.
	done _ false.
	semaphore _ Semaphore new.
	[
		tries timesRepeat: [
			semaphore wait.
			[
				consistentState _ false.
				self wasteTime: iterationsFor50MSecs atRandom.	"process for some time between 0 and 50 mSecs"
				updates _ updates + 1.
				consistentState _ true
			] valueUnpreemptively
		].
		done _ true
	] forkAt: Processor activeProcess priority -1.

	observations _ 0.
	totalWait _ 0.
	[ done ] whileFalse: [
		semaphore signal.
		waitStart _ Time millisecondClockValue.
		(Delay forMilliseconds: 25) wait.
		waited _ Time millisecondClockValue - waitStart.
		totalWait _ totalWait + waited.
		observations _ observations + 1.
		self assert: consistentState description: 'The low priority process was preempted in inconsistent state!!'.
	].

	self
		assert: updates = tries
		description: 'Too few updates done. It seems as if the low priority process was not allowed to finish processing'.
	self
		assert: observations = tries
		description: 'Too few observations done. It seems as if the low priority process was was never suspended'.
	self
		assert: (1.0 * totalWait / observations) < 40	"Mean value should be around 32"
		description: 'The low priority process was not preempted at the end of #grabProcessor'! !

!ProcessorTest methodsFor: 'private' stamp: 'jmv 9/22/2009 09:42'!
wasteTime: iterations
	iterations timesRepeat: [1.23 asString asNumber]! !

