1/** 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <queue> 18#include <v8.h> 19 20#include "logging.h" 21#include "js_support.h" 22#include "node_object_wrap.h" 23#include "node_util.h" 24#include "util.h" 25#include "worker.h" 26 27#include "worker_v8.h" 28 29 30//#define WORKER_V8_V8_DEBUG 31#ifdef WORKER_V8_V8_DEBUG 32 33#define DBG(...) LOGD(__VA_ARGS__) 34 35#else 36 37#define DBG(...) 38 39#endif 40 41v8::Persistent<v8::FunctionTemplate> WorkerV8Template; 42 43class WorkerV8 : public ObjectWrap { 44 private: 45 friend class Handler; 46 47 48 struct ArgInfo { 49 v8::Persistent<v8::Object> js_this; 50 v8::Persistent<v8::Value> value; 51 }; 52 53 pthread_mutex_t ai_free_list_mutex_; 54 std::queue<ArgInfo *> ai_free_list_; 55 56 ArgInfo *ObtainArgInfo() { 57 ArgInfo *ai; 58 pthread_mutex_lock(&ai_free_list_mutex_); 59 if (ai_free_list_.size() == 0) { 60 ai = new ArgInfo(); 61 } else { 62 ai = ai_free_list_.front(); 63 ai_free_list_.pop(); 64 } 65 pthread_mutex_unlock(&ai_free_list_mutex_); 66 return ai; 67 } 68 69 void ReleaseArgInfo(ArgInfo *ai) { 70 pthread_mutex_lock(&ai_free_list_mutex_); 71 ai_free_list_.push(ai); 72 pthread_mutex_unlock(&ai_free_list_mutex_); 73 } 74 75 class Handler : public WorkerQueue { 76 private: 77 v8::Persistent<v8::Value> functionValue_; 78 WorkerV8 *worker_; 79 80 public: 81 Handler(WorkerV8 *worker, v8::Handle<v8::Value> value) 82 : worker_(worker) { 83 functionValue_ = v8::Persistent<v8::Value>::New(value); 84 } 85 86 void Process(void *param) { 87 DBG("Handler::Process: E"); 88 89 v8::Locker locker; 90 v8::HandleScope handle_scope; 91 v8::TryCatch try_catch; 92 try_catch.SetVerbose(true); 93 94 ArgInfo *ai = (ArgInfo*)param; 95 v8::Handle<v8::Value> args(ai->value); 96 v8::Function::Cast(*functionValue_)->Call(ai->js_this, 1, &args); 97 98 ai->js_this.Dispose(); 99 ai->value.Dispose(); 100 101 worker_->ReleaseArgInfo(ai); 102 103 DBG("Handler::Process: X"); 104 } 105 }; 106 107 Handler *handler_; 108 109 public: 110 WorkerV8(v8::Handle<v8::Object> self, v8::Handle<v8::Value> functionValue) { 111 DBG("WorkerV8::WorkerV8 E:"); 112 pthread_mutex_init(&ai_free_list_mutex_, NULL); 113 handler_ = new Handler(this, functionValue); 114 Wrap(self); 115 DBG("WorkerV8::WorkerV8 X: this=%p handler_=%p", this, handler_); 116 } 117 118 virtual ~WorkerV8() { 119 DBG("~WorkerV8::WorkerV8 E:"); 120 DBG("~WorkerV8::WorkerV8 X:"); 121 } 122 123 static v8::Handle<v8::Value> Run(const v8::Arguments& args) { 124 WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); 125 DBG("WorkerV8::Run(args) E:"); 126 workerV8->handler_->Run(); 127 DBG("WorkerV8::Run(args) X:"); 128 return v8::Undefined(); 129 } 130 131 static v8::Handle<v8::Value> Add(const v8::Arguments& args) { 132 DBG("WorkerV8::Add(args) E:"); 133 WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); 134 135 // Validate one argument to add 136 if (args.Length() != 1) { 137 DBG("WorkerV8::Add(args) X: expecting one param"); 138 return v8::ThrowException(v8::String::New("Add has no parameter")); 139 } 140 ArgInfo *ai = workerV8->ObtainArgInfo(); 141 ai->js_this = v8::Persistent<v8::Object>::New( args.This() ); 142 ai->value = v8::Persistent<v8::Value>::New( args[0] ); 143 144 workerV8->handler_->Add(ai); 145 DBG("WorkerV8::Add(args) X:"); 146 return v8::Undefined(); 147 } 148 149 static v8::Handle<v8::Value> AddDelayed(const v8::Arguments& args) { 150 DBG("WorkerV8::AddDelayed(args) E:"); 151 WorkerV8 *workerV8 = ObjectWrap::Unwrap<WorkerV8>(args.This()); 152 153 // Validate two argument to addDelayed 154 if (args.Length() != 2) { 155 DBG("WorkerV8::AddDelayed(args) X: expecting two params"); 156 return v8::ThrowException(v8::String::New("AddDelayed expects req delayTime params")); 157 } 158 ArgInfo *ai = workerV8->ObtainArgInfo(); 159 ai->js_this = v8::Persistent<v8::Object>::New( args.This() ); 160 ai->value = v8::Persistent<v8::Value>::New( args[0] ); 161 v8::Handle<v8::Value> v8DelayMs(args[1]->ToObject()); 162 int32_t delay_ms = v8DelayMs->Int32Value(); 163 workerV8->handler_->AddDelayed(ai, delay_ms); 164 165 DBG("WorkerV8::AddDelayed(args) X:"); 166 return v8::Undefined(); 167 } 168 169 static v8::Handle<v8::Value> NewWorkerV8(const v8::Arguments& args) { 170 DBG("WorkerV8::NewWorkerV8 E: args.Length()=%d", args.Length()); 171 WorkerV8 *worker = new WorkerV8(args.This(), args[0]); 172 DBG("WorkerV8::NewWorkerV8 X:"); 173 return worker->handle_; 174 } 175}; 176 177void WorkerV8Init() { 178 DBG("WorkerV8Init E:"); 179 v8::HandleScope handle_scope; 180 181 WorkerV8Template = v8::Persistent<v8::FunctionTemplate>::New( 182 v8::FunctionTemplate::New(WorkerV8::NewWorkerV8)); 183 WorkerV8Template->SetClassName(v8::String::New("Worker")); 184 // native self (Field 0 is handle_) field count is at least 1 185 WorkerV8Template->InstanceTemplate()->SetInternalFieldCount(1); 186 187 // Set prototype methods 188 SET_PROTOTYPE_METHOD(WorkerV8Template, "run", WorkerV8::Run); 189 SET_PROTOTYPE_METHOD(WorkerV8Template, "add", WorkerV8::Add); 190 SET_PROTOTYPE_METHOD(WorkerV8Template, "addDelayed", WorkerV8::AddDelayed); 191 192 DBG("WorkerV8Init X:"); 193} 194 195void testWorkerV8(v8::Handle<v8::Context> context) { 196 LOGD("testWorkerV8 E: ********"); 197 v8::HandleScope handle_scope; 198 199 v8::TryCatch try_catch; 200 try_catch.SetVerbose(true); 201 202 LOGD("testWorkerV8 runJs"); 203 runJs(context, &try_catch, "local-string", 204 "var w1 = new Worker(function (msg) {" 205 " print('w1: ' + msg);\n" 206 "});\n" 207 "w1.run();\n" 208 "var w2 = new Worker(function (msg) {" 209 " print('w2: ' + msg);\n" 210 "});\n" 211 "w2.run();\n" 212 "w2.addDelayed('three', 1000);\n" 213 "w2.add('one');\n" 214 "w1.add('two');\n" 215 "w1.addDelayed('four', 2000);\n" 216 ); 217 LOGD("testWorkerV8 X: ********"); 218} 219 220extern void WorkerV8ObjectTemplateInit(v8::Handle<v8::ObjectTemplate> target) { 221 DBG("WorkerV8ObjectTemplateInit(target) E:"); 222 target->Set(v8::String::New("Worker"), WorkerV8Template); 223 DBG("WorkerV8ObjectTemplateInit(target) X:\n"); 224} 225