#include "pmc_garbage.h"
+void incrementthreads() {
+ tmc_spin_mutex_lock(&pmc_heapptr->lock);
+ pmc_heapptr->numthreads++;
+ tmc_spin_mutex_unlock(&pmc_heapptr->lock);
+}
+
+void decrementthreads() {
+ tmc_spin_mutex_lock(&pmc_heapptr->lock);
+ pmc_heapptr->numthreads--;
+ tmc_spin_mutex_unlock(&pmc_heapptr->lock);
+}
#ifndef PMC_GARBAGE_H
#define PMC_GARBAGE_H
+#include <tmc/spin.h>
+
struct pmc_unit {
- unsigned int lock;
+ tmc_spin_mutex_t lock;
unsigned int numbytes;
};
struct pmc_region {
void * lastptr;
struct ___Object___ * lastobj;
+ struct pmc_queue markqueue;
};
struct pmc_heap {
struct pmc_region units[NUMCORES4GC*4];
struct pmc_region regions[NUMCORES4GC];
- unsigned int lock;
- unsigned int numthreads;
+ tmc_spin_mutex_t lock;
+ volatile unsigned int numthreads;
};
extern struct pmc_heap * pmc_heapptr;
+void incrementthreads();
+void decrementthreads() {
+
+
#endif
void pmc_markObj(struct ___Object___ *ptr) {
if (!ptr->mark) {
ptr->mark=1;
- pmc_enqueue(ptr);
+ pmc_enqueue(pmc_localqueue, ptr);
}
}
void pmc_mark(struct garbagelist *stackptr) {
pmc_tomark(stackptr);
while(true) {
+ //scan everything in our local queue
pmc_marklocal();
-
-
+ if (pmc_trysteal())
+ break;
}
}
+bool pmc_trysteal() {
+ decrementthreads();
+ while(pmc_heapptr->numthreads) {
+ for(int i=0;i<NUMCORES4GC;i++) {
+ struct pmc_queue *queue=&pmc_heapptr->regions[i].markqueue;
+ if (!pmc_isEmpty(queue)) {
+ incrementthreads();
+ void *objptr=pmc_dequeue(queue);
+ if (objptr!=NULL) {
+ unsigned int type=((struct ___Object___*)objptr)->type;
+ pmc_scanPtrsInObj(objptr, type);
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
void pmc_marklocal() {
-
+ void *objptr;
+ while(objptr=pmc_dequeue(pmc_localqueue)) {
+ unsigned int type=((struct ___Object___*)objptr)->type;
+ pmc_scanPtrsInObj(objptr, type);
+ }
}
void pmc_tomark(struct garbagelist * stackptr) {
--- /dev/null
+#include "pmc_queue.h"
+
+void pmc_init(struct pmc_queue *queue) {
+ queue->head=queue->tail=RUNMALLOC(struct pmc_queue_segment);
+ queue->headindex=queue->tailindex=0;
+}
+
+void * pmc_dequeue(struct pmc_queue *queue) {
+ void *value=NULL;
+ tmc_spin_mutex_lock(&queue->lock);
+ //do-while loop allows sharing cleanup code
+ do {
+ //check for possible rollover
+ if (queue->tailindex==NUM_PMC_QUEUE_OBJECTS) {
+ if (queue->tail!=queue->head) {
+ struct pmc_queue_segment *oldtail=queue->tail;
+ queue->tail=oldtail->next;
+ queue->tailindex=0;
+ RUNFREE(oldtail);
+ } else break;
+ }
+ //now try to decrement
+ if (queue->tailindex!=queue->headindex) {
+ value=queue->tail[queue->tailindex];
+ queue->tailindex++;
+ }
+ } while(false);
+ tmc_spin_mutex_unlock(&queue->lock);
+ return status;
+}
+
+void pmc_enqueue(struct pmc_queue* queue, void *ptr) {
+ if (queue->headindex<NUM_PMC_QUEUE_OBJECTS) {
+ queue->head->objects[queue->headindex]=ptr;
+ //need fence to prevent reordering
+ __insn_mf();
+ queue->headindex++;
+ return;
+ } else {
+ struct pmc_queue_segment * seg=RUNMALLOC(struct pmc_queue_segment);
+ seg->objects[0]=ptr;
+ //simplify everything by grabbing a lock on segment change
+ tmc_spin_mutex_lock(&queue->lock);
+ queue->headindex=1;
+ queue->head->next=seg;
+ queue->head=seg;
+ tmc_spin_mutex_unlock(&queue->lock);
+ }
+}
+
+bool pmc_isEmpty(struct pmc_queue *queue) {
+ tmc_spin_mutex_lock(&queue->lock);
+ bool status=(queue->head==queue->tail)&&(queue->headindex==queue->tailindex);
+ tmc_spin_mutex_unlock(&queue->lock);
+ return status;
+}
--- /dev/null
+#ifndef PMC_QUEUE_H
+#define PMC_QUEUE_H
+#include <tmc/spin.h>
+
+#define NUM_PMC_QUEUE_OBJECTS 256
+struct pmc_queue_segment {
+ volatile void * objects[NUM_PMC_QUEUE_OBJECTS];
+ struct pmc_queue_segment * next;
+};
+
+struct pmc_queue {
+ volatile struct pmc_queue_segment *head;
+ volatile struct pmc_queue_segment *tail;
+ volatile int headindex;
+ volatile int tailindex;
+ tmc_spin_mutex_t lock;
+};
+
+void * pmc_dequeue(struct pmc_queue *queue);
+void pmc_enqueue(struct pmc_queue* queue, void *ptr);
+bool pmc_isEmpty(struct pmc_queue *queue);
+void pmc_init(struct pmc_queue *queue);
+#endif