Home | History | Annotate | Download | only in cpp
      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(...) ALOGD(__VA_ARGS__)
     34 
     35 #else
     36 
     37 #define DBG(...)
     38 
     39 #endif
     40 
     41 v8::Persistent<v8::FunctionTemplate> WorkerV8Template;
     42 
     43 class 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 
    177 void 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 
    195 void testWorkerV8(v8::Handle<v8::Context> context) {
    196     ALOGD("testWorkerV8 E: ********");
    197     v8::HandleScope handle_scope;
    198 
    199     v8::TryCatch try_catch;
    200     try_catch.SetVerbose(true);
    201 
    202     ALOGD("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     ALOGD("testWorkerV8 X: ********");
    218 }
    219 
    220 extern 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