| /** |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <queue> |
| #include <v8.h> |
| |
| #include "logging.h" |
| #include "js_support.h" |
| #include "node_object_wrap.h" |
| #include "node_util.h" |
| #include "util.h" |
| #include "worker.h" |
| |
| #include "worker_v8.h" |
| |
| |
| //#define WORKER_V8_V8_DEBUG |
| #ifdef WORKER_V8_V8_DEBUG |
| |
| #define DBG(...) ALOGD(__VA_ARGS__) |
| |
| #else |
| |
| #define DBG(...) |
| |
| #endif |
| |
| v8::Persistent<v8::FunctionTemplate> WorkerV8Template; |
| |
| class WorkerV8 : public ObjectWrap { |
| private: |
| friend class Handler; |
| |
| |
| struct ArgInfo { |
| v8::Persistent<v8::Object> js_this; |
| v8::Persistent<v8::Value> value; |
| }; |
| |
| pthread_mutex_t ai_free_list_mutex_; |
| std::queue<ArgInfo *> ai_free_list_; |
| |
| ArgInfo *ObtainArgInfo() { |
| ArgInfo *ai; |
| pthread_mutex_lock(&ai_free_list_mutex_); |
| if (ai_free_list_.size() == 0) { |
| ai = new ArgInfo(); |
| } else { |
| ai = ai_free_list_.front(); |
| ai_free_list_.pop(); |
| } |
| pthread_mutex_unlock(&ai_free_list_mutex_); |
| return ai; |
| } |
| |
| void ReleaseArgInfo(ArgInfo *ai) { |
| pthread_mutex_lock(&ai_free_list_mutex_); |
| ai_free_list_.push(ai); |
| pthread_mutex_unlock(&ai_free_list_mutex_); |
| } |
| |
| class Handler : public WorkerQueue { |
| private: |
| v8::Persistent<v8::Value> functionValue_; |
| WorkerV8 *worker_; |
| |
| public: |
| Handler(WorkerV8 *worker, v8::Handle<v8::Value> value) |
| : worker_(worker) { |
| functionValue_ = v8::Persistent<v8::Value>::New(value); |
| } |
| |
| void Process(void *param) { |
| DBG("Handler::Process: E"); |
| |
| v8::Locker locker; |
| v8::HandleScope handle_scope; |
| v8::TryCatch try_catch; |
| try_catch.SetVerbose(true); |
| |
| ArgInfo *ai = (ArgInfo*)param; |
| v8::Handle<v8::Value> args(ai->value); |
| v8::Function::Cast(*functionValue_)->Call(ai->js_this, 1, &args); |
| |
| ai->js_this.Dispose(); |
| ai->value.Dispose(); |
| |
| worker_->ReleaseArgInfo(ai); |
| |
| DBG("Handler::Process: X"); |
| } |
| }; |
| |
| Handler *handler_; |
| |
| public: |
| WorkerV8(v8::Handle<v8::Object> self, v8::Handle<v8::Value> functionValue) { |
| DBG("WorkerV8::WorkerV8 E:"); |
| pthread_mutex_init(&ai_free_list_mutex_, NULL); |
| handler_ = new Handler(this, functionValue); |
| Wrap(self); |
| DBG("WorkerV8::WorkerV8 X: this=%p handler_=%p", this, handler_); |
| } |
| |
| virtual ~WorkerV8() { |
| DBG("~WorkerV8::WorkerV8 E:"); |
| DBG("~WorkerV8::WorkerV8 X:"); |
| } |
| |
| static v8::Handle<v8::Value> Run(const v8::Arguments& args) { |
| WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); |
| DBG("WorkerV8::Run(args) E:"); |
| workerV8->handler_->Run(); |
| DBG("WorkerV8::Run(args) X:"); |
| return v8::Undefined(); |
| } |
| |
| static v8::Handle<v8::Value> Add(const v8::Arguments& args) { |
| DBG("WorkerV8::Add(args) E:"); |
| WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); |
| |
| // Validate one argument to add |
| if (args.Length() != 1) { |
| DBG("WorkerV8::Add(args) X: expecting one param"); |
| return v8::ThrowException(v8::String::New("Add has no parameter")); |
| } |
| ArgInfo *ai = workerV8->ObtainArgInfo(); |
| ai->js_this = v8::Persistent<v8::Object>::New( args.This() ); |
| ai->value = v8::Persistent<v8::Value>::New( args[0] ); |
| |
| workerV8->handler_->Add(ai); |
| DBG("WorkerV8::Add(args) X:"); |
| return v8::Undefined(); |
| } |
| |
| static v8::Handle<v8::Value> AddDelayed(const v8::Arguments& args) { |
| DBG("WorkerV8::AddDelayed(args) E:"); |
| WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); |
| |
| // Validate two argument to addDelayed |
| if (args.Length() != 2) { |
| DBG("WorkerV8::AddDelayed(args) X: expecting two params"); |
| return v8::ThrowException(v8::String::New("AddDelayed expects req delayTime params")); |
| } |
| ArgInfo *ai = workerV8->ObtainArgInfo(); |
| ai->js_this = v8::Persistent<v8::Object>::New( args.This() ); |
| ai->value = v8::Persistent<v8::Value>::New( args[0] ); |
| v8::Handle<v8::Value> v8DelayMs(args[1]->ToObject()); |
| int32_t delay_ms = v8DelayMs->Int32Value(); |
| workerV8->handler_->AddDelayed(ai, delay_ms); |
| |
| DBG("WorkerV8::AddDelayed(args) X:"); |
| return v8::Undefined(); |
| } |
| |
| static v8::Handle<v8::Value> NewWorkerV8(const v8::Arguments& args) { |
| DBG("WorkerV8::NewWorkerV8 E: args.Length()=%d", args.Length()); |
| WorkerV8 *worker = new WorkerV8(args.This(), args[0]); |
| DBG("WorkerV8::NewWorkerV8 X:"); |
| return worker->handle_; |
| } |
| }; |
| |
| void WorkerV8Init() { |
| DBG("WorkerV8Init E:"); |
| v8::HandleScope handle_scope; |
| |
| WorkerV8Template = v8::Persistent<v8::FunctionTemplate>::New( |
| v8::FunctionTemplate::New(WorkerV8::NewWorkerV8)); |
| WorkerV8Template->SetClassName(v8::String::New("Worker")); |
| // native self (Field 0 is handle_) field count is at least 1 |
| WorkerV8Template->InstanceTemplate()->SetInternalFieldCount(1); |
| |
| // Set prototype methods |
| SET_PROTOTYPE_METHOD(WorkerV8Template, "run", WorkerV8::Run); |
| SET_PROTOTYPE_METHOD(WorkerV8Template, "add", WorkerV8::Add); |
| SET_PROTOTYPE_METHOD(WorkerV8Template, "addDelayed", WorkerV8::AddDelayed); |
| |
| DBG("WorkerV8Init X:"); |
| } |
| |
| void testWorkerV8(v8::Handle<v8::Context> context) { |
| ALOGD("testWorkerV8 E: ********"); |
| v8::HandleScope handle_scope; |
| |
| v8::TryCatch try_catch; |
| try_catch.SetVerbose(true); |
| |
| ALOGD("testWorkerV8 runJs"); |
| runJs(context, &try_catch, "local-string", |
| "var w1 = new Worker(function (msg) {" |
| " print('w1: ' + msg);\n" |
| "});\n" |
| "w1.run();\n" |
| "var w2 = new Worker(function (msg) {" |
| " print('w2: ' + msg);\n" |
| "});\n" |
| "w2.run();\n" |
| "w2.addDelayed('three', 1000);\n" |
| "w2.add('one');\n" |
| "w1.add('two');\n" |
| "w1.addDelayed('four', 2000);\n" |
| ); |
| ALOGD("testWorkerV8 X: ********"); |
| } |
| |
| extern void WorkerV8ObjectTemplateInit(v8::Handle<v8::ObjectTemplate> target) { |
| DBG("WorkerV8ObjectTemplateInit(target) E:"); |
| target->Set(v8::String::New("Worker"), WorkerV8Template); |
| DBG("WorkerV8ObjectTemplateInit(target) X:\n"); |
| } |