From 73d363c11a63e4b87a0510a378641a9edd99b05f Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 3 May 2012 02:00:04 -0700 Subject: [PATCH] use a lock-free queue to finalize v8 handles. --- ext/v8/gc.cc | 43 ++++++++++++++++++++++++++++++------------- ext/v8/rr.h | 30 ++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/ext/v8/gc.cc b/ext/v8/gc.cc index 0a97820..1616544 100644 --- a/ext/v8/gc.cc +++ b/ext/v8/gc.cc @@ -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(); } } \ No newline at end of file diff --git a/ext/v8/rr.h b/ext/v8/rr.h index 1b15181..7656f6b 100644 --- a/ext/v8/rr.h +++ b/ext/v8/rr.h @@ -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 handle, VALUE klass) { this->handle = v8::Persistent::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 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 { public: - inline Phantom(VALUE value) : Ref(value) {} + inline Phantom(void* reference) : Ref((Ref::Holder*)reference) {} + inline bool NotNull() { + return this->holder != NULL; + } inline void destroy() { delete holder; }