]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[fdxhook] Improved GC handling
authorFrancis Dupont <fdupont@isc.org>
Mon, 27 Jun 2016 13:27:10 +0000 (15:27 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 27 Jun 2016 13:27:10 +0000 (15:27 +0200)
src/hooks/external/v8/Makefile [new file with mode: 0644]
src/hooks/external/v8/dso.cc
src/hooks/external/v8/voption.cc
src/hooks/external/v8/voption.h
src/hooks/external/v8/vpkt4.cc
src/hooks/external/v8/vpkt4.h

diff --git a/src/hooks/external/v8/Makefile b/src/hooks/external/v8/Makefile
new file mode 100644 (file)
index 0000000..03a4007
--- /dev/null
@@ -0,0 +1,49 @@
+#KEASRC = /tmp/kea/src/lib
+
+# Kea includes and boost
+CPPFLAGS = -I../../.. -I$(KEASRC) -I/usr/local/include
+# v8
+
+CXXFLAGS = -DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_SYSTEM_NO_DEPRECATED
+CXXFLAGS += -g -fPIC -dynamic -DNDEBUG -fwrapv
+# v8
+CXXFLAGS += -Wno-c++11-extensions
+
+# Kea dhcp library
+LIBS = -lkea-dhcp++ -lkea-hooks -lkea-exceptions
+# v8
+LIBS += -lv8_base -lv8_libbase -lv8_snapshot -lv8_libplatform -lv8
+
+# Kea dependencies
+LDFLAGS = -L/usr/local/Cellar/botan/1.10.12/lib
+LDFLAGS += -L$(KEASRC)/dhcp/.libs
+LDFLAGS += -L$(KEASRC)/hooks/.libs
+LDFLAGS += -L$(KEASRC)/exceptions/.libs
+# v8
+
+SRCS = dso.cc globals.cc globals.h voption.h voption.cc vpkt4.h vpkt4.cc
+
+OBJS = dso.o globals.o voption.o vpkt4.o
+
+all: kea.so tests
+
+kea.so: $(OBJS)
+       g++ -shared $(OBJS) $(LDFLAGS) $(LIBS) -o kea.so
+
+TESTLIBS = -lkea-dhcpsrv -lkea-dhcp++ -lkea-asiolink -lkea-cc
+TESTLIBS += -lkea-hooks -lkea-log -lkea-exceptions
+
+TESTLDFLAGS = -L/usr/local/Cellar/botan/1.10.12/lib
+TESTLDFLAGS += -L$(KEASRC)/dhcpsrv/.libs
+TESTLDFLAGS += -L$(KEASRC)/dhcp/.libs
+TESTLDFLAGS += -L$(KEASRC)/asiolink/.libs
+TESTLDFLAGS += -L$(KEASRC)/cc/.libs
+TESTLDFLAGS += -L$(KEASRC)/hooks/.libs
+TESTLDFLAGS += -L$(KEASRC)/log/.libs
+TESTLDFLAGS += -L$(KEASRC)/exceptions/.libs
+
+tests: tests.o
+       g++ tests.o $(TESTLDFLAGS) $(TESTLIBS) -o tests
+
+clean:
+       rm -f *.o *.so tests
index ab2ea6d871f67c9cc0e43324d28bd0aa860eca29..ef8212bf761cbb85bf11b5f92047714608353536 100644 (file)
@@ -151,8 +151,8 @@ int load(LibraryHandle& handle) {
     Context::Scope context_scope(context);
 
     // Initialize option and pkt4
-    init_option_template(isolate_);
-    init_pkt4_template(isolate_);
+    init_option(isolate_);
+    init_pkt4(isolate_);
 
     // Import script file content
     Local<String> source =
@@ -244,18 +244,11 @@ int pkt4_receive(CalloutHandle& handle) {
     Context::Scope context_scope(context);
 
     // Create pkt4 object
-    Local<ObjectTemplate> templ =
-        Local<ObjectTemplate>::New(isolate_, pkt4_template);
-    Local<Object> query;
-    if (!templ->NewInstance(context).ToLocal(&query)) {
-        String::Utf8Value error(try_catch.Exception());
-        cerr << "NewInstance failed: " << *error << "\n";
+    Local<Object> query = make_pkt4(isolate_, query4);
+    if (query.IsEmpty()) {
+        cerr << "empty v8 query\n";
         return (0);
     }
-    v8_pkt4* ccpobj(new v8_pkt4());
-    ccpobj->object = query4;
-    Local<External> ptr = External::New(isolate_, ccpobj);
-    query->SetInternalField(0, ptr);
 
     // Call the handler
     const int argc = 1;
@@ -264,7 +257,6 @@ int pkt4_receive(CalloutHandle& handle) {
     Local<Value> result;
     if (!handler->Call(context, context->Global(),
                        argc, argv).ToLocal(&result)) {
-      cerr << "call failed\n";
         String::Utf8Value error(try_catch.Exception());
         cerr << "pkt4_receive handler failed: " << *error << "\n";
         return (0);
index 67ac27a666cda9a1df7f7d8053438000f1fdb999..61d2959b0a6b40d9842a73b6051a8a55ec930699 100644 (file)
@@ -23,13 +23,26 @@ namespace { // anonymous namespace
 
 // finalize (how to call it?)
 void
-option_finalize(Local<Object> obj) {
+option_finalize(const WeakCallbackData<Object, v8_option>& data) {
     // This is a critical code to avoid memory leaks
     cout << "option_finalize called\n";
-    Local<External> field = Local<External>::Cast(obj->GetInternalField(0));
+    Local<External> field =
+        Local<External>::Cast(data.GetValue()->GetInternalField(0));
+    delete static_cast<v8_option*>(field->Value());
+}
+
+// toString
+void
+option_tostring(const FunctionCallbackInfo<Value>& info) {
+    HandleScope handle_scope(info.GetIsolate());
+
+    Local<External> field =
+        Local<External>::Cast(info.Holder()->GetInternalField(0));
     v8_option* const self = static_cast<v8_option*>(field->Value());
-    self->object.reset();
-    delete self;
+    info.GetReturnValue().Set(
+        String::NewFromUtf8(info.GetIsolate(),
+                            self->object->toText().c_str(),
+                            NewStringType::kNormal).ToLocalChecked());
 }
 
 } // end of anonymous namespace
@@ -39,7 +52,37 @@ namespace v8 {
 
 Global<ObjectTemplate> option_template;
 
-void init_option_template(Isolate* isolate) {
+Local<Object> make_option(Isolate* isolate, OptionPtr opt) {
+    // Create a stack-allocated handle scope.
+    EscapableHandleScope handle_scope(isolate);
+
+    // Catch errors
+    TryCatch try_catch(isolate);
+
+    // Generate a new instance from the template
+    Local<ObjectTemplate> templ =
+        Local<ObjectTemplate>::New(isolate, option_template);
+    Local<Object> result;
+    if (!templ->NewInstance(isolate->GetCurrentContext()).ToLocal(&result)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "NewInstance failed: " << *error << "\n";
+        return (handle_scope.Escape(result));
+    }
+
+    // Set the C++ part
+    v8_option* ccpobj(new v8_option());
+    ccpobj->object = opt;
+    Local<External> ptr = External::New(isolate, ccpobj);
+    result->SetInternalField(0, ptr);
+
+    // Show the new value to the garbage collector
+    Persistent<Object> gcref(isolate, result);
+    gcref.SetWeak<v8_option>(ccpobj, option_finalize);
+
+    return (handle_scope.Escape(result));
+}
+
+void init_option(Isolate* isolate) {
     // Create a stack-allocated handle scope.
     HandleScope handle_scope(isolate);
 
@@ -49,7 +92,13 @@ void init_option_template(Isolate* isolate) {
     // Get one field
     templ->SetInternalFieldCount(1);
 
-    ///// TODO set methods
+    // Set Methods
+    Local<Function> tostring;
+    if (!Function::New(isolate->GetCurrentContext(),
+                       option_tostring).ToLocal(&tostring)) {
+        cerr << "can't create pkt4_tostring\n";
+    }
+    templ->Set(isolate, "toString", tostring);
 
     // Store it
     option_template.Reset(isolate, templ);
index ddc8ba0fc9c58c36b9552551022c2ace7027ba3f..af1ad12f7128179b9bd205d31783362bfff3529b 100644 (file)
@@ -14,15 +14,16 @@ namespace v8 {
 
 // Ocaml option class
 class v8_option {
+public:
     v8_option();
 
-public:
     isc::dhcp::OptionPtr object;
 };
 
-extern ::v8::Global< ::v8::ObjectTemplate> option_template;
+::v8::Local< ::v8::Object> make_option(::v8::Isolate* isolate,
+                                       isc::dhcp::OptionPtr opt);
 
-void init_option_template(::v8::Isolate* isolate);
+void init_option(::v8::Isolate* isolate);
 
 } // end of namespace v8
 } // end of namespace isc
index 3445790ef956bab73579b3b56af54e0ef565f883..66656d83e6c24eebb9eb7f888372ca17f2ff8447 100644 (file)
@@ -24,13 +24,12 @@ namespace { // anonymous namespace
 
 // finalize (how to call it?)
 void
-pkt4_finalize(Local<Object> obj) {
+pkt4_finalize(const WeakCallbackData<Object, v8_pkt4>& data) {
     // This is a critical code to avoid memory leaks
     cout << "pkt4_finalize called\n";
-    Local<External> field = Local<External>::Cast(obj->GetInternalField(0));
-    v8_pkt4* const self = static_cast<v8_pkt4*>(field->Value());
-    self->object.reset();
-    delete self;
+    Local<External> field =
+        Local<External>::Cast(data.GetValue()->GetInternalField(0));
+    delete static_cast<v8_pkt4*>(field->Value());
 }
 
 // toString
@@ -54,7 +53,37 @@ namespace v8 {
 
 Global<ObjectTemplate> pkt4_template;
 
-void init_pkt4_template(Isolate* isolate) {
+Local<Object> make_pkt4(Isolate* isolate, Pkt4Ptr pkt) {
+    // Create a stack-allocated handle scope.
+    EscapableHandleScope handle_scope(isolate);
+
+    // Catch errors
+    TryCatch try_catch(isolate);
+
+    // Generate a new instance from the template
+    Local<ObjectTemplate> templ =
+        Local<ObjectTemplate>::New(isolate, pkt4_template);
+    Local<Object> result;
+    if (!templ->NewInstance(isolate->GetCurrentContext()).ToLocal(&result)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "NewInstance failed: " << *error << "\n";
+        return (handle_scope.Escape(result));
+    }
+
+    // Set the C++ part
+    v8_pkt4* ccpobj(new v8_pkt4());
+    ccpobj->object = pkt;
+    Local<External> ptr = External::New(isolate, ccpobj);
+    result->SetInternalField(0, ptr);
+
+    // Show the new value to the garbage collector
+    Persistent<Object> gcref(isolate, result);
+    gcref.SetWeak<v8_pkt4>(ccpobj, pkt4_finalize);
+
+    return (handle_scope.Escape(result));
+}
+
+void init_pkt4(Isolate* isolate) {
     // Create a stack-allocated handle scope.
     HandleScope handle_scope(isolate);
 
index 381938a7d348a8c80e2cf9bad157af9be46adfd1..88a05c436a38e6a1c367c02b136d77f9cdc90545 100644 (file)
@@ -20,9 +20,10 @@ public:
     isc::dhcp::Pkt4Ptr object;
 };
 
-extern ::v8::Global< ::v8::ObjectTemplate> pkt4_template;
+::v8::Local< ::v8::Object> make_pkt4(::v8::Isolate* isolate,
+                                     isc::dhcp::Pkt4Ptr pkt);
 
-void init_pkt4_template(::v8::Isolate* isolate);
+void init_pkt4(::v8::Isolate* isolate);
 
 } // end of namespace v8
 } // end of namespace isc