blob: 729b05adf7be2c9322b778db2aca8c6dffbb43a3 [file] [log] [blame]
//===--- FinalizerThread.h - Implementation of finalizable references--===//
//
// The VMKit project
//
// This file is distributed under the University of Pierre et Marie Curie
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef VMKIT_FINALIZERTHREAD_H_
#define VMKIT_FINALIZERTHREAD_H_
namespace vmkit {
template <class T_THREAD> class FinalizerThread : public T_THREAD {
public:
/// FinalizationQueueLock - A lock to protect access to the queue.
///
vmkit::SpinLock FinalizationQueueLock;
/// finalizationQueue - A list of allocated objets that contain a finalize
/// method.
///
gc** FinalizationQueue;
/// CurrentIndex - Current index in the queue of finalizable objects.
///
uint32 CurrentIndex;
/// QueueLength - Current length of the queue of finalizable objects.
///
uint32 QueueLength;
/// growFinalizationQueue - Grow the queue of finalizable objects.
///
void growFinalizationQueue() {
if (CurrentIndex >= QueueLength) {
uint32 newLength = QueueLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle finalizer overflows yet!\n");
abort();
}
for (uint32 i = 0; i < QueueLength; ++i) newQueue[i] = FinalizationQueue[i];
delete[] FinalizationQueue;
FinalizationQueue = newQueue;
QueueLength = newLength;
}
}
/// ToBeFinalized - List of objects that are scheduled to be finalized.
///
gc** ToBeFinalized;
/// ToBeFinalizedLength - Current length of the queue of objects scheduled
/// for finalization.
///
uint32 ToBeFinalizedLength;
/// CurrentFinalizedIndex - The current index in the ToBeFinalized queue
/// that will be sceduled for finalization.
///
uint32 CurrentFinalizedIndex;
/// growToBeFinalizedQueue - Grow the queue of the to-be finalized objects.
///
void growToBeFinalizedQueue() {
if (CurrentFinalizedIndex >= ToBeFinalizedLength) {
uint32 newLength = ToBeFinalizedLength * GROW_FACTOR;
gc** newQueue = new gc*[newLength];
if (!newQueue) {
fprintf(stderr, "I don't know how to handle finalizer overflows yet!\n");
abort();
}
for (uint32 i = 0; i < ToBeFinalizedLength; ++i) newQueue[i] = ToBeFinalized[i];
delete[] ToBeFinalized;
ToBeFinalized = newQueue;
ToBeFinalizedLength = newLength;
}
}
/// finalizationCond - Condition variable to wake up finalization threads.
///
vmkit::Cond FinalizationCond;
/// finalizationLock - Lock for the condition variable.
///
vmkit::LockNormal FinalizationLock;
static void finalizerStart(FinalizerThread* th) {
gc* res = NULL;
llvm_gcroot(res, 0);
while (true) {
th->FinalizationLock.lock();
while (th->CurrentFinalizedIndex == 0) {
th->FinalizationCond.wait(&th->FinalizationLock);
}
th->FinalizationLock.unlock();
while (true) {
th->FinalizationQueueLock.acquire();
if (th->CurrentFinalizedIndex != 0) {
res = th->ToBeFinalized[th->CurrentFinalizedIndex - 1];
--th->CurrentFinalizedIndex;
}
th->FinalizationQueueLock.release();
if (!res) break;
th->MyVM->finalizeObject(res);
res = NULL;
}
}
}
/// addFinalizationCandidate - Add an object to the queue of objects with
/// a finalization method.
///
void addFinalizationCandidate(gc* obj) {
llvm_gcroot(obj, 0);
FinalizationQueueLock.acquire();
if (CurrentIndex >= QueueLength) {
growFinalizationQueue();
}
FinalizationQueue[CurrentIndex++] = obj;
FinalizationQueueLock.release();
}
/// scanFinalizationQueue - Scan objets with a finalized method and schedule
/// them for finalization if they are not live.
///
void scanFinalizationQueue(word_t closure) {
gc* obj = NULL;
llvm_gcroot(obj, 0);
uint32 NewIndex = 0;
for (uint32 i = 0; i < CurrentIndex; ++i) {
obj = FinalizationQueue[i];
if (!vmkit::Collector::isLive(obj, closure)) {
obj = vmkit::Collector::retainForFinalize(FinalizationQueue[i], closure);
if (CurrentFinalizedIndex >= ToBeFinalizedLength)
growToBeFinalizedQueue();
/* Add to object table */
ToBeFinalized[CurrentFinalizedIndex++] = obj;
} else {
FinalizationQueue[NewIndex++] =
vmkit::Collector::getForwardedFinalizable(obj, closure);
}
}
CurrentIndex = NewIndex;
}
FinalizerThread(vmkit::VirtualMachine* vm) : T_THREAD(vm) {
FinalizationQueue = new gc*[INITIAL_QUEUE_SIZE];
QueueLength = INITIAL_QUEUE_SIZE;
CurrentIndex = 0;
ToBeFinalized = new gc*[INITIAL_QUEUE_SIZE];
ToBeFinalizedLength = INITIAL_QUEUE_SIZE;
CurrentFinalizedIndex = 0;
}
~FinalizerThread() {
delete[] FinalizationQueue;
delete[] ToBeFinalized;
}
};
}
#endif /* VMKIT_FINALIZERTHREAD_H_ */