'From Cuis 2.0 of 4 January 2010 [latest update: #393] on 11 February 2010 at 11:15:14 am'!

!Delay commentStamp: 'laza 9/5/2009 08:45' prior: 0!
I am the main way that a process may pause for some amount of time.  The simplest usage is like this:

	(Delay forSeconds: 5) wait.

An instance of Delay responds to the message 'wait' by suspending the caller's process for a certain amount of time. The duration of the pause is specified when the Delay is created with the message forMilliseconds: or forSeconds:. A Delay can be used again when the current wait has finished. For example, a clock process might repeatedly wait on a one-second Delay.

A delay in progress when an image snapshot is saved is resumed when the snapshot is re-started. Delays work across millisecond clock roll-overs.


For a more complex example, see  #testDelayOf:for:rect: .

A word of advice:
This is THE highest priority code which is run in Squeak, in other words it is time-critical. The speed of this code is critical for accurate responses, it is critical for network services, it affects every last part of the system.

In short: Don't fix it if it ain't broken!! This code isn't supposed to be beautiful, it's supposed to be fast!! The reason for duplicating code is to make it fast. The reason for not using ifNil:[]ifNotNil:[] is that the compiler may not inline those. Since the effect of changes are VERY hard to predict it is best to leave things as they are for now unless there is an actual need to change anything!


!Process methodsFor: 'changing process state' stamp: 'ar 3/24/2009 16:31'!
terminate 
	"Stop the process that the receiver represents forever.  Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."

	| ctxt unwindBlock oldList |
	self isActiveProcess ifTrue: [
		ctxt := thisContext.
		[	ctxt := ctxt findNextUnwindContextUpTo: nil.
			ctxt isNil
		] whileFalse: [
			(ctxt tempAt: 2) ifNil:[
				ctxt tempAt: 2 put: nil.
				unwindBlock := ctxt tempAt: 1.
				thisContext terminateTo: ctxt.
				unwindBlock value].
		].
		thisContext terminateTo: nil.
		self suspend.
	] ifFalse:[
		"Always suspend the process first so it doesn't accidentally get woken up"
		oldList := self suspend.
		suspendedContext ifNotNil:[
			"Figure out if we are terminating the process while waiting in Semaphore>>critical:
			In this case, pop the suspendedContext so that we leave the ensure: block inside
			Semaphore>>critical: without signaling the semaphore."
			(oldList class == Semaphore and:[
				suspendedContext method == (Semaphore compiledMethodAt: #critical:)]) ifTrue:[
					suspendedContext := suspendedContext home.
			].
			ctxt := self popTo: suspendedContext bottomContext.
			ctxt == suspendedContext bottomContext ifFalse: [
				self debug: ctxt title: 'Unwind error during termination']].
	].
! !

!Process methodsFor: 'changing suspended state' stamp: 'nk 7/10/2004 11:16'!
restartTopWith: method
	"Rollback top context and replace with new method.  Assumes self is suspended"

	method isQuick 
		ifTrue: [ self popTo: suspendedContext sender ]
		ifFalse: [ suspendedContext privRefreshWith: method ].
! !

!Process methodsFor: 'accessing' stamp: 'bgf 12/31/2008 11:56'!
isTerminated

	self isActiveProcess ifTrue: [^ false].
	^suspendedContext isNil
	  or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
		   If so, and the pc is greater than the startpc, the bock has alrteady sent and returned
		   from value and there is nothing more to do."
		suspendedContext isBottomContext
		and: [suspendedContext pc > suspendedContext startpc]]! !


!Semaphore methodsFor: 'mutual exclusion' stamp: 'nice 12/26/2009 00:08'!
critical: mutuallyExcludedBlock			
	"Evaluate mutuallyExcludedBlock only if the receiver is not currently in
	the process of running the critical: message. If the receiver is, evaluate
	mutuallyExcludedBlock after the other critical: message is finished."
	| caught |
	caught := false.
	^[
		caught := true.
		self wait.
		mutuallyExcludedBlock value
	] ensure: [caught ifTrue: [self signal]]
! !

