![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* js_call.cc 00002 Jeremy Barnes, 15 November 2010 00003 Copyright (c) 2010 Datacratic. All rights reserved. 00004 00005 JS calling and notifier functionality. 00006 */ 00007 00008 #include "js_call.h" 00009 #include <unordered_map> 00010 #include "jml/arch/backtrace.h" 00011 #include "v8.h" 00012 #include "node.h" 00013 00014 00015 using namespace std; 00016 00017 extern "C" { 00018 // Define as a weak symbol to avoid linker errors when linking without libeio 00019 __attribute__((__weak__)) 00020 eio_req * eio_custom(void (*)(eio_req*), int, int (*)(eio_req*), void*) 00021 { 00022 throw ML::Exception("node needs to be linked in to use JS context callbacks"); 00023 } 00024 }; 00025 00026 namespace node { 00027 00028 // Define as a weak symbol to avoid linker errors when linking without node 00029 __attribute__((__weak__)) 00030 void FatalException(v8::TryCatch & tc) 00031 { 00032 throw ML::Exception("node needs to be linked in to use JS context callbacks"); 00033 } 00034 00035 } // namespace node 00036 00037 00038 namespace Datacratic { 00039 namespace JS { 00040 00041 /*****************************************************************************/ 00042 /* CALL IN JS CONTEXT */ 00043 /*****************************************************************************/ 00044 00045 struct CallInJsContextData { 00046 boost::function<void ()> callback; 00047 00048 ~CallInJsContextData() 00049 { 00050 } 00051 }; 00052 00053 static void doNothing(eio_req * req) 00054 { 00055 // TODO: don't do this; find how to use libeio properly 00056 } 00057 00058 static int doCallInJs(eio_req * req) 00059 { 00060 v8::HandleScope scope; 00061 00062 auto_ptr<CallInJsContextData> data((CallInJsContextData *)req->data); 00063 00064 v8::TryCatch try_catch; 00065 00066 try { 00067 data->callback(); 00068 } catch (const JSPassException & exc) { 00069 cerr << "got JSPassException" << endl; 00070 if (!try_catch.HasCaught()) { 00071 cerr << "handler returned passed exception " << endl; 00072 ML::backtrace(); 00073 abort(); 00074 } 00075 // Corner case... but probably shouldn't happen 00076 } catch (const std::exception & exc) { 00077 /* v8::Handle<v8::Value> result = */ translateCurrentException(); 00078 // TODO: what do we do with result? 00079 if (!try_catch.HasCaught()) { 00080 cerr << "handler returned exception: " << exc.what() << endl; 00081 ML::backtrace(); 00082 abort(); 00083 } 00084 } catch (...) { 00085 /* v8::Handle<v8::Value> result = */ translateCurrentException(); 00086 // TODO: what to do with result? 00087 if (!try_catch.HasCaught()) { 00088 cerr << "handler returned exception " << endl; 00089 ML::backtrace(); 00090 abort(); 00091 } 00092 } 00093 00094 if (try_catch.HasCaught()) 00095 node::FatalException(try_catch); 00096 00097 return 0; 00098 } 00099 00100 void callInJsThread(const boost::function<void ()> & fn) 00101 { 00102 // This is called from a thread that is probably not the right thread for 00103 // JS to be executed in. Here we arrange for the right thread to be called 00104 // back by libev once the JS engine is ready to do something. 00105 00106 auto_ptr<CallInJsContextData> data(new CallInJsContextData()); 00107 data->callback = fn; 00108 eio_custom(doNothing, EIO_PRI_DEFAULT, doCallInJs, data.release()); 00109 } 00110 00111 boost::function<void ()> 00112 createCrossThreadCallback(v8::Handle<v8::Function> fn, 00113 v8::Handle<v8::Object> This) 00114 { 00115 calltojsbase args(fn, This); 00116 00117 auto onceInJsContext = [=] () 00118 { 00119 v8::HandleScope scope; 00120 v8::Handle<v8::Value> result; 00121 { 00122 v8::TryCatch tc; 00123 result = args.params->fn->Call(args.params->This, 0, 0); 00124 00125 if (result.IsEmpty()) { 00126 if(tc.HasCaught()) { 00127 tc.ReThrow(); 00128 throw JSPassException(); 00129 } 00130 throw ML::Exception("didn't return anything"); 00131 } 00132 } 00133 }; 00134 00135 auto result = [=] () 00136 { 00137 callInJsContext(onceInJsContext); 00138 }; 00139 00140 return result; 00141 } 00142 00143 00144 /*****************************************************************************/ 00145 /* JS OPERATIONS */ 00146 /*****************************************************************************/ 00147 00148 std::unordered_map<const std::type_info *, JSOperations> operations; 00149 00150 void registerJsOps(const std::type_info & type, 00151 JSOperations ops) 00152 { 00153 //cerr << "registered " << ML::demangle(type) << " at " << &type << " with " << &ops << endl; 00154 //ML::backtrace(); 00155 00156 operations[&type] = ops; 00157 } 00158 00159 JSOperations 00160 getOps(const std::type_info & fntype) 00161 { 00162 auto it = operations.find(&fntype); 00163 if (it == operations.end()) 00164 throw ML::Exception("no JS operations registered for " 00165 + ML::demangle(fntype)); 00166 return it->second; 00167 } 00168 00169 } // namespace JS 00170 } // namespace Datacratic