From b8d0e7a3ac14151e022e475575558b2d3ba4e63a Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 29 Mar 2013 19:37:33 +0100 Subject: [PATCH] beta quality v8 plugin --- core/mule.c | 4 +- plugins/lua/lua_plugin.c | 1 + plugins/v8/plugin.c | 27 +++++ plugins/v8/uwsgiplugin.py | 6 ++ plugins/v8/v8_uwsgi.cc | 205 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 plugins/v8/plugin.c create mode 100644 plugins/v8/uwsgiplugin.py create mode 100644 plugins/v8/v8_uwsgi.cc diff --git a/core/mule.c b/core/mule.c index d2e65e21..05a82c2e 100644 --- a/core/mule.c +++ b/core/mule.c @@ -198,7 +198,9 @@ void uwsgi_mule_handler() { else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) { len = read(interesting_fd, message, 65536); if (len < 0) { - uwsgi_error("read()"); + if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { + uwsgi_error("uwsgi_mule_handler/read()"); + } } else { int i, found = 0; diff --git a/plugins/lua/lua_plugin.c b/plugins/lua/lua_plugin.c index 920e455f..816b0ddb 100644 --- a/plugins/lua/lua_plugin.c +++ b/plugins/lua/lua_plugin.c @@ -722,6 +722,7 @@ static void uwsgi_lua_configurator(char *filename, char *magic_table[]) { uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1)); exit(1); } + free(code); if (!lua_istable(L, -1)) { uwsgi_log("Lua configurator has to return a table !!!\n"); diff --git a/plugins/v8/plugin.c b/plugins/v8/plugin.c new file mode 100644 index 00000000..0bcdc0dd --- /dev/null +++ b/plugins/v8/plugin.c @@ -0,0 +1,27 @@ +#include + +int uwsgi_v8_init(void); +void uwsgi_v8_apps(void); +void uwsgi_v8_configurator(char *, char **); +uint16_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char *); + +static void uwsgi_v8_register(void) { + uwsgi_register_configurator(".js", uwsgi_v8_configurator); +} + +extern struct uwsgi_option uwsgi_v8_options[]; + +static int uwsgi_v8_request(struct wsgi_request *wsgi_req) { + return UWSGI_OK; +} + +struct uwsgi_plugin v8_plugin = { + .name = "v8", + .modifier1 = 24, + .init = uwsgi_v8_init, + .init_apps = uwsgi_v8_apps, + .options = uwsgi_v8_options, + .on_load = uwsgi_v8_register, + .rpc = uwsgi_v8_rpc, + .request = uwsgi_v8_request, +}; diff --git a/plugins/v8/uwsgiplugin.py b/plugins/v8/uwsgiplugin.py new file mode 100644 index 00000000..2143a26f --- /dev/null +++ b/plugins/v8/uwsgiplugin.py @@ -0,0 +1,6 @@ +NAME='v8' + +CFLAGS = [] +LDFLAGS = [] +LIBS = ['-lv8'] +GCC_LIST = ['plugin', 'v8_uwsgi.cc'] diff --git a/plugins/v8/v8_uwsgi.cc b/plugins/v8/v8_uwsgi.cc new file mode 100644 index 00000000..93bf9db4 --- /dev/null +++ b/plugins/v8/v8_uwsgi.cc @@ -0,0 +1,205 @@ +#include +#include + +struct uwsgi_v8 { + v8::Persistent *contexts; + struct uwsgi_string_list *load; +} uv8; + +extern struct uwsgi_server uwsgi; +extern struct uwsgi_plugin v8_plugin; + +struct uwsgi_option uwsgi_v8_options[] = { + {(char *)"v8-load", required_argument, 0, (char *)"load a javascript file", uwsgi_opt_add_string_list, &uv8.load, 0}, + {0, 0, 0, 0}, +}; + +static v8::Handle uwsgi_v8_api_register_rpc(const v8::Arguments& args) { + + if (args.Length() > 1) { + v8::String::Utf8Value name(args[0]->ToString()); + uint8_t j_argc = 0; + if (args.Length() > 2) { + j_argc = args[2]->Uint32Value(); + } + + v8::Persistent func = v8::Persistent::New(v8::Handle::Cast(args[1])); + + if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, *func)) { + uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name); + return v8::Undefined(); + } + + return v8::True(); + } + + return v8::Undefined(); +} + + +static void uwsgi_v8_load_file(v8::Persistent context, char *filename) { + + v8::HandleScope handle_scope; + + v8::Context::Scope context_scope(context); + + size_t len = 0; + char *code = uwsgi_open_and_read(filename, &len, 1, NULL); + + // we do not use TryCatch as we directly use stderr and simply exit with error code 1 + v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); + free(code); + if (script.IsEmpty()) { + exit(1); + } + + v8::Handle result = script->Run(); + if (result.IsEmpty()) { + exit(1); + } + +} + +extern "C" int uwsgi_v8_init(){ + uwsgi_log("Initializing V8 %s environment... (%d Isolates)\n", v8::V8::GetVersion(), uwsgi.cores); + uv8.contexts = (v8::Persistent *) uwsgi_malloc( sizeof(v8::Persistent*) * uwsgi.cores ); + return 0; +} + +static v8::Handle uwsgi_v8_api_log(const v8::Arguments& args) { + + if (args.Length() > 0) { + v8::String::Utf8Value str(args[0]->ToString()); + size_t slen = strlen(*str); + if ((*str)[slen-1] == '\n') { + uwsgi_log("%s", *str); + } + else { + uwsgi_log("%s\n", *str); + } + } + return v8::Undefined(); +} + +static v8::Persistent uwsgi_v8_new_isolate(int core) { + v8::HandleScope handle_scope; + if (core > 0) { + // create a new isolate + v8::Isolate *isolate = v8::Isolate::New(); + // set as the current isolate + v8::Isolate::Scope iscope(isolate); + } + + v8::Handle global = v8::ObjectTemplate::New(); + // print alias is always handy + global->Set(v8::String::New("uwsgi_log"), v8::FunctionTemplate::New(uwsgi_v8_api_log)); + global->Set(v8::String::New("uwsgi_register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc)); + + // create a new context + v8::Persistent context = v8::Context::New(NULL, global); + return context; +} + +extern "C" void uwsgi_v8_apps() { + + if (!uv8.load) return; + + int i; + for(i=0;ivalue); + usl = usl->next; + } + } +} + +extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) { + + v8::HandleScope handle_scope; + + uwsgi_log_initial("[uWSGI] getting javascript (V8) configuration from %s\n", filename); + + size_t len = 0; + char *code = uwsgi_open_and_read(filename, &len, 1, NULL); + + v8::Handle context = v8::Context::New(); + + v8::Context::Scope context_scope(context); + + // we do not use TryCatch as we directly use stderr and simply exit with error code 1 + + v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); + if (script.IsEmpty()) { + exit(1); + } + free(code); + + v8::Handle result = script->Run(); + if (result.IsEmpty()) { + exit(1); + } + + if (!result->IsArray() && !result->IsObject()) { + uwsgi_log("javascript return value must be an object or an array !!!\n"); + exit(1); + } + + uint32_t i; + const v8::Local props = result->ToObject()->GetPropertyNames(); + const uint32_t l = props->Length(); + + for(i=0;i key = props->Get(i); + const v8::Local value = result->ToObject()->Get(key); + v8::String::Utf8Value c_key(key->ToString()); + if (value->IsArray()) { + uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value(); + uint32_t j; + for(j=0;jToObject()->Get(j)->ToString()); + add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0); + } + } + else { + v8::String::Utf8Value c_value(value->ToString()); + add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0); + } + } + +} + +extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) { + + v8::HandleScope handle_scope; + + v8::Handle argj[256]; + + struct wsgi_request *wsgi_req = current_wsgi_req(); + + v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]); + + + v8::Persistent l_func = static_cast (func); + + uint8_t i; + for(i=0;i result = l_func->Call(l_func, argc, argj); + if (result.IsEmpty()) return 0; + + v8::Handle robj = result->ToString(); + + v8::String::Utf8Value r_value(robj); + if (!*robj) return 0; + uint16_t rlen = robj->Length(); + memcpy(buffer, *r_value, rlen); + // call GC every time, could be overkill, we should allow to tune that choice + while(!v8::V8::IdleNotification()) {}; + return rlen; + +} +