blob: 2619627377d014bbbb6e91089530dd6805c0b4bd [file] [log] [blame]
//===--------------- gcthread.h - Mvm Garbage Collector -------------------===//
//
// Mvm
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _GC_THREAD_H_
#define _GC_THREAD_H_
//#include "gcalloc.h"
//#include "ctlock.h"
#include "ctcircular.h"
#include "mvm/GC/GC.h"
#include "mvm/Threads/Cond.h"
#include "mvm/Threads/Key.h"
#include "mvm/Threads/Locks.h"
#include "mvm/Threads/Thread.h" // only for self
// class GCAllocator;
namespace mvm {
class GCThreadCollector : public CircularBase {
void *_base_sp;
int _cur_mark;
int _tid;
public:
static void initialise_Key(void *) {}
static void duplicate_for_thread(void *, void *) {}
static void destroy_Key(void *ptr);
inline GCThreadCollector() {}
inline GCThreadCollector(GCThreadCollector *pred, int t, void *p, int m) : CircularBase(pred) {
_base_sp = p;
_cur_mark = m;
_tid = t;
}
/* cette fonction n'est appelée que dans deux cas: soit parsqu'un thread quit */
/* dans ce cas, tout est déjà fait */
/* soit parce que le collecteur quitte et dans ce cas, toute la mémoire est bien libérée */
inline ~GCThreadCollector() {}
void *operator new(size_t sz);
void operator delete(void *ptr);
inline int tid() { return _tid; }
inline unsigned int current_mark() { return _cur_mark; }
inline void current_mark(unsigned int m) { _cur_mark = m; }
inline unsigned int **base_sp() { return (unsigned int **)_base_sp; }
};
class GCLockRecovery : public LockNormal {
gc_lock_recovery_fct_t _fct;
int _args[8];
public:
inline GCLockRecovery() { _fct = 0; }
int verify_recall(gc_lock_recovery_fct_t fct, int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7);
inline void unlock_dont_recovery() {
if(owner() == Thread::self()) {
LockNormal::unlock();
}
}
inline void unlock() {
if(_fct) {
gc_lock_recovery_fct_t tmp = _fct;
int l[8];
l[0] = _args[0]; l[1] = _args[1]; l[2] = _args[2]; l[3] = _args[3];
l[4] = _args[4]; l[5] = _args[5]; l[6] = _args[6]; l[7] = _args[7];
_fct = 0;
LockNormal::unlock();
tmp(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]);
} else
LockNormal::unlock();
}
};
class GCThread {
Key<GCThreadCollector> _loc;
GCThreadCollector base;
GCLockRecovery _globalLock; /* lock global pour gcmalloc */
LockNormal _stackLock; /* lock de la pile pour la syncro */
Cond _stackCond; /* condition pour déverouiller les autres taches (write protect) */
Cond _collectionCond;/* condition pour débloquer le collecteur */
unsigned int _nb_threads; /* nombre de threads actifs */
unsigned int _nb_collected; /* nombre de threads ayant collecté */
int collector_tid; /* il ne faut pas le synchroniser celui là */
public:
inline void lock() { _globalLock.lock(); }
inline void unlock() { _globalLock.unlock(); }
inline void unlock_dont_recovery() { _globalLock.unlock_dont_recovery(); }
inline int isStable(gc_lock_recovery_fct_t fct, int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) {
return _globalLock.verify_recall(fct, a0, a1, a2, a3, a4, a5, a6, a7);
}
inline void stackLock() { _stackLock.lock(); }
inline void stackUnlock() { _stackLock.unlock(); }
void waitStacks();
void waitCollection();
inline void collectionFinished() { _collectionCond.broadcast(); }
inline void collectorGo() { _stackCond.broadcast(); }
inline void cancel() {
_nb_collected = _nb_threads; /* toutes les piles sont collectées */
collectorGo(); /* débloque les autres threads sur la phase de collection de pile */
collectionFinished(); /* débloque les mutateurs */
}
inline GCThreadCollector *myloc() { return _loc.get(); }
inline void another_mark() { _nb_collected++; }
void synchronize();
inline void remove(GCThreadCollector *loc) {
lock();
loc->remove();
_nb_threads--;
delete loc;
unlock();
}
inline void inject(void *sp, int m) {
GCThreadCollector *me = _loc.get();
if(me)
gcfatal("thread %d is already in pool for allocator %p", Thread::self(), this);
lock(); /* the new should be protected */
me = new GCThreadCollector(&base, Thread::self(), sp, m);
_nb_threads++;
_loc.set(me);
unlock();
}
};
}
#endif