enhanced finalization handling further
This commit is contained in:
parent
03fd02d59b
commit
7412ae0dac
@ -19,7 +19,7 @@ class(#pointer,#final,#limited) Process(Object)
|
|||||||
|
|
||||||
method terminate
|
method terminate
|
||||||
{
|
{
|
||||||
##search from the top contextof the process down to intial_context and find ensure blocks and execute them.
|
##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,
|
## if a different process calls 'terminate' on a process,
|
||||||
## the ensureblock is not executed in the context of the
|
## the ensureblock is not executed in the context of the
|
||||||
## process being terminated, but in the context of terminatig process.
|
## process being terminated, but in the context of terminatig process.
|
||||||
@ -42,8 +42,8 @@ class(#pointer,#final,#limited) Process(Object)
|
|||||||
## the process must not be scheduled.
|
## the process must not be scheduled.
|
||||||
## ----------------------------------------------------------------------------------------------------------
|
## ----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
##(Processor activeProcess ~~ self) ifTrue: [ self _suspend ].
|
##if (Processor activeProcess ~~ self) { self _suspend }.
|
||||||
(thisProcess ~~ self) ifTrue: [ self _suspend ].
|
if (thisProcess ~~ self) { self _suspend }.
|
||||||
self.current_context unwindTo: self.initial_context return: nil.
|
self.current_context unwindTo: self.initial_context return: nil.
|
||||||
^self _terminate
|
^self _terminate
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ class Semaphore(Object)
|
|||||||
fireTimeSec := 0,
|
fireTimeSec := 0,
|
||||||
fireTimeNsec := 0,
|
fireTimeNsec := 0,
|
||||||
ioIndex := -1,
|
ioIndex := -1,
|
||||||
ioData := nil,
|
ioHandle := nil,
|
||||||
ioMask := 0.
|
ioMask := 0.
|
||||||
|
|
||||||
method(#class) forMutualExclusion
|
method(#class) forMutualExclusion
|
||||||
@ -129,6 +129,11 @@ class Semaphore(Object)
|
|||||||
{
|
{
|
||||||
^self.fireTimeSec < (aSemaphore fireTime)
|
^self.fireTimeSec < (aSemaphore fireTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
method notYoungerThan: aSemaphore
|
||||||
|
{
|
||||||
|
^self.fireTimeSec >= (aSemaphore fireTime)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SemaphoreHeap(Object)
|
class SemaphoreHeap(Object)
|
||||||
@ -190,36 +195,30 @@ class SemaphoreHeap(Object)
|
|||||||
self.arr at: anIndex put: aSemaphore.
|
self.arr at: anIndex put: aSemaphore.
|
||||||
aSemaphore heapIndex: anIndex.
|
aSemaphore heapIndex: anIndex.
|
||||||
|
|
||||||
^(aSemaphore youngerThan: item)
|
^if (aSemaphore youngerThan: item) { self siftUp: anIndex } else { self siftDown: anIndex }.
|
||||||
ifTrue: [ self siftUp: anIndex ]
|
|
||||||
ifFalse: [ self siftDown: anIndex ].
|
|
||||||
}
|
}
|
||||||
|
|
||||||
method deleteAt: anIndex
|
method deleteAt: anIndex
|
||||||
{
|
{
|
||||||
| item |
|
| item xitem |
|
||||||
|
|
||||||
item := self.arr at: anIndex.
|
item := self.arr at: anIndex.
|
||||||
item heapIndex: -1.
|
item heapIndex: -1.
|
||||||
|
|
||||||
self.size := self.size - 1.
|
self.size := self.size - 1.
|
||||||
(anIndex == self.size)
|
if (anIndex == self.size)
|
||||||
ifTrue: [
|
{
|
||||||
"the last item"
|
## the last item
|
||||||
self.arr at: self.size put: nil.
|
self.arr at: self.size put: nil.
|
||||||
]
|
}
|
||||||
ifFalse: [
|
else
|
||||||
| xitem |
|
{
|
||||||
|
xitem := self.arr at: self.size.
|
||||||
xitem := self.arr at: self.size.
|
self.arr at: anIndex put: xitem.
|
||||||
self.arr at: anIndex put: xitem.
|
xitem heapIndex: anIndex.
|
||||||
xitem heapIndex: anIndex.
|
self.arr at: self.size put: nil.
|
||||||
self.arr at: self.size put: nil.
|
if (xitem youngerThan: item) { self siftUp: anIndex } else { self siftDown: anIndex }.
|
||||||
|
}
|
||||||
(xitem youngerThan: item)
|
|
||||||
ifTrue: [self siftUp: anIndex ]
|
|
||||||
ifFalse: [self siftDown: anIndex ]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
method parentIndex: anIndex
|
method parentIndex: anIndex
|
||||||
@ -239,34 +238,31 @@ class SemaphoreHeap(Object)
|
|||||||
|
|
||||||
method siftUp: anIndex
|
method siftUp: anIndex
|
||||||
{
|
{
|
||||||
| pindex cindex par item stop |
|
| pindex cindex par item |
|
||||||
|
|
||||||
(anIndex <= 0) ifTrue: [ ^anIndex ].
|
if (anIndex <= 0) { ^anIndex }.
|
||||||
|
|
||||||
pindex := anIndex.
|
pindex := anIndex.
|
||||||
item := self.arr at: anIndex.
|
item := self.arr at: anIndex.
|
||||||
|
|
||||||
stop := false.
|
while (true)
|
||||||
[ stop ] whileFalse: [
|
{
|
||||||
|
|
||||||
cindex := pindex.
|
cindex := pindex.
|
||||||
|
|
||||||
(cindex > 0)
|
if (pindex <= 0) { break }.
|
||||||
ifTrue: [
|
|
||||||
pindex := self parentIndex: cindex.
|
|
||||||
par := self.arr at: pindex.
|
|
||||||
|
|
||||||
(item youngerThan: par)
|
pindex := self parentIndex: cindex.
|
||||||
ifTrue: [
|
par := self.arr at: pindex.
|
||||||
## move the parent down
|
|
||||||
self.arr at: cindex put: par.
|
|
||||||
par heapIndex: cindex.
|
|
||||||
]
|
|
||||||
ifFalse: [ stop := true ].
|
|
||||||
]
|
|
||||||
ifFalse: [ stop := true ].
|
|
||||||
].
|
|
||||||
|
|
||||||
|
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.
|
self.arr at: cindex put: item.
|
||||||
item heapIndex: cindex.
|
item heapIndex: cindex.
|
||||||
|
|
||||||
@ -275,36 +271,29 @@ class SemaphoreHeap(Object)
|
|||||||
|
|
||||||
method siftDown: anIndex
|
method siftDown: anIndex
|
||||||
{
|
{
|
||||||
| base capa cindex item |
|
| base capa cindex item
|
||||||
|
left right younger xitem |
|
||||||
|
|
||||||
base := self.size quo: 2.
|
base := self.size quo: 2.
|
||||||
(anIndex >= base) ifTrue: [^anIndex].
|
if (anIndex >= base) { ^anIndex }.
|
||||||
|
|
||||||
cindex := anIndex.
|
cindex := anIndex.
|
||||||
item := self.arr at: cindex.
|
item := self.arr at: cindex.
|
||||||
|
|
||||||
[ cindex < base ] whileTrue: [
|
while (cindex < base)
|
||||||
| left right younger xitem |
|
{
|
||||||
|
|
||||||
left := self leftChildIndex: cindex.
|
left := self leftChildIndex: cindex.
|
||||||
right := self rightChildIndex: cindex.
|
right := self rightChildIndex: cindex.
|
||||||
|
|
||||||
((right < self.size) and: [(self.arr at: right) youngerThan: (self.arr at: left)])
|
younger := if ((right < self.size) and: [(self.arr at: right) youngerThan: (self.arr at: left)]) { right } else { left }.
|
||||||
ifTrue: [ younger := right ]
|
|
||||||
ifFalse: [ younger := left ].
|
|
||||||
|
|
||||||
xitem := self.arr at: younger.
|
xitem := self.arr at: younger.
|
||||||
(item youngerThan: xitem)
|
if (item youngerThan: xitem) { break }.
|
||||||
ifTrue: [
|
|
||||||
"break the loop"
|
self.arr at: cindex put: xitem.
|
||||||
base := anIndex
|
xitem heapIndex: cindex.
|
||||||
]
|
cindex := younger.
|
||||||
ifFalse: [
|
}.
|
||||||
self.arr at: cindex put: xitem.
|
|
||||||
xitem heapIndex: cindex.
|
|
||||||
cindex := younger.
|
|
||||||
]
|
|
||||||
].
|
|
||||||
|
|
||||||
self.arr at: cindex put: item.
|
self.arr at: cindex put: item.
|
||||||
item heapIndex: cindex.
|
item heapIndex: cindex.
|
||||||
@ -315,13 +304,8 @@ class SemaphoreHeap(Object)
|
|||||||
|
|
||||||
class(#final,#limited) ProcessScheduler(Object)
|
class(#final,#limited) ProcessScheduler(Object)
|
||||||
{
|
{
|
||||||
var tally, active, runnable_head, runnable_tail, sem_heap.
|
var(#get) tally, active.
|
||||||
|
var runnable_head, runnable_tail (*, sem_heap*).
|
||||||
method new
|
|
||||||
{
|
|
||||||
"instantiation is not allowed"
|
|
||||||
^nil. "TODO: raise an exception"
|
|
||||||
}
|
|
||||||
|
|
||||||
method activeProcess
|
method activeProcess
|
||||||
{
|
{
|
||||||
@ -333,8 +317,8 @@ class(#final,#limited) ProcessScheduler(Object)
|
|||||||
<primitive: #_processor_schedule>
|
<primitive: #_processor_schedule>
|
||||||
self primitiveFailed.
|
self primitiveFailed.
|
||||||
|
|
||||||
"The primitive does something like the following in principle:
|
(* The primitive does something like the following in principle:
|
||||||
(self.tally = 0)
|
(self.tally == 0)
|
||||||
ifTrue: [
|
ifTrue: [
|
||||||
self.head := process.
|
self.head := process.
|
||||||
self.tail := process.
|
self.tail := process.
|
||||||
@ -346,16 +330,16 @@ class(#final,#limited) ProcessScheduler(Object)
|
|||||||
self.head := process.
|
self.head := process.
|
||||||
self.tally := self.tally + 1.
|
self.tally := self.tally + 1.
|
||||||
].
|
].
|
||||||
"
|
*)
|
||||||
}
|
}
|
||||||
|
|
||||||
"
|
(* -------------------
|
||||||
method yield
|
method yield
|
||||||
{
|
{
|
||||||
<primitive: #_processor_yield>
|
<primitive: #_processor_yield>
|
||||||
self primitiveFailed
|
self primitiveFailed
|
||||||
}
|
}
|
||||||
"
|
----------------- *)
|
||||||
|
|
||||||
method signal: semaphore after: secs
|
method signal: semaphore after: secs
|
||||||
{
|
{
|
||||||
|
@ -32,23 +32,36 @@ class System(Apex)
|
|||||||
|
|
||||||
method(#class) __gc_finalizer
|
method(#class) __gc_finalizer
|
||||||
{
|
{
|
||||||
| tmp |
|
| tmp gc |
|
||||||
|
|
||||||
|
gc := false.
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
## TODO: exit from this loop when there are no other processes running.
|
## TODO: exit from this loop when there are no other processes running except this finalizer process
|
||||||
while ((tmp := self _popCollectable) notError)
|
while ((tmp := self _popCollectable) notError)
|
||||||
{
|
{
|
||||||
## TODO: Do i have to protected this in an exception handler???
|
## TODO: Do i have to protected this in an exception handler???
|
||||||
tmp finalize.
|
if (tmp respondsTo: #finalize) { tmp finalize }.
|
||||||
}.
|
}.
|
||||||
|
|
||||||
System logNl: 'gc_waiting....'.
|
(*
|
||||||
Processor sleepFor: 1. ## TODO: wait on semaphore instead..
|
if (Processor tally == 1 and: [Processor active == thisProcess])
|
||||||
|
{
|
||||||
|
if (gc) { break }.
|
||||||
|
|
||||||
|
self collectGarbage.
|
||||||
|
'GC GC GC GC' dump.
|
||||||
|
Processor tally dump.
|
||||||
|
gc := true.
|
||||||
|
}.*)
|
||||||
|
|
||||||
|
##System logNl: 'gc_waiting....'.
|
||||||
|
##Processor sleepFor: 1. ## TODO: wait on semaphore instead..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
method(#class,#primitive) _popCollectable.
|
method(#class,#primitive) _popCollectable.
|
||||||
|
method(#class,#primitive) collectGarbage.
|
||||||
}
|
}
|
||||||
|
|
||||||
pooldic System.Log
|
pooldic System.Log
|
||||||
|
@ -618,10 +618,11 @@ extend X11
|
|||||||
'CLOSING X11 EVENT LOOP' dump.
|
'CLOSING X11 EVENT LOOP' dump.
|
||||||
|
|
||||||
Processor unsignal: self.event_loop_sem.
|
Processor unsignal: self.event_loop_sem.
|
||||||
|
## TODO: LOOK HERE FOR RACE CONDITION
|
||||||
self.event_loop_sem := nil.
|
self.event_loop_sem := nil.
|
||||||
|
self.event_loop_proc := nil.
|
||||||
|
|
||||||
self dispose.
|
self dispose.
|
||||||
|
|
||||||
] fork.
|
] fork.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,6 +631,7 @@ extend X11
|
|||||||
{
|
{
|
||||||
if (self.event_loop_sem notNil)
|
if (self.event_loop_sem notNil)
|
||||||
{
|
{
|
||||||
|
## TODO: handle race-condition with the part maked 'LOOK HERE FOR RACE CONDITION'
|
||||||
self.event_loop_proc terminate.
|
self.event_loop_proc terminate.
|
||||||
self.event_loop_proc := nil.
|
self.event_loop_proc := nil.
|
||||||
self.event_loop_sem := nil.
|
self.event_loop_sem := nil.
|
||||||
@ -704,14 +706,19 @@ extend X11
|
|||||||
|
|
||||||
class Fx(Object)
|
class Fx(Object)
|
||||||
{
|
{
|
||||||
|
var(#class) X := 20.
|
||||||
|
var x.
|
||||||
|
|
||||||
method initialize
|
method initialize
|
||||||
{
|
{
|
||||||
|
self.X := self.X + 1.
|
||||||
|
self.x := self.X.
|
||||||
self addToBeFinalized.
|
self addToBeFinalized.
|
||||||
}
|
}
|
||||||
|
|
||||||
method finalize
|
method finalize
|
||||||
{
|
{
|
||||||
System logNl: 'Greate... FX instance finalized'.
|
System logNl: ('Greate... FX instance finalized' & self.x asString).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,6 +729,7 @@ class MyObject(Object)
|
|||||||
method main1
|
method main1
|
||||||
{
|
{
|
||||||
| comp1 |
|
| comp1 |
|
||||||
|
|
||||||
self.disp1 := X11 new.
|
self.disp1 := X11 new.
|
||||||
self.disp2 := X11 new.
|
self.disp2 := X11 new.
|
||||||
|
|
||||||
@ -755,11 +763,9 @@ class MyObject(Object)
|
|||||||
self.disp1 enterEventLoop. ## this is not a blocking call. it spawns another process.
|
self.disp1 enterEventLoop. ## this is not a blocking call. it spawns another process.
|
||||||
self.disp2 enterEventLoop.
|
self.disp2 enterEventLoop.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
comp1 := Fx new.
|
comp1 := Fx new.
|
||||||
Fx new.
|
Fx new.
|
||||||
Fx new.
|
comp1 := Fx new.
|
||||||
Fx new.
|
Fx new.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,38 @@ class MyObject(Object)
|
|||||||
^a
|
^a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
method(#class) test_semaphore_heap
|
||||||
|
{
|
||||||
|
| sempq a |
|
||||||
|
sempq := SemaphoreHeap new.
|
||||||
|
|
||||||
|
'--------------------------' dump.
|
||||||
|
|
||||||
|
1 to: 200 by: 1 do: [ :i |
|
||||||
|
| sem |
|
||||||
|
sem := Semaphore new.
|
||||||
|
sem fireTime: (200 - i).
|
||||||
|
sempq insert: sem
|
||||||
|
].
|
||||||
|
|
||||||
|
'--------------------------' dump.
|
||||||
|
sempq deleteAt: 40.
|
||||||
|
sempq deleteAt: 50.
|
||||||
|
sempq deleteAt: 100.
|
||||||
|
|
||||||
|
|
||||||
|
a := -100.
|
||||||
|
[sempq size > 0] whileTrue: [
|
||||||
|
| sem b |
|
||||||
|
sem := sempq popTop.
|
||||||
|
b := sem fireTime.
|
||||||
|
if (a > b) { ^false }.
|
||||||
|
a := b.
|
||||||
|
].
|
||||||
|
|
||||||
|
^true
|
||||||
|
}
|
||||||
|
|
||||||
method(#class) main
|
method(#class) main
|
||||||
{
|
{
|
||||||
| tc limit |
|
| tc limit |
|
||||||
@ -24,7 +56,8 @@ class MyObject(Object)
|
|||||||
tc := %(
|
tc := %(
|
||||||
## 0 - 4
|
## 0 - 4
|
||||||
[ self proc1 == 100 ],
|
[ self proc1 == 100 ],
|
||||||
[ Processor sleepFor: 2. self proc1 == 200 ]
|
[ Processor sleepFor: 2. self proc1 == 200 ],
|
||||||
|
[ self test_semaphore_heap == true ]
|
||||||
).
|
).
|
||||||
|
|
||||||
limit := tc size.
|
limit := tc size.
|
||||||
@ -33,7 +66,7 @@ class MyObject(Object)
|
|||||||
| tb |
|
| tb |
|
||||||
tb := tc at: idx.
|
tb := tc at: idx.
|
||||||
System log(System.Log.INFO, idx asString, (if (tb value) { ' PASS' } else { ' FAIL' }), S'\n').
|
System log(System.Log.INFO, idx asString, (if (tb value) { ' PASS' } else { ' FAIL' }), S'\n').
|
||||||
]
|
].
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ static moo_oop_process_t make_process (moo_t* moo, moo_oop_context_t c)
|
|||||||
#if defined(MOO_DEBUG_VM_PROCESSOR)
|
#if defined(MOO_DEBUG_VM_PROCESSOR)
|
||||||
MOO_LOG2 (moo, MOO_LOG_IC | MOO_LOG_DEBUG, "Processor - made process %O of size %zu\n", proc, MOO_OBJ_GET_SIZE(proc));
|
MOO_LOG2 (moo, MOO_LOG_IC | MOO_LOG_DEBUG, "Processor - made process %O of size %zu\n", proc, MOO_OBJ_GET_SIZE(proc));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,9 +255,9 @@ static MOO_INLINE int chain_into_processor (moo_t* moo, moo_oop_process_t proc)
|
|||||||
MOO_ASSERT (moo, tally >= 0);
|
MOO_ASSERT (moo, tally >= 0);
|
||||||
if (tally >= MOO_SMOOI_MAX)
|
if (tally >= MOO_SMOOI_MAX)
|
||||||
{
|
{
|
||||||
#if defined(MOO_DEBUG_VM_PROCESSOR)
|
#if defined(MOO_DEBUG_VM_PROCESSOR)
|
||||||
MOO_LOG0 (moo, MOO_LOG_IC | MOO_LOG_FATAL, "Processor - too many process\n");
|
MOO_LOG0 (moo, MOO_LOG_IC | MOO_LOG_FATAL, "Processor - too many processes\n");
|
||||||
#endif
|
#endif
|
||||||
moo_seterrnum (moo, MOO_EPFULL);
|
moo_seterrnum (moo, MOO_EPFULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -713,11 +714,13 @@ static void delete_from_sem_heap (moo_t* moo, moo_ooi_t index)
|
|||||||
{
|
{
|
||||||
moo_oop_semaphore_t sem, lastsem;
|
moo_oop_semaphore_t sem, lastsem;
|
||||||
|
|
||||||
|
MOO_ASSERT (moo, index >= 0 && index < moo->sem_heap_count);
|
||||||
|
|
||||||
sem = moo->sem_heap[index];
|
sem = moo->sem_heap[index];
|
||||||
sem->heap_index = MOO_SMOOI_TO_OOP(-1);
|
sem->heap_index = MOO_SMOOI_TO_OOP(-1);
|
||||||
|
|
||||||
moo->sem_heap_count--;
|
moo->sem_heap_count--;
|
||||||
if (moo->sem_heap_count > 0 && index != moo->sem_heap_count)
|
if (/*moo->sem_heap_count > 0 &&*/ index != moo->sem_heap_count)
|
||||||
{
|
{
|
||||||
/* move the last item to the deletion position */
|
/* move the last item to the deletion position */
|
||||||
lastsem = moo->sem_heap[moo->sem_heap_count];
|
lastsem = moo->sem_heap[moo->sem_heap_count];
|
||||||
@ -808,6 +811,7 @@ static int delete_from_sem_io (moo_t* moo, moo_ooi_t index)
|
|||||||
moo_oop_semaphore_t sem;
|
moo_oop_semaphore_t sem;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
|
MOO_ASSERT (moo, index >= 0 && index < moo->sem_io_count);
|
||||||
sem = moo->sem_io[index];
|
sem = moo->sem_io[index];
|
||||||
MOO_ASSERT (moo, index == MOO_OOP_TO_SMOOI(sem->io_index));
|
MOO_ASSERT (moo, index == MOO_OOP_TO_SMOOI(sem->io_index));
|
||||||
|
|
||||||
@ -824,7 +828,7 @@ static int delete_from_sem_io (moo_t* moo, moo_ooi_t index)
|
|||||||
sem->io_index = MOO_SMOOI_TO_OOP(-1);
|
sem->io_index = MOO_SMOOI_TO_OOP(-1);
|
||||||
|
|
||||||
moo->sem_io_count--;
|
moo->sem_io_count--;
|
||||||
if (moo->sem_io_count > 0 && index != moo->sem_io_count)
|
if (/*moo->sem_io_count > 0 &&*/ index != moo->sem_io_count)
|
||||||
{
|
{
|
||||||
moo_oop_semaphore_t lastsem;
|
moo_oop_semaphore_t lastsem;
|
||||||
|
|
||||||
@ -3071,11 +3075,18 @@ static moo_pfrc_t pf_system_log (moo_t* moo, moo_ooi_t nargs)
|
|||||||
return MOO_PF_SUCCESS;
|
return MOO_PF_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static moo_pfrc_t pf_system_collect_garbage (moo_t* moo, moo_ooi_t nargs)
|
||||||
|
{
|
||||||
|
moo_gc (moo);
|
||||||
|
MOO_STACK_SETRETTORCV (moo, nargs);
|
||||||
|
return MOO_PF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static moo_pfrc_t pf_system_pop_collectable (moo_t* moo, moo_ooi_t nargs)
|
static moo_pfrc_t pf_system_pop_collectable (moo_t* moo, moo_ooi_t nargs)
|
||||||
{
|
{
|
||||||
if (moo->collectable.first)
|
if (moo->collectable.first)
|
||||||
{
|
{
|
||||||
moo_collectable_t* first;
|
moo_finalizable_t* first;
|
||||||
|
|
||||||
first = moo->collectable.first;
|
first = moo->collectable.first;
|
||||||
|
|
||||||
@ -3086,11 +3097,8 @@ static moo_pfrc_t pf_system_pop_collectable (moo_t* moo, moo_ooi_t nargs)
|
|||||||
MOO_STACK_SETRET (moo, nargs, first->oop);
|
MOO_STACK_SETRET (moo, nargs, first->oop);
|
||||||
MOO_OBJ_SET_FLAGS_GCFIN (first->oop, MOO_OBJ_GET_FLAGS_GCFIN(first->oop) | MOO_GCFIN_FINALIZED);
|
MOO_OBJ_SET_FLAGS_GCFIN (first->oop, MOO_OBJ_GET_FLAGS_GCFIN(first->oop) | MOO_GCFIN_FINALIZED);
|
||||||
|
|
||||||
MOO_DEBUG1 (moo, "POPPING FINALIZABLE...%O\n", first->oop);
|
|
||||||
MOO_DELETE_FROM_LIST (&moo->collectable, first);
|
MOO_DELETE_FROM_LIST (&moo->collectable, first);
|
||||||
moo_freemem (moo, first);
|
moo_freemem (moo, first); /* TODO: move it to the free list instead... */
|
||||||
|
|
||||||
MOO_DEBUG1 (moo, "POPPED FINALIZABLE...%p\n", moo->collectable.first);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3982,6 +3990,7 @@ static pf_t pftab[] =
|
|||||||
{ "System__putUint32", { pf_system_put_uint32, 3, 3 } },
|
{ "System__putUint32", { pf_system_put_uint32, 3, 3 } },
|
||||||
{ "System__putUint64", { pf_system_put_uint64, 3, 3 } },
|
{ "System__putUint64", { pf_system_put_uint64, 3, 3 } },
|
||||||
|
|
||||||
|
{ "System_collectGarbage", { pf_system_collect_garbage, 0, 0 } },
|
||||||
{ "System_log", { pf_system_log, 2, MA } }
|
{ "System_log", { pf_system_log, 2, MA } }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
49
moo/lib/gc.c
49
moo/lib/gc.c
@ -551,6 +551,9 @@ static moo_uint8_t* scan_new_heap (moo_t* moo, moo_uint8_t* ptr)
|
|||||||
moo_oop_oop_t xtmp;
|
moo_oop_oop_t xtmp;
|
||||||
moo_oow_t size;
|
moo_oow_t size;
|
||||||
|
|
||||||
|
/* TODO: is it better to use a flag bit in the header to
|
||||||
|
* determine that it is an instance of process?
|
||||||
|
* for example, if (MOO_OBJ_GET_FLAGS_PROC(oop))... */
|
||||||
if (moo->_process && MOO_OBJ_GET_CLASS(oop) == moo->_process)
|
if (moo->_process && MOO_OBJ_GET_CLASS(oop) == moo->_process)
|
||||||
{
|
{
|
||||||
/* the stack in a process object doesn't need to be
|
/* the stack in a process object doesn't need to be
|
||||||
@ -620,7 +623,7 @@ void moo_gc (moo_t* moo)
|
|||||||
* move objects pointed to by the fields to the new heap.
|
* move objects pointed to by the fields to the new heap.
|
||||||
* finally perform some tricky symbol table clean-up.
|
* finally perform some tricky symbol table clean-up.
|
||||||
*/
|
*/
|
||||||
moo_uint8_t* ptr;
|
moo_uint8_t* scan_ptr;
|
||||||
moo_heap_t* tmp;
|
moo_heap_t* tmp;
|
||||||
moo_oop_t old_nil;
|
moo_oop_t old_nil;
|
||||||
moo_oow_t i;
|
moo_oow_t i;
|
||||||
@ -643,6 +646,8 @@ void moo_gc (moo_t* moo)
|
|||||||
"Starting GC curheap base %p ptr %p newheap base %p ptr %p\n",
|
"Starting GC curheap base %p ptr %p newheap base %p ptr %p\n",
|
||||||
moo->curheap->base, moo->curheap->ptr, moo->newheap->base, moo->newheap->ptr);
|
moo->curheap->base, moo->curheap->ptr, moo->newheap->base, moo->newheap->ptr);
|
||||||
|
|
||||||
|
scan_ptr = (moo_uint8_t*) MOO_ALIGN ((moo_uintptr_t)moo->newheap->base, MOO_SIZEOF(moo_oop_t));
|
||||||
|
|
||||||
/* TODO: allocate common objects like _nil and the root dictionary
|
/* TODO: allocate common objects like _nil and the root dictionary
|
||||||
* in the permanant heap. minimize moving around */
|
* in the permanant heap. minimize moving around */
|
||||||
old_nil = moo->_nil;
|
old_nil = moo->_nil;
|
||||||
@ -701,12 +706,11 @@ void moo_gc (moo_t* moo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* scan the new heap to move referenced objects */
|
/* scan the new heap to move referenced objects */
|
||||||
ptr = (moo_uint8_t*) MOO_ALIGN ((moo_uintptr_t)moo->newheap->base, MOO_SIZEOF(moo_oop_t));
|
scan_ptr = scan_new_heap (moo, scan_ptr);
|
||||||
ptr = scan_new_heap (moo, ptr);
|
|
||||||
|
|
||||||
/* FINALIZATION */
|
/* FINALIZATION */
|
||||||
move_finalizable_objects (moo);
|
move_finalizable_objects (moo);
|
||||||
ptr = scan_new_heap (moo, ptr);
|
scan_ptr = scan_new_heap (moo, scan_ptr);
|
||||||
/* END FINALIZATION */
|
/* END FINALIZATION */
|
||||||
|
|
||||||
/* traverse the symbol table for unreferenced symbols.
|
/* traverse the symbol table for unreferenced symbols.
|
||||||
@ -721,7 +725,7 @@ void moo_gc (moo_t* moo)
|
|||||||
/* scan the new heap again from the end position of
|
/* scan the new heap again from the end position of
|
||||||
* the previous scan to move referenced objects by
|
* the previous scan to move referenced objects by
|
||||||
* the symbol table. */
|
* the symbol table. */
|
||||||
ptr = scan_new_heap (moo, ptr);
|
scan_ptr = scan_new_heap (moo, scan_ptr);
|
||||||
|
|
||||||
/* the contents of the current heap is not needed any more.
|
/* the contents of the current heap is not needed any more.
|
||||||
* reset the upper bound to the base. don't forget to align the heap
|
* reset the upper bound to the base. don't forget to align the heap
|
||||||
@ -822,11 +826,10 @@ moo_oop_t moo_shallowcopy (moo_t* moo, moo_oop_t oop)
|
|||||||
|
|
||||||
int moo_regfinalizable (moo_t* moo, moo_oop_t oop)
|
int moo_regfinalizable (moo_t* moo, moo_oop_t oop)
|
||||||
{
|
{
|
||||||
moo_collectable_t* x;
|
moo_finalizable_t* x;
|
||||||
|
|
||||||
MOO_DEBUG1 (moo, "ADDING FINALIZABLE... %O\n", oop);
|
|
||||||
if (!MOO_OOP_IS_POINTER(oop) ||
|
if (!MOO_OOP_IS_POINTER(oop) || (MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)))
|
||||||
(MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)))
|
|
||||||
{
|
{
|
||||||
moo_seterrnum (moo, MOO_EINVAL);
|
moo_seterrnum (moo, MOO_EINVAL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -840,17 +843,15 @@ MOO_DEBUG1 (moo, "ADDING FINALIZABLE... %O\n", oop);
|
|||||||
|
|
||||||
MOO_APPEND_TO_LIST (&moo->finalizable, x);
|
MOO_APPEND_TO_LIST (&moo->finalizable, x);
|
||||||
|
|
||||||
MOO_DEBUG1 (moo, "ADDED FINALIZABLE... %O\n", oop);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int moo_deregfinalizable (moo_t* moo, moo_oop_t oop)
|
int moo_deregfinalizable (moo_t* moo, moo_oop_t oop)
|
||||||
{
|
{
|
||||||
moo_collectable_t* x;
|
moo_finalizable_t* x;
|
||||||
|
|
||||||
if (!MOO_OOP_IS_POINTER(oop) ||
|
if (!MOO_OOP_IS_POINTER(oop) || ((MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)) != MOO_GCFIN_FINALIZABLE))
|
||||||
((MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)) != MOO_GCFIN_FINALIZABLE))
|
|
||||||
{
|
{
|
||||||
moo_seterrnum (moo, MOO_EINVAL);
|
moo_seterrnum (moo, MOO_EINVAL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -861,7 +862,6 @@ int moo_deregfinalizable (moo_t* moo, moo_oop_t oop)
|
|||||||
{
|
{
|
||||||
if (x->oop == oop)
|
if (x->oop == oop)
|
||||||
{
|
{
|
||||||
/* TODO: do i need to clear other flags like GC */
|
|
||||||
MOO_OBJ_SET_FLAGS_GCFIN(oop, (MOO_OBJ_GET_FLAGS_GCFIN(oop) & ~MOO_GCFIN_FINALIZABLE));
|
MOO_OBJ_SET_FLAGS_GCFIN(oop, (MOO_OBJ_GET_FLAGS_GCFIN(oop) & ~MOO_GCFIN_FINALIZABLE));
|
||||||
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
|
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
|
||||||
return 0;
|
return 0;
|
||||||
@ -874,10 +874,11 @@ int moo_deregfinalizable (moo_t* moo, moo_oop_t oop)
|
|||||||
|
|
||||||
static void move_finalizable_objects (moo_t* moo)
|
static void move_finalizable_objects (moo_t* moo)
|
||||||
{
|
{
|
||||||
moo_collectable_t* x, * y;
|
moo_finalizable_t* x, * y;
|
||||||
|
|
||||||
for (x = moo->collectable.first; x; x = x->next)
|
for (x = moo->collectable.first; x; x = x->next)
|
||||||
{
|
{
|
||||||
|
MOO_ASSERT (moo, (MOO_OBJ_GET_FLAGS_GCFIN(x->oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)) == MOO_GCFIN_FINALIZABLE);
|
||||||
x->oop = moo_moveoop (moo, x->oop);
|
x->oop = moo_moveoop (moo, x->oop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,15 +886,20 @@ static void move_finalizable_objects (moo_t* moo)
|
|||||||
{
|
{
|
||||||
y = x->next;
|
y = x->next;
|
||||||
|
|
||||||
|
MOO_ASSERT (moo, (MOO_OBJ_GET_FLAGS_GCFIN(x->oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)) == MOO_GCFIN_FINALIZABLE);
|
||||||
|
|
||||||
if (!MOO_OBJ_GET_FLAGS_MOVED(x->oop))
|
if (!MOO_OBJ_GET_FLAGS_MOVED(x->oop))
|
||||||
{
|
{
|
||||||
/* TODO: if already finalized, don't move, don't add to collectable
|
/* the object has not been moved. it means this object is not reachable
|
||||||
if (MOVE_OBJ_GET_FLAGS_FINALIZED(x->oop)) continue;
|
* from the root except this finalizable list. this object would be
|
||||||
* */
|
* garbage if not for finalizatin. it's almost collectable. but it
|
||||||
x->oop = moo_moveoop (moo, x->oop);
|
* will survive this cycle for finalization.
|
||||||
|
*
|
||||||
|
* if garbages consist of finalizable objects only, GC should fail miserably.
|
||||||
|
* however this is quite unlikely because some key objects for VM execution
|
||||||
|
* like context objects doesn't require finalization. */
|
||||||
|
|
||||||
/* it's almost collectable. but don't collect it yet.
|
x->oop = moo_moveoop (moo, x->oop);
|
||||||
* if garbages consist of finalizable objects only, GC should fail miserably */
|
|
||||||
|
|
||||||
/* remove it from the finalizable list */
|
/* remove it from the finalizable list */
|
||||||
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
|
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
|
||||||
@ -901,6 +907,7 @@ if (MOVE_OBJ_GET_FLAGS_FINALIZED(x->oop)) continue;
|
|||||||
/* add it to the collectable list */
|
/* add it to the collectable list */
|
||||||
MOO_APPEND_TO_LIST (&moo->collectable, x);
|
MOO_APPEND_TO_LIST (&moo->collectable, x);
|
||||||
|
|
||||||
|
// TODO: singal semaphore..
|
||||||
//signal_semaphore (moo, moo->collectable_semaphore);
|
//signal_semaphore (moo, moo->collectable_semaphore);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -314,7 +314,9 @@ typedef enum moo_obj_type_t moo_obj_type_t;
|
|||||||
enum moo_gcfin_t
|
enum moo_gcfin_t
|
||||||
{
|
{
|
||||||
MOO_GCFIN_FINALIZABLE = (1 << 0),
|
MOO_GCFIN_FINALIZABLE = (1 << 0),
|
||||||
MOO_GCFIN_FINALIZED = (1 << 1)
|
MOO_GCFIN_FINALIZED = (1 << 1),
|
||||||
|
MOO_GCFIN_RESERVED_0 = (1 << 2),
|
||||||
|
MOO_GCFIN_RESERVED_1 = (1 << 3)
|
||||||
};
|
};
|
||||||
typedef enum moo_gcfin_t moo_gcfin_t;
|
typedef enum moo_gcfin_t moo_gcfin_t;
|
||||||
|
|
||||||
@ -373,7 +375,7 @@ typedef enum moo_gcfin_t moo_gcfin_t;
|
|||||||
#define MOO_OBJ_FLAGS_MOVED_BITS 1
|
#define MOO_OBJ_FLAGS_MOVED_BITS 1
|
||||||
#define MOO_OBJ_FLAGS_NGC_BITS 1
|
#define MOO_OBJ_FLAGS_NGC_BITS 1
|
||||||
#define MOO_OBJ_FLAGS_RDONLY_BITS 1
|
#define MOO_OBJ_FLAGS_RDONLY_BITS 1
|
||||||
#define MOO_OBJ_FLAGS_GCFIN_BITS 2
|
#define MOO_OBJ_FLAGS_GCFIN_BITS 4
|
||||||
#define MOO_OBJ_FLAGS_TRAILER_BITS 1
|
#define MOO_OBJ_FLAGS_TRAILER_BITS 1
|
||||||
|
|
||||||
#define MOO_OBJ_FLAGS_TYPE_SHIFT (MOO_OBJ_FLAGS_UNIT_BITS + MOO_OBJ_FLAGS_UNIT_SHIFT)
|
#define MOO_OBJ_FLAGS_TYPE_SHIFT (MOO_OBJ_FLAGS_UNIT_BITS + MOO_OBJ_FLAGS_UNIT_SHIFT)
|
||||||
@ -792,7 +794,7 @@ struct moo_semaphore_t
|
|||||||
moo_oop_t io_mask; /* SmallInteger */
|
moo_oop_t io_mask; /* SmallInteger */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MOO_PROCESS_SCHEDULER_NAMED_INSTVARS 5
|
#define MOO_PROCESS_SCHEDULER_NAMED_INSTVARS 4
|
||||||
typedef struct moo_process_scheduler_t moo_process_scheduler_t;
|
typedef struct moo_process_scheduler_t moo_process_scheduler_t;
|
||||||
typedef struct moo_process_scheduler_t* moo_oop_process_scheduler_t;
|
typedef struct moo_process_scheduler_t* moo_oop_process_scheduler_t;
|
||||||
struct moo_process_scheduler_t
|
struct moo_process_scheduler_t
|
||||||
@ -802,7 +804,7 @@ struct moo_process_scheduler_t
|
|||||||
moo_oop_process_t active; /* pointer to an active process in the runnable process list */
|
moo_oop_process_t active; /* pointer to an active process in the runnable process list */
|
||||||
moo_oop_process_t runnable_head; /* runnable process list */
|
moo_oop_process_t runnable_head; /* runnable process list */
|
||||||
moo_oop_process_t runnable_tail; /* runnable process list */
|
moo_oop_process_t runnable_tail; /* runnable process list */
|
||||||
moo_oop_t sempq; /* SemaphoreHeap */
|
/*moo_oop_t sempq;*/ /* SemaphoreHeap */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1001,12 +1003,12 @@ struct moo_sbuf_t
|
|||||||
};
|
};
|
||||||
typedef struct moo_sbuf_t moo_sbuf_t;
|
typedef struct moo_sbuf_t moo_sbuf_t;
|
||||||
|
|
||||||
typedef struct moo_collectable_t moo_collectable_t;
|
typedef struct moo_finalizable_t moo_finalizable_t;
|
||||||
struct moo_collectable_t
|
struct moo_finalizable_t
|
||||||
{
|
{
|
||||||
moo_oop_t oop;
|
moo_oop_t oop;
|
||||||
moo_collectable_t* prev;
|
moo_finalizable_t* prev;
|
||||||
moo_collectable_t* next;
|
moo_finalizable_t* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* special callback to be called for trailer */
|
/* special callback to be called for trailer */
|
||||||
@ -1178,14 +1180,14 @@ struct moo_t
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
moo_collectable_t* first;
|
moo_finalizable_t* first;
|
||||||
moo_collectable_t* last;
|
moo_finalizable_t* last;
|
||||||
} collectable;
|
} collectable;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
moo_collectable_t* first;
|
moo_finalizable_t* first;
|
||||||
moo_collectable_t* last;
|
moo_finalizable_t* last;
|
||||||
} finalizable;
|
} finalizable;
|
||||||
|
|
||||||
moo_uintmax_t inst_counter;
|
moo_uintmax_t inst_counter;
|
||||||
|
Loading…
Reference in New Issue
Block a user