
class(#pointer,#final,#limited) Process(Object)
{
	var(#get) initialContext, currentContext, id, state.
	var sp.
	var(#get) ps_prev, ps_next, sem_wait_prev, sem_wait_next.
	var sem, perr, perrmsg.

	method primError { ^self.perr }
	method primErrorMessage { ^self.perrmsg }

	method(#primitive) sp.

	method(#primitive) resume.
	method(#primitive) yield.
	method(#primitive) suspend.
	method(#primitive) _terminate.

	method terminate
	{
		## search from the top context of the process down to intial_context and find ensure blocks and execute them.
		## if a different process calls 'terminate' on a process,
		## the ensureblock is not executed in the context of the
		## process being terminated, but in the context of terminatig process.
		##
		## 1) process termianted by another process
		##   p := [ 
		##       [  1 to: 10000 by: 1 do: [:ex | System logNl: i asString] ] ensure: [System logNl: 'ensured....'] 
		##   ] newProcess.
		##   p resume.
		##   p terminate.
		##
		## 2) process terminated by itself
		##   p := [ 
		##       [ thisProcess terminate. ] ensure: [System logNl: 'ensured....'] 
		##   ] newProcess.
		##   p resume.
		##   p terminate.
		## ----------------------------------------------------------------------------------------------------------
		## the process must be frozen first. while unwinding is performed, 
		## the process must not be scheduled.
		## ----------------------------------------------------------------------------------------------------------

		##if (Processor activeProcess ~~ self) { self suspend }.
		if (thisProcess ~~ self) { self suspend }.
		self.currentContext unwindTo: self.initialContext return: nil.
		^self _terminate
	}
}

class Semaphore(Object)
{
	var waiting_head  := nil,
	    waiting_tail  := nil,
	    count         :=   0.

	var(#get,#set) heapIndex := -1.

	var fireTimeSec   :=   0,
	    fireTimeNsec  :=   0,
	    ioIndex       :=  -1,
	    ioHandle      := nil,
	    ioMask        :=   0.

	var(#get,#set) signalAction := nil.

	var(#get,#set) _group := nil, 
	               _grm_next := nil,
	               _grm_prev := nil.

	## ==================================================================

	method(#primitive) signal.
	method(#primitive) _wait.

	method wait
	{
		| k |
		k := self _wait.
		if (self.signalAction notNil) { self.signalAction value: self }.
		^k
	}

	## ==================================================================

	method fireTime
	{
		^fireTimeSec
	}

	method fireTime: anInteger
	{
		self.fireTimeSec := anInteger.
	}

	method youngerThan: aSemaphore
	{
		^self.fireTimeSec < (aSemaphore fireTime)
	}

	method notYoungerThan: aSemaphore
	{
		^self.fireTimeSec >= (aSemaphore fireTime)
	}
}

class Mutex(Semaphore)
{
	method(#class) new
	{
		| s |
		s := super new.
		s signal.
		^s.
	}

(*
TODO: how to prohibit wait and signal???
	method(#prohibited) wait.
	method(#prohibited) signal.
*)

	method lock  { ^super wait }
	method unlock { ^super signal }

	method critical: block
	{
		self wait.
		^block ensure: [ self signal ]
	}
}

 
(*
 xxx := Semaphore new.
 xxx on: #signal do: [ ].
 
 
 ========= CASE 1 ====================
 sg := SemaphoreGroup with (xxx, yyy, zzz).
 System signal: xxx onInput: aaa.
 System signal: yyy onInput: bbb.
 System signal: zzz onOutput: ccc.
 
 while (true)
 {
	sem := sg wait.
	if (sem == xxx)
	{
		
	}
	elsif (sem == yyy)
	{
	}
	elsif (sem == zzz)
	{
	}.
 }
 
 ============ CASE 2====================
 ### ASSOCIATE CALLBACK WITH SEMAPHORE.
 
 sg := SemaphoreGroup with (xxx, yyy, zzz).
 
 oldaction := xxx signalAction: [ ... ].  ### similar interface like unix system call signal()????   method signalAction: block {} , method signalAction { ^self.signalAction }
 yyy signalAction: [ ... ].
 zzz signalAction: [ ... ].
 
 System signal: xxx onInput: aaa.
 System signal: yyy onInput: bbb.
 System signal: zzz onOutput: ccc.
 
 
 while (true)
 {
	sem := sg wait. ### the action associated with the semaphore must get executed.  => wait may be a primitive. the primitive handler may return failure... if so, the actual primitive body can execute the action easily
 }
 
 
 Semaphore>>method wait 
 {
	<primitive: #Semaphore_wait>
	if (errorCode == NO ERROR)
	{
		self.signalAction value.  ## which is better???
		self.sginalAction value: self.
	}
 } 
*)
 

class SemaphoreGroup(Object)
{
	var waiting_head  := nil,
	    waiting_tail  := nil,
	    first_sem := nil,
	    last_sem := nil,
	    first_sigsem := nil,
	    last_sigsem := nil,
	    sem_io_count := 0.

(* TODO: good idea to a shortcut way to prohibit a certain method in the heirarchy chain?
method(#class,#prohibited) new.
method(#class,#prohibited) new: size.
method(#class,#abstract) xxx. => method(#class) xxx { self subclassResponsibility: #xxxx }
*)

(*
	method(#class) new { self messageProhibited: #new }
	method(#class) new: size { self messageProhibited: #new: }
*)

	method(#primitive) addSemaphore: sem.
	method(#primitive) removeSemaphore: sem.
	method(#primitive) _wait.

	method wait
	{
		| x |
		x := self _wait.
		if (x isError) { Exception signal: ('Cannot wait on a semaphore - ' & x asString) }.
		if (x signalAction notNil) { x signalAction value: x }.
		^x
	}

	method _waitWithTimeout: seconds
	{
		| s r |

		## create an internal semaphore for timeout notification.
		s := Semaphore _new.
		if (s isError) { ^s }.

		## grant the partial membership to the internal semaphore.
		## it's partial because it's not added to self.semarr.
		##s _group: self. 
		if ((r := (self addSemaphore: s)) isError) { ^r }.

		## arrange the processor to notify upon timeout.
		if ((r := (System _signal: s after: seconds)) isError) { ^r }.

		if ((r := self _wait) isError) 
		{
			System _unsignal: s.
			^r.
		}.

		## if the internal semaphore has been signaled, 
		## arrange to return nil to indicate timeout.
		if (r == s) { r := nil }
		elsif (r signalAction notNil) { r signalAction value: r }.

		## nullify the membership
		self _removeSemaphore: s.

		## cancel the notification arrangement in case it didn't time out.
		System _unsignal: s.

		^r.
	}

	method waitWithTimeout: seconds
	{
		| r |
		r := self _waitWithTimeout: seconds.
		if (r isError)  
		{
			Exception signal: 'Error has occurred...' error: r.
		}.
		^r
	}

(*
	method waitWithTimeout: seconds
	{
		| s r |

		## create an internal semaphore for timeout notification.
		s := Semaphore new. 

		## grant the partial membership to the internal semaphore.
		## it's partial because it's not added to self.semarr.
		##s _group: self. 
		self addSemaphore: s.

		## arrange the processor to notify upon timeout.
		System signal: s after: seconds.

		[
			## wait on the semaphore group.
			r := self wait.
		] on: Exception do: [:ex |
			System _unsignal: s.
			ex throw
		].

		## if the internal semaphore has been signaled, 
		## arrange to return nil to indicate timeout.
		if (r == s) { r := nil }
		elsif (r signalAction notNil) { r signalAction value: r }.

		## nullify the membership
		self removeSemaphore: s.

		## cancel the notification arrangement in case it didn't time out.
		System unsignal: s.

		^r.
	} 
*)
}

class SemaphoreHeap(Object)
{
	var arr, size.

	method initialize
	{
		self.size := 0.
		self.arr := Array new: 100.
	}

	method size
	{
		^self.size
	}

	method at: anIndex
	{
		^self.arr at: anIndex.
	}

	method insert: aSemaphore
	{
		| index newarr newsize |

		index := self.size.
		if (index >= (self.arr size)) 
		{
			newsize := (self.arr size) * 2.
			newarr := Array new: newsize.
			newarr copy: self.arr.
			self.arr := newarr.
		}.

		self.arr at: index put: aSemaphore.
		aSemaphore heapIndex: index.
		self.size := self.size + 1.

		^self siftUp: index
	}

	method popTop
	{
		| top |

		top := self.arr at: 0.
		self deleteAt: 0.
		^top
	}

	method updateAt: anIndex with: aSemaphore
	{
		| item |

		item := self.arr at: anIndex.
		item heapIndex: -1.

		self.arr at: anIndex put: aSemaphore.
		aSemaphore heapIndex: anIndex.

		^if (aSemaphore youngerThan: item) { self siftUp: anIndex } else { self siftDown: anIndex }.
	}

	method deleteAt: anIndex
	{
		| item xitem |

		item := self.arr at: anIndex.
		item heapIndex: -1.

		self.size := self.size - 1.
		if (anIndex == self.size) 
		{
			## the last item
			self.arr at: self.size put: nil.
		}
		else
		{
			xitem := self.arr at: self.size.
			self.arr at: anIndex put: xitem.
			xitem heapIndex: anIndex.
			self.arr at: self.size put: nil.
			if (xitem youngerThan: item) { self siftUp: anIndex } else { self siftDown: anIndex }.
		}
	}

	method parentIndex: anIndex
	{
		^(anIndex - 1) quo: 2
	}

	method leftChildIndex: anIndex
	{
		^(anIndex * 2) + 1.
	}

	method rightChildIndex: anIndex
	{
		 ^(anIndex * 2) + 2.
	}

	method siftUp: anIndex
	{
		| pindex cindex par item |

		if (anIndex <= 0) { ^anIndex }.

		pindex := anIndex.
		item := self.arr at: anIndex.

		while (true)
		{
			cindex := pindex.

			if (pindex <= 0) { break }.

			pindex := self parentIndex: cindex.
			par := self.arr at: pindex.

			if (item notYoungerThan: par)  { break }.

			## item is younger than the parent. 
			## move the parent down
			self.arr at: cindex put: par.
			par heapIndex: cindex.
		}.

		## place the item as high as it can
		self.arr at: cindex put: item.
		item heapIndex: cindex.

		^cindex
	}

	method siftDown: anIndex
	{
		| base capa cindex item 
		  left right younger xitem |

		base := self.size quo: 2.
		if (anIndex >= base) { ^anIndex }.

		cindex := anIndex.
		item := self.arr at: cindex.

		while (cindex < base) 
		{
			left := self leftChildIndex: cindex.
			right := self rightChildIndex: cindex.

			younger := if ((right < self.size) and: [(self.arr at: right) youngerThan: (self.arr at: left)]) { right } else { left }.

			xitem := self.arr at: younger.
			if (item youngerThan: xitem)  { break }.

			self.arr at: cindex put: xitem.
			xitem heapIndex: cindex.
			cindex := younger.
		}.

		self.arr at: cindex put: item.
		item heapIndex: cindex.

		^cindex
	}
}

class(#final,#limited) ProcessScheduler(Object)
{
	var(#get) active, should_exit := false, total_count := 0.
	var(#get) runnable_count := 0.
	var runnable_head, runnable_tail.
	var(#get) suspended_count := 0.
	var suspended_head, suspended_tail.

	method activeProcess
	{
		^self.active.
	}

	method resume: process
	{
		<primitive: #_processor_schedule>
		self primitiveFailed.

		(* The primitive does something like the following in principle:
		(self.tally == 0)
			ifTrue: [
				self.head := process.
				self.tail := process.
				self.tally := 1.
			]
			ifFalse: [
				process ps_next: self.head.
				self.head ps_prev: process.
				self.head := process.
				self.tally := self.tally + 1.
			].
		*)
	}
}
