1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

use a lock-free queue to finalize v8 handles.

This commit is contained in:
Charles Lowell 2012-05-03 02:00:04 -07:00
parent 3c8bd2bb1d
commit 73d363c11a
2 changed files with 52 additions and 21 deletions

View file

@ -1,25 +1,42 @@
#include "rr.h"
namespace rr {
VALUE queue;
GC::Queue* queue;
namespace gc {
VALUE dequeue(VALUE q) {
return rb_funcall(q, rb_intern("pop"), 1, Qtrue);
GC::Queue::Queue() : first(0), divider(0), last(0){
first = new GC::Queue::Node(NULL);
divider = first;
last = first;
}
void GC::Queue::Enqueue(void* reference) {
last->next = new Node(reference);
last = last->next;
while (first != divider) {
Node* tmp = first;
first = first->next;
delete tmp;
}
}
void GC::Push(VALUE phantom) {
rb_funcall(queue, rb_intern("<<"), 1, phantom);
void* GC::Queue::Dequeue() {
void* result = NULL;
if (divider != last) {
result = divider->next->value;
divider = divider->next;
}
return result;
}
void GC::Pop(v8::GCType type, v8::GCCallbackFlags flags) {
VALUE next = rb_protect(&gc::dequeue, queue, NULL);
rb_set_errinfo(Qnil);
if (!NIL_P(next)) {
Phantom(next).destroy();
void GC::Finalize(void* phantom) {
queue->Enqueue(phantom);
}
void GC::Drain(v8::GCType type, v8::GCCallbackFlags flags) {
for(Phantom phantom = queue->Dequeue(); phantom.NotNull(); phantom = queue->Dequeue()) {
phantom.destroy();
}
}
void GC::Init() {
rb_gc_register_address(&queue);
queue = rb_eval_string("require 'thread'; Queue.new");
queue = new GC::Queue();
}
}

View file

@ -20,8 +20,23 @@ protected:
class GC {
public:
static void Push(VALUE phantom);
static void Pop(v8::GCType type, v8::GCCallbackFlags flags);
class Queue {
public:
Queue();
void Enqueue(void* phantom);
void* Dequeue();
private:
struct Node {
Node(void* val ) : value(val), next(NULL) { }
void* value;
Node* next;
};
Node* first; // for producer only
Node* divider;
Node* last;
};
static void Finalize(void* phantom);
static void Drain(v8::GCType type, v8::GCCallbackFlags flags);
static void Init();
};
@ -52,21 +67,17 @@ public:
Holder(v8::Handle<T> handle, VALUE klass) {
this->handle = v8::Persistent<T>::New(handle);
this->value = Data_Wrap_Struct(klass, 0, &Holder::enqueue, this);
this->phantom = Data_Wrap_Struct(rb_cObject, 0, 0, this);
rb_gc_register_address(&phantom);
}
virtual ~Holder() {
handle.Dispose();
rb_gc_unregister_address(&phantom);
}
protected:
VALUE value;
VALUE phantom;
v8::Persistent<T> handle;
static void enqueue(Holder* holder) {
holder->value = Qnil;
GC::Push(holder->phantom);
GC::Finalize(holder);
}
};
Ref(Holder* holder) {
@ -77,7 +88,10 @@ public:
class Phantom : public Ref<void> {
public:
inline Phantom(VALUE value) : Ref<void>(value) {}
inline Phantom(void* reference) : Ref<void>((Ref<void>::Holder*)reference) {}
inline bool NotNull() {
return this->holder != NULL;
}
inline void destroy() {
delete holder;
}