moo/moo/kernel/Process.moo

406 lines
7.9 KiB
Smalltalk
Raw Normal View History

class(#pointer,#final,#limited) Process(Object)
2015-10-15 14:40:08 +00:00
{
var initial_context, current_context, state, sp, prev, next, sem, perr, perrmsg.
method prev { ^self.prev }
method next { ^self.next }
2015-10-15 14:40:08 +00:00
method next: process { self.next := process }
method prev: process { self.prev := process }
2015-10-15 14:40:08 +00:00
method primError { ^self.perr }
method primErrorMessage { ^self.perrmsg }
2015-10-18 15:06:17 +00:00
method(#primitive) resume.
method(#primitive) yield.
method(#primitive) _terminate.
method(#primitive) _suspend.
method terminate
{
2017-07-21 16:54:43 +00:00
##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.
## ----------------------------------------------------------------------------------------------------------
2017-07-21 16:54:43 +00:00
##if (Processor activeProcess ~~ self) { self _suspend }.
if (thisProcess ~~ self) { self _suspend }.
self.current_context unwindTo: self.initial_context return: nil.
^self _terminate
}
method sp
{
^self.sp.
}
method initialContext
{
^self.initial_context
}
2015-10-15 14:40:08 +00:00
}
class Semaphore(Object)
{
var count := 0,
waiting_head := nil,
waiting_tail := nil,
heapIndex := -1,
fireTimeSec := 0,
fireTimeNsec := 0,
ioIndex := -1,
2017-07-21 16:54:43 +00:00
ioHandle := nil,
ioMask := 0.
method(#class) forMutualExclusion
2016-05-18 15:10:00 +00:00
{
| sem |
sem := self new.
sem signal.
^sem
}
## ==================================================================
method(#primitive) signal.
method(#primitive) wait.
2016-03-16 02:27:18 +00:00
(*
method waitWithTimeout: seconds
{
<primitive: #_semaphore_wait>
self primitiveFailed
}
method waitWithTimeout: seconds and: nanoSeconds
{
<primitive: #_semaphore_wait>
self primitiveFailed
}
*)
method critical: aBlock
{
self wait.
^aBlock ensure: [ self signal ]
}
## ==================================================================
method heapIndex
2016-03-16 02:27:18 +00:00
{
^heapIndex
}
method heapIndex: anIndex
2016-03-16 02:27:18 +00:00
{
heapIndex := anIndex
}
method fireTime
2016-03-16 02:27:18 +00:00
{
^fireTimeSec
2016-03-16 02:27:18 +00:00
}
method fireTime: anInteger
2016-03-16 02:27:18 +00:00
{
self.fireTimeSec := anInteger.
2016-03-16 02:27:18 +00:00
}
method youngerThan: aSemaphore
2016-03-16 02:27:18 +00:00
{
^self.fireTimeSec < (aSemaphore fireTime)
2016-03-16 02:27:18 +00:00
}
2017-07-21 16:54:43 +00:00
method notYoungerThan: aSemaphore
{
^self.fireTimeSec >= (aSemaphore fireTime)
}
2016-03-16 02:27:18 +00:00
}
class SemaphoreHeap(Object)
2016-03-16 02:27:18 +00:00
{
var arr, size.
2016-03-16 02:27:18 +00:00
method initialize
2016-03-16 02:27:18 +00:00
{
self.size := 0.
self.arr := Array new: 100.
}
method size
2016-03-16 02:27:18 +00:00
{
^self.size
}
method at: anIndex
{
^self.arr at: anIndex.
}
method insert: aSemaphore
2016-03-16 02:27:18 +00:00
{
2016-03-16 14:05:34 +00:00
| index |
index := self.size.
(index >= (self.arr size)) ifTrue: [
2016-03-16 02:27:18 +00:00
| newarr newsize |
newsize := (self.arr size) * 2.
newarr := Array new: newsize.
newarr copy: self.arr.
self.arr := newarr.
].
2016-03-16 14:05:34 +00:00
self.arr at: index put: aSemaphore.
aSemaphore heapIndex: index.
2016-03-16 02:27:18 +00:00
self.size := self.size + 1.
2016-03-16 14:05:34 +00:00
^self siftUp: index
2016-03-16 02:27:18 +00:00
}
method popTop
2016-03-16 02:27:18 +00:00
{
| top |
2016-03-16 14:05:34 +00:00
top := self.arr at: 0.
self deleteAt: 0.
2016-03-16 02:27:18 +00:00
^top
}
method updateAt: anIndex with: aSemaphore
2016-03-16 02:27:18 +00:00
{
| item |
item := self.arr at: anIndex.
item heapIndex: -1.
self.arr at: anIndex put: aSemaphore.
aSemaphore heapIndex: anIndex.
2017-07-21 16:54:43 +00:00
^if (aSemaphore youngerThan: item) { self siftUp: anIndex } else { self siftDown: anIndex }.
2016-03-16 02:27:18 +00:00
}
method deleteAt: anIndex
2016-03-16 02:27:18 +00:00
{
2017-07-21 16:54:43 +00:00
| item xitem |
2016-03-16 02:27:18 +00:00
item := self.arr at: anIndex.
item heapIndex: -1.
2016-03-16 14:05:34 +00:00
self.size := self.size - 1.
2017-07-21 16:54:43 +00:00
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 }.
}
2016-03-16 02:27:18 +00:00
}
method parentIndex: anIndex
2016-03-16 02:27:18 +00:00
{
2016-03-16 14:05:34 +00:00
^(anIndex - 1) quo: 2
2016-03-16 02:27:18 +00:00
}
method leftChildIndex: anIndex
2016-03-16 02:27:18 +00:00
{
2016-03-16 14:05:34 +00:00
^(anIndex * 2) + 1.
2016-03-16 02:27:18 +00:00
}
method rightChildIndex: anIndex
2016-03-16 02:27:18 +00:00
{
2016-03-16 14:05:34 +00:00
^(anIndex * 2) + 2.
2016-03-16 02:27:18 +00:00
}
method siftUp: anIndex
2016-03-16 02:27:18 +00:00
{
2017-07-21 16:54:43 +00:00
| pindex cindex par item |
2016-03-16 02:27:18 +00:00
2017-07-21 16:54:43 +00:00
if (anIndex <= 0) { ^anIndex }.
2016-03-16 02:27:18 +00:00
pindex := anIndex.
item := self.arr at: anIndex.
2016-03-16 02:27:18 +00:00
2017-07-21 16:54:43 +00:00
while (true)
{
2016-03-16 02:27:18 +00:00
cindex := pindex.
2017-07-21 16:54:43 +00:00
if (pindex <= 0) { break }.
pindex := self parentIndex: cindex.
par := self.arr at: pindex.
if (item notYoungerThan: par) { break }.
2016-03-16 02:27:18 +00:00
2017-07-21 16:54:43 +00:00
## 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.
2016-03-16 02:27:18 +00:00
^cindex
}
method siftDown: anIndex
2016-03-16 02:27:18 +00:00
{
2017-07-21 16:54:43 +00:00
| base capa cindex item
left right younger xitem |
2016-03-16 02:27:18 +00:00
2016-03-16 14:05:34 +00:00
base := self.size quo: 2.
2017-07-21 16:54:43 +00:00
if (anIndex >= base) { ^anIndex }.
2016-03-16 02:27:18 +00:00
cindex := anIndex.
item := self.arr at: cindex.
2017-07-21 16:54:43 +00:00
while (cindex < base)
{
2016-03-16 02:27:18 +00:00
left := self leftChildIndex: cindex.
right := self rightChildIndex: cindex.
2017-07-21 16:54:43 +00:00
younger := if ((right < self.size) and: [(self.arr at: right) youngerThan: (self.arr at: left)]) { right } else { left }.
2016-03-16 02:27:18 +00:00
xitem := self.arr at: younger.
2017-07-21 16:54:43 +00:00
if (item youngerThan: xitem) { break }.
self.arr at: cindex put: xitem.
xitem heapIndex: cindex.
cindex := younger.
}.
2016-03-16 02:27:18 +00:00
self.arr at: cindex put: item.
item heapIndex: cindex.
^cindex
}
}
class(#final,#limited) ProcessScheduler(Object)
2015-10-15 14:40:08 +00:00
{
2017-07-21 16:54:43 +00:00
var(#get) tally, active.
var runnable_head, runnable_tail (*, sem_heap*).
2015-10-15 14:40:08 +00:00
method activeProcess
2015-10-15 14:40:08 +00:00
{
^self.active.
}
method resume: process
{
<primitive: #_processor_schedule>
self primitiveFailed.
2015-10-15 14:40:08 +00:00
2017-07-21 16:54:43 +00:00
(* The primitive does something like the following in principle:
(self.tally == 0)
2015-10-15 14:40:08 +00:00
ifTrue: [
self.head := process.
self.tail := process.
2015-10-15 14:40:08 +00:00
self.tally := 1.
]
ifFalse: [
process next: self.head.
self.head prev: process.
self.head := process.
2015-10-15 14:40:08 +00:00
self.tally := self.tally + 1.
].
2017-07-21 16:54:43 +00:00
*)
2015-10-18 15:06:17 +00:00
}
2017-07-21 16:54:43 +00:00
(* -------------------
method yield
2015-10-15 14:40:08 +00:00
{
<primitive: #_processor_yield>
2015-10-15 14:40:08 +00:00
self primitiveFailed
}
2017-07-21 16:54:43 +00:00
----------------- *)
2016-03-16 02:27:18 +00:00
method signal: semaphore after: secs
2016-03-16 02:27:18 +00:00
{
<primitive: #_processor_add_timed_semaphore>
self primitiveFailed.
}
method signal: semaphore after: secs and: nanosecs
{
<primitive: #_processor_add_timed_semaphore>
self primitiveFailed.
2016-03-16 02:27:18 +00:00
}
method unsignal: semaphore
{
<primitive: #_processor_remove_semaphore>
self primitiveFailed.
}
method signal: semaphore onInput: file
{
<primitive: #_processor_add_input_semaphore>
self primitiveFailed.
}
method signal: semaphore onOutput: file
{
<primitive: #_processor_add_output_semaphore>
self primitiveFailed.
}
method signal: semaphore onInOutput: file
{
<primitive: #_processor_add_inoutput_semaphore>
self primitiveFailed.
}
method return: object to: context
{
<primitive: #_processor_return_to>
self primitiveFailed.
}
method sleepFor: secs
{
## -----------------------------------------------------
## put the calling process to sleep for given seconds.
## -----------------------------------------------------
| s |
s := Semaphore new.
self signal: s after: secs.
s wait.
}
method sleepFor: secs and: nanosecs
{
## -----------------------------------------------------
## put the calling process to sleep for given seconds.
## -----------------------------------------------------
| s |
s := Semaphore new.
self signal: s after: secs and: nanosecs
s wait.
}
2015-10-15 14:40:08 +00:00
}