diff options
| author | yo mama <pepper@scannerjammer.com> | 2015-04-04 01:00:59 -0700 |
|---|---|---|
| committer | yo mama <pepper@scannerjammer.com> | 2015-04-04 01:00:59 -0700 |
| commit | c7c22e3db1c826bcfb2bc66651ec480aae0d4ae0 (patch) | |
| tree | 8546df448afef40d3814d2581f4dacff7cebb87f /node_modules/webworker-threads/src | |
Diffstat (limited to 'node_modules/webworker-threads/src')
20 files changed, 3088 insertions, 0 deletions
diff --git a/node_modules/webworker-threads/src/WebWorkerThreads.cc b/node_modules/webworker-threads/src/WebWorkerThreads.cc new file mode 100644 index 0000000..7cf7746 --- /dev/null +++ b/node_modules/webworker-threads/src/WebWorkerThreads.cc @@ -0,0 +1,955 @@ +//2011-11 Proyectos Equis Ka, s.l., jorge@jorgechamorro.com +//WebWorkerThreads.cc + + +#include <v8.h> +#include <node.h> +#include <uv.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <string> + +#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) || defined(_AIX) +#define WWT_PTHREAD 1 +#include <pthread.h> +#include <unistd.h> +#ifndef uv_cond_t +#define uv_cond_signal(x) pthread_cond_signal(x) +#define uv_cond_init(x) pthread_cond_init(x, NULL) +#define uv_cond_wait(x,y) pthread_cond_wait(x, y) +typedef pthread_cond_t uv_cond_t; +#endif +#else +#define pthread_setcancelstate(x,y) NULL +#define pthread_setcanceltype(x,y) NULL +#endif + + +/* +static int debug_threads= 0; +static int debug_allocs= 0; +*/ + +#include "queues_a_gogo.cc" +#include "bson.cc" +#include "jslib.cc" + +//using namespace node; +using namespace v8; + +static Persistent<String> id_symbol; +static Persistent<ObjectTemplate> threadTemplate; +static bool useLocker; + +static typeQueue* freeJobsQueue= NULL; +static typeQueue* freeThreadsQueue= NULL; + +#define kThreadMagicCookie 0x99c0ffee +typedef struct { + uv_async_t async_watcher; //MUST be the first one + + long int id; + uv_thread_t thread; + volatile int sigkill; + + typeQueue inQueue; //Jobs to run + typeQueue outQueue; //Jobs done + + volatile int IDLE; + uv_cond_t IDLE_cv; + uv_mutex_t IDLE_mutex; + + Isolate* isolate; + Persistent<Context> context; + Persistent<Object> JSObject; + Persistent<Object> threadJSObject; + Persistent<Object> dispatchEvents; + + unsigned long threadMagicCookie; +} typeThread; + +enum jobTypes { + kJobTypeEval, + kJobTypeEvent, + kJobTypeEventSerialized +}; + +typedef struct { + int jobType; + Persistent<Object> cb; + union { + struct { + int length; + String::Utf8Value* eventName; + String::Utf8Value** argumentos; + } typeEvent; + struct { + int length; + String::Utf8Value* eventName; + char* buffer; + size_t bufferSize; + } typeEventSerialized; + struct { + int error; + int tiene_callBack; + int useStringObject; + String::Utf8Value* resultado; + union { + char* scriptText_CharPtr; + String::Utf8Value* scriptText_StringObject; + }; + } typeEval; + }; +} typeJob; + +/* + +cd deps/minifier/src +gcc minify.c -o minify +cat ../../../src/events.js | ./minify kEvents_js > ../../../src/kEvents_js +cat ../../../src/load.js | ./minify kLoad_js > ../../../src/kLoad_js +cat ../../../src/createPool.js | ./minify kCreatePool_js > ../../../src/kCreatePool_js +cat ../../../src/worker.js | ./minify kWorker_js > ../../../src/kWorker_js +cat ../../../src/thread_nextTick.js | ./minify kThread_nextTick_js > ../../../src/kThread_nextTick_js + +*/ + +#include "events.js.c" +#include "load.js.c" +#include "createPool.js.c" +#include "worker.js.c" +#include "thread_nextTick.js.c" +//#include "JASON.js.c" + +//node-waf configure uninstall distclean configure build install + + + + + + + + +static typeQueueItem* nuJobQueueItem (void) { + typeQueueItem* qitem= queue_pull(freeJobsQueue); + if (!qitem) { + qitem= nuItem(kItemTypePointer, calloc(1, sizeof(typeJob))); + } + return qitem; +} + + + + + + +static typeThread* isAThread (Handle<Object> receiver) { + typeThread* thread; + + if (receiver->IsObject()) { + if (receiver->InternalFieldCount() == 1) { + thread= (typeThread*) receiver->GetPointerFromInternalField(0); + if (thread && (thread->threadMagicCookie == kThreadMagicCookie)) { + return thread; + } + } + } + + return NULL; +} + + + + + + +static void pushToInQueue (typeQueueItem* qitem, typeThread* thread) { + uv_mutex_lock(&thread->IDLE_mutex); + queue_push(qitem, &thread->inQueue); + if (thread->IDLE) { + uv_cond_signal(&thread->IDLE_cv); + } + uv_mutex_unlock(&thread->IDLE_mutex); +} + + + + + + +static Handle<Value> Puts (const Arguments &args) { + //fprintf(stdout, "*** Puts BEGIN\n"); + + HandleScope scope; + int i= 0; + while (i < args.Length()) { + String::Utf8Value c_str(args[i]); + fputs(*c_str, stdout); + i++; + } + fflush(stdout); + + //fprintf(stdout, "*** Puts END\n"); + return Undefined(); +} + +static Handle<Value> Print (const Arguments &args) { + HandleScope scope; + int i= 0; + while (i < args.Length()) { + String::Utf8Value c_str(args[i]); + fputs(*c_str, stdout); + i++; + } + static char end = '\n'; + fputs(&end, stdout); + fflush(stdout); + + //fprintf(stdout, "*** Puts END\n"); + return Undefined(); +} + + + + +static void eventLoop (typeThread* thread); + +// A background thread +#ifdef WWT_PTHREAD +static void* aThread (void* arg) { +#else +static void aThread (void* arg) { +#endif + + int dummy; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &dummy); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy); + + typeThread* thread= (typeThread*) arg; + thread->isolate= Isolate::New(); + thread->isolate->SetData(thread); + + if (useLocker) { + //printf("**** USING LOCKER: YES\n"); + v8::Locker myLocker(thread->isolate); + //v8::Isolate::Scope isolate_scope(thread->isolate); + eventLoop(thread); + } + else { + //printf("**** USING LOCKER: NO\n"); + //v8::Isolate::Scope isolate_scope(thread->isolate); + eventLoop(thread); + } + thread->isolate->Exit(); + thread->isolate->Dispose(); + + // wake up callback + if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); +#ifdef WWT_PTHREAD + return NULL; +#endif +} + + + +static Handle<Value> threadEmit (const Arguments &args); +static Handle<Value> postMessage (const Arguments &args); +static Handle<Value> postError (const Arguments &args); + + + +static void eventLoop (typeThread* thread) { + thread->isolate->Enter(); + thread->context= Context::New(); + thread->context->Enter(); + + { + HandleScope scope1; + + Local<Object> global= thread->context->Global(); + + Handle<Object> fs_obj = Object::New(); + JSObjFn(fs_obj, "readFileSync", readFileSync_); + global->Set(String::New("native_fs_"), fs_obj, attribute_ro_dd); + + Handle<Object> console_obj = Object::New(); + JSObjFn(console_obj, "log", console_log); + JSObjFn(console_obj, "error", console_error); + global->Set(String::New("console"), console_obj, attribute_ro_dd); + + global->Set(String::NewSymbol("self"), global); + global->Set(String::NewSymbol("global"), global); + + global->Set(String::NewSymbol("puts"), FunctionTemplate::New(Puts)->GetFunction()); + global->Set(String::NewSymbol("print"), FunctionTemplate::New(Print)->GetFunction()); + + global->Set(String::NewSymbol("postMessage"), FunctionTemplate::New(postMessage)->GetFunction()); + global->Set(String::NewSymbol("__postError"), FunctionTemplate::New(postError)->GetFunction()); + + Local<Object> threadObject= Object::New(); + global->Set(String::NewSymbol("thread"), threadObject); + + threadObject->Set(String::NewSymbol("id"), Number::New(thread->id)); + threadObject->Set(String::NewSymbol("emit"), FunctionTemplate::New(threadEmit)->GetFunction()); + Local<Object> dispatchEvents= Script::Compile(String::New(kEvents_js))->Run()->ToObject()->CallAsFunction(threadObject, 0, NULL)->ToObject(); + Local<Object> dispatchNextTicks= Script::Compile(String::New(kThread_nextTick_js))->Run()->ToObject(); + Local<Array> _ntq= (v8::Array*) *threadObject->Get(String::NewSymbol("_ntq")); + + Script::Compile(String::New(kLoad_js))->Run(); + + double nextTickQueueLength= 0; + long int ctr= 0; + + //SetFatalErrorHandler(FatalErrorCB); + + while (!thread->sigkill) { + typeJob* job; + typeQueueItem* qitem; + + { + HandleScope scope2; + TryCatch onError; + String::Utf8Value* str; + Local<String> source; + Local<Script> script; + Local<Value> resultado; + + + while ((qitem= queue_pull(&thread->inQueue))) { + + job= (typeJob*) qitem->asPtr; + + if ((++ctr) > 2e3) { + ctr= 0; + V8::IdleNotification(); + } + + if (job->jobType == kJobTypeEval) { + //Ejecutar un texto + + if (job->typeEval.useStringObject) { + str= job->typeEval.scriptText_StringObject; + source= String::New(**str, (*str).length()); + delete str; + } + else { + source= String::New(job->typeEval.scriptText_CharPtr); + free(job->typeEval.scriptText_CharPtr); + } + + script= Script::New(source); + + if (!onError.HasCaught()) resultado= script->Run(); + + if (job->typeEval.tiene_callBack) { + job->typeEval.error= onError.HasCaught() ? 1 : 0; + job->typeEval.resultado= new String::Utf8Value(job->typeEval.error ? onError.Exception() : resultado); + queue_push(qitem, &thread->outQueue); + // wake up callback + if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); + } + else { + queue_push(qitem, freeJobsQueue); + } + + if (onError.HasCaught()) onError.Reset(); + } + else if (job->jobType == kJobTypeEvent) { + //Emitir evento. + + Local<Value> args[2]; + str= job->typeEvent.eventName; + args[0]= String::New(**str, (*str).length()); + delete str; + + Local<Array> array= Array::New(job->typeEvent.length); + args[1]= array; + + int i= 0; + while (i < job->typeEvent.length) { + str= job->typeEvent.argumentos[i]; + array->Set(i, String::New(**str, (*str).length())); + delete str; + i++; + } + + free(job->typeEvent.argumentos); + queue_push(qitem, freeJobsQueue); + dispatchEvents->CallAsFunction(global, 2, args); + } + else if (job->jobType == kJobTypeEventSerialized) { + Local<Value> args[2]; + str= job->typeEventSerialized.eventName; + args[0]= String::New(**str, (*str).length()); + delete str; + + int len = job->typeEventSerialized.length; + Local<Array> array= Array::New(len); + args[1]= array; + + { + BSON *bson = new BSON(); + char* data = job->typeEventSerialized.buffer; + size_t size = job->typeEventSerialized.bufferSize; + BSONDeserializer deserializer(bson, data, size); + Local<Object> result = deserializer.DeserializeDocument()->ToObject(); + int i = 0; do { array->Set(i, result->Get(i)); } while (++i < len); + free(data); + } + + queue_push(qitem, freeJobsQueue); + dispatchEvents->CallAsFunction(global, 2, args); + } + } + + if (_ntq->Length()) { + + if ((++ctr) > 2e3) { + ctr= 0; + V8::IdleNotification(); + } + + resultado= dispatchNextTicks->CallAsFunction(global, 0, NULL); + if (onError.HasCaught()) { + nextTickQueueLength= 1; + onError.Reset(); + } + else { + nextTickQueueLength= resultado->NumberValue(); + } + } + } + + if (nextTickQueueLength || thread->inQueue.length) continue; + if (thread->sigkill) break; + + uv_mutex_lock(&thread->IDLE_mutex); + if (!thread->inQueue.length) { + thread->IDLE= 1; + uv_cond_wait(&thread->IDLE_cv, &thread->IDLE_mutex); + thread->IDLE= 0; + } + uv_mutex_unlock(&thread->IDLE_mutex); + } + } + + thread->context.Dispose(); +} + + + + + + +static void destroyaThread (typeThread* thread) { + + thread->sigkill= 0; + //TODO: hay que vaciar las colas y destruir los trabajos antes de ponerlas a NULL + thread->inQueue.first= thread->inQueue.last= NULL; + thread->outQueue.first= thread->outQueue.last= NULL; + thread->JSObject->SetPointerInInternalField(0, NULL); + thread->JSObject.Dispose(); + + uv_unref((uv_handle_t*)&thread->async_watcher); + + if (freeThreadsQueue) { + queue_push(nuItem(kItemTypePointer, thread), freeThreadsQueue); + } + else { + free(thread); + } +} + + + + + + +// C callback that runs in the main nodejs thread. This is the one responsible for +// calling the thread's JS callback. +static void Callback (uv_async_t *watcher, int revents) { + typeThread* thread= (typeThread*) watcher; + + if (thread->sigkill) { + destroyaThread(thread); + return; + } + + HandleScope scope; + typeJob* job; + Local<Value> argv[2]; + Local<Value> null= Local<Value>::New(Null()); + typeQueueItem* qitem; + String::Utf8Value* str; + + TryCatch onError; + while ((qitem= queue_pull(&thread->outQueue))) { + job= (typeJob*) qitem->asPtr; + + if (job->jobType == kJobTypeEval) { + + if (job->typeEval.tiene_callBack) { + str= job->typeEval.resultado; + + if (job->typeEval.error) { + argv[0]= Exception::Error(String::New(**str, (*str).length())); + argv[1]= null; + } else { + argv[0]= null; + argv[1]= String::New(**str, (*str).length()); + } + job->cb->CallAsFunction(thread->JSObject, 2, argv); + job->cb.Dispose(); + job->typeEval.tiene_callBack= 0; + + delete str; + job->typeEval.resultado= NULL; + } + + queue_push(qitem, freeJobsQueue); + + if (onError.HasCaught()) { + if (thread->outQueue.first) { + uv_async_send(&thread->async_watcher); // wake up callback again + } + node::FatalException(onError); + return; + } + } + else if (job->jobType == kJobTypeEvent) { + + //fprintf(stdout, "*** Callback\n"); + + Local<Value> args[2]; + + str= job->typeEvent.eventName; + args[0]= String::New(**str, (*str).length()); + delete str; + + Local<Array> array= Array::New(job->typeEvent.length); + args[1]= array; + + int i= 0; + while (i < job->typeEvent.length) { + str= job->typeEvent.argumentos[i]; + array->Set(i, String::New(**str, (*str).length())); + delete str; + i++; + } + + free(job->typeEvent.argumentos); + queue_push(qitem, freeJobsQueue); + thread->dispatchEvents->CallAsFunction(thread->JSObject, 2, args); + } + else if (job->jobType == kJobTypeEventSerialized) { + Local<Value> args[2]; + + str= job->typeEventSerialized.eventName; + args[0]= String::New(**str, (*str).length()); + delete str; + + int len = job->typeEventSerialized.length; + Local<Array> array= Array::New(len); + args[1]= array; + + { + BSON *bson = new BSON(); + char* data = job->typeEventSerialized.buffer; + size_t size = job->typeEventSerialized.bufferSize; + BSONDeserializer deserializer(bson, data, size); + Local<Object> result = deserializer.DeserializeDocument()->ToObject(); + int i = 0; do { array->Set(i, result->Get(i)); } while (++i < len); + free(data); + } + + queue_push(qitem, freeJobsQueue); + thread->dispatchEvents->CallAsFunction(thread->JSObject, 2, args); + } + } +} + + + + + + +// unconditionally destroys a thread by brute force. +static Handle<Value> Destroy (const Arguments &args) { + HandleScope scope; + //TODO: Hay que comprobar que this en un objeto y que tiene hiddenRefTotypeThread_symbol y que no es nil + //TODO: Aquí habría que usar static void TerminateExecution(int thread_id); + //TODO: static void v8::V8::TerminateExecution ( Isolate * isolate= NULL ) [static] + + typeThread* thread= isAThread(args.This()); + if (!thread) { + return ThrowException(Exception::TypeError(String::New("thread.destroy(): the receiver must be a thread object"))); + } + + if (!thread->sigkill) { + //pthread_cancel(thread->thread); + thread->sigkill= 1; + uv_mutex_lock(&thread->IDLE_mutex); + if (thread->IDLE) { + uv_cond_signal(&thread->IDLE_cv); + } + uv_mutex_unlock(&thread->IDLE_mutex); + } + + return Undefined(); +} + + + + + + +// Eval: Pushes a job into the thread's ->inQueue. +static Handle<Value> Eval (const Arguments &args) { + HandleScope scope; + + if (!args.Length()) { + return ThrowException(Exception::TypeError(String::New("thread.eval(program [,callback]): missing arguments"))); + } + + typeThread* thread= isAThread(args.This()); + if (!thread) { + return ThrowException(Exception::TypeError(String::New("thread.eval(): the receiver must be a thread object"))); + } + + typeQueueItem* qitem= nuJobQueueItem(); + typeJob* job= (typeJob*) qitem->asPtr; + + job->typeEval.tiene_callBack= ((args.Length() > 1) && (args[1]->IsFunction())); + if (job->typeEval.tiene_callBack) { + job->cb= Persistent<Object>::New(args[1]->ToObject()); + } + job->typeEval.scriptText_StringObject= new String::Utf8Value(args[0]); + job->typeEval.useStringObject= 1; + job->jobType= kJobTypeEval; + + pushToInQueue(qitem, thread); + return scope.Close(args.This()); +} + + + + + +static char* readFile (Handle<String> path) { + v8::String::Utf8Value c_str(path); + FILE* fp= fopen(*c_str, "rb"); + if (!fp) { + fprintf(stderr, "Error opening the file %s\n", *c_str); + //@bruno: Shouldn't we throw, here ? + return NULL; + } + fseek(fp, 0, SEEK_END); + size_t len= ftell(fp); + rewind(fp); //fseek(fp, 0, SEEK_SET); + char *buf= (char*)malloc((len+1) * sizeof(char)); // +1 to get null terminated string + if (fread(buf, sizeof(char), len, fp) < len) { + fprintf(stderr, "Error reading the file %s\n", *c_str); + return NULL; + } + buf[len] = 0; + fclose(fp); + /* + printf("SOURCE:\n%s\n", buf); + fflush(stdout); + */ + return buf; +} + + + + + + +// Load: Loads from file and passes to Eval +static Handle<Value> Load (const Arguments &args) { + HandleScope scope; + + if (!args.Length()) { + return ThrowException(Exception::TypeError(String::New("thread.load(filename [,callback]): missing arguments"))); + } + + typeThread* thread= isAThread(args.This()); + if (!thread) { + return ThrowException(Exception::TypeError(String::New("thread.load(): the receiver must be a thread object"))); + } + + char* source= readFile(args[0]->ToString()); //@Bruno: here we don't know if the file was not found or if it was an empty file + if (!source) return scope.Close(args.This()); //@Bruno: even if source is empty, we should call the callback ? + + typeQueueItem* qitem= nuJobQueueItem(); + typeJob* job= (typeJob*) qitem->asPtr; + + job->typeEval.tiene_callBack= ((args.Length() > 1) && (args[1]->IsFunction())); + if (job->typeEval.tiene_callBack) { + job->cb= Persistent<Object>::New(args[1]->ToObject()); + } + job->typeEval.scriptText_CharPtr= source; + job->typeEval.useStringObject= 0; + job->jobType= kJobTypeEval; + + pushToInQueue(qitem, thread); + + return scope.Close(args.This()); +} + + + + + + +static Handle<Value> processEmit (const Arguments &args) { + HandleScope scope; + + //fprintf(stdout, "*** processEmit\n"); + + if (!args.Length()) return scope.Close(args.This()); + + typeThread* thread= isAThread(args.This()); + if (!thread) { + return ThrowException(Exception::TypeError(String::New("thread.emit(): the receiver must be a thread object"))); + } + + typeQueueItem* qitem= nuJobQueueItem(); + typeJob* job= (typeJob*) qitem->asPtr; + + job->jobType= kJobTypeEvent; + job->typeEvent.length= args.Length()- 1; + job->typeEvent.eventName= new String::Utf8Value(args[0]); + job->typeEvent.argumentos= (v8::String::Utf8Value**) malloc(job->typeEvent.length* sizeof(void*)); + + int i= 1; + do { + job->typeEvent.argumentos[i-1]= new String::Utf8Value(args[i]); + } while (++i <= job->typeEvent.length); + + pushToInQueue(qitem, thread); + + return scope.Close(args.This()); +} + +static Handle<Value> processEmitSerialized (const Arguments &args) { + HandleScope scope; + + //fprintf(stdout, "*** processEmit\n"); + int len = args.Length(); + + if (!len) return scope.Close(args.This()); + + typeThread* thread= isAThread(args.This()); + if (!thread) { + return ThrowException(Exception::TypeError(String::New("thread.emit(): the receiver must be a thread object"))); + } + + typeQueueItem* qitem= nuJobQueueItem(); + typeJob* job= (typeJob*) qitem->asPtr; + + job->jobType= kJobTypeEventSerialized; + job->typeEventSerialized.length= len-1; + job->typeEventSerialized.eventName= new String::Utf8Value(args[0]); + Local<Array> array= Array::New(len-1); + int i = 1; do { array->Set(i-1, args[i]); } while (++i < len); + + { + char* buffer; + BSON *bson = new BSON(); + size_t object_size; + Local<Object> object = bson->GetSerializeObject(array); + BSONSerializer<CountStream> counter(bson, false, false); + counter.SerializeDocument(object); + object_size = counter.GetSerializeSize(); + buffer = (char *)malloc(object_size); + BSONSerializer<DataStream> data(bson, false, false, buffer); + data.SerializeDocument(object); + job->typeEventSerialized.buffer= buffer; + job->typeEventSerialized.bufferSize= object_size; + } + + pushToInQueue(qitem, thread); + + return scope.Close(args.This()); +} + +#define POST_EVENT(eventname) { \ + HandleScope scope; \ + int len = args.Length(); \ + \ + if (!len) return scope.Close(args.This()); \ + \ + typeThread* thread= (typeThread*) Isolate::GetCurrent()->GetData(); \ + \ + typeQueueItem* qitem= nuJobQueueItem(); \ + typeJob* job= (typeJob*) qitem->asPtr; \ + \ + job->jobType= kJobTypeEventSerialized; \ + job->typeEventSerialized.eventName= new String::Utf8Value(String::New(eventname)); \ + job->typeEventSerialized.length= len; \ + \ + Local<Array> array= Array::New(len); \ + int i = 0; do { array->Set(i, args[i]); } while (++i < len); \ + \ + { \ + char* buffer; \ + BSON *bson = new BSON(); \ + size_t object_size; \ + Local<Object> object = bson->GetSerializeObject(array); \ + BSONSerializer<CountStream> counter(bson, false, false); \ + counter.SerializeDocument(object); \ + object_size = counter.GetSerializeSize(); \ + buffer = (char *)malloc(object_size); \ + BSONSerializer<DataStream> data(bson, false, false, buffer); \ + data.SerializeDocument(object); \ + job->typeEventSerialized.buffer= buffer; \ + job->typeEventSerialized.bufferSize= object_size; \ + } \ + \ + queue_push(qitem, &thread->outQueue); \ + if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); \ + \ + return scope.Close(args.This()); \ +} + +static Handle<Value> postMessage (const Arguments &args) { + POST_EVENT("message"); +} + +static Handle<Value> postError (const Arguments &args) { + POST_EVENT("error"); +} + +static Handle<Value> threadEmit (const Arguments &args) { + HandleScope scope; + + //fprintf(stdout, "*** threadEmit\n"); + + if (!args.Length()) return scope.Close(args.This()); + + int i; + typeThread* thread= (typeThread*) Isolate::GetCurrent()->GetData(); + + typeQueueItem* qitem= nuJobQueueItem(); + typeJob* job= (typeJob*) qitem->asPtr; + + job->jobType= kJobTypeEvent; + job->typeEvent.length= args.Length()- 1; + job->typeEvent.eventName= new String::Utf8Value(args[0]); + job->typeEvent.argumentos= (v8::String::Utf8Value**) malloc(job->typeEvent.length* sizeof(void*)); + + i= 1; + do { + job->typeEvent.argumentos[i-1]= new String::Utf8Value(args[i]); + } while (++i <= job->typeEvent.length); + + queue_push(qitem, &thread->outQueue); + if (!(thread->inQueue.length)) uv_async_send(&thread->async_watcher); // wake up callback + + //fprintf(stdout, "*** threadEmit END\n"); + + return scope.Close(args.This()); +} + + + + + + + + +// Creates and launches a new isolate in a new background thread. +static Handle<Value> Create (const Arguments &args) { + HandleScope scope; + + typeThread* thread; + typeQueueItem* qitem= NULL; + qitem= queue_pull(freeThreadsQueue); + if (qitem) { + thread= (typeThread*) qitem->asPtr; + destroyItem(qitem); + } + else { + thread= (typeThread*) calloc(1, sizeof(typeThread)); + thread->threadMagicCookie= kThreadMagicCookie; + } + + static long int threadsCtr= 0; + thread->id= threadsCtr++; + + thread->JSObject= Persistent<Object>::New(threadTemplate->NewInstance()); + thread->JSObject->Set(id_symbol, Integer::New(thread->id)); + thread->JSObject->SetPointerInInternalField(0, thread); + Local<Value> dispatchEvents= Script::Compile(String::New(kEvents_js))->Run()->ToObject()->CallAsFunction(thread->JSObject, 0, NULL); + thread->dispatchEvents= Persistent<Object>::New(dispatchEvents->ToObject()); + + uv_async_init(uv_default_loop(), &thread->async_watcher, Callback); + uv_ref((uv_handle_t*)&thread->async_watcher); + + uv_cond_init(&thread->IDLE_cv); + uv_mutex_init(&thread->IDLE_mutex); + uv_mutex_init(&thread->inQueue.queueLock); + uv_mutex_init(&thread->outQueue.queueLock); + +#ifdef WWT_PTHREAD + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int err= pthread_create(&thread->thread, &attr, aThread, thread); + pthread_attr_destroy(&attr); +#else + int err= uv_thread_create(&thread->thread, aThread, thread); +#endif + if (err) { + //Ha habido un error no se ha arrancado esta thread + destroyaThread(thread); + return ThrowException(Exception::TypeError(String::New("create(): error in pthread_create()"))); + } + + V8::AdjustAmountOfExternalAllocatedMemory(sizeof(typeThread)); //OJO V8 con V mayúscula. + return scope.Close(thread->JSObject); +} + + +#if NODE_MODULE_VERSION >= 0x000B +void Init (Handle<Object> target, Handle<Value> module) { +#else +void Init (Handle<Object> target) { +#endif + + initQueues(); + freeThreadsQueue= nuQueue(-3); + freeJobsQueue= nuQueue(-4); + + HandleScope scope; + + useLocker= v8::Locker::IsActive(); + + target->Set(String::NewSymbol("create"), FunctionTemplate::New(Create)->GetFunction()); + target->Set(String::NewSymbol("createPool"), Script::Compile(String::New(kCreatePool_js))->Run()->ToObject()); + target->Set(String::NewSymbol("Worker"), Script::Compile(String::New(kWorker_js))->Run()->ToObject()->CallAsFunction(target, 0, NULL)->ToObject()); + //target->Set(String::NewSymbol("JASON"), Script::Compile(String::New(kJASON_js))->Run()->ToObject()); + + id_symbol= Persistent<String>::New(String::NewSymbol("id")); + + threadTemplate= Persistent<ObjectTemplate>::New(ObjectTemplate::New()); + threadTemplate->SetInternalFieldCount(1); + threadTemplate->Set(id_symbol, Integer::New(0)); + threadTemplate->Set(String::NewSymbol("eval"), FunctionTemplate::New(Eval)); + threadTemplate->Set(String::NewSymbol("load"), FunctionTemplate::New(Load)); + threadTemplate->Set(String::NewSymbol("emit"), FunctionTemplate::New(processEmit)); + threadTemplate->Set(String::NewSymbol("emitSerialized"), FunctionTemplate::New(processEmitSerialized)); + threadTemplate->Set(String::NewSymbol("destroy"), FunctionTemplate::New(Destroy)); + +} + + + + +NODE_MODULE(WebWorkerThreads, Init) + +/* +gcc -E -I /Users/jorge/JAVASCRIPT/binarios/include/node -o /o.c /Users/jorge/JAVASCRIPT/threads_a_gogo/src/threads_a_gogo.cc && mate /o.c +*/ diff --git a/node_modules/webworker-threads/src/bson.cc b/node_modules/webworker-threads/src/bson.cc new file mode 100644 index 0000000..accf8da --- /dev/null +++ b/node_modules/webworker-threads/src/bson.cc @@ -0,0 +1,1016 @@ +//===========================================================================
+
+#include <stdarg.h>
+#include <cstdlib>
+#include <cstring>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include <v8.h>
+
+// this and the above block must be around the v8.h header otherwise
+// v8 is not happy
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include "bson.h"
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+void DataStream::WriteObjectId(const Handle<Object>& object, const Handle<String>& key)
+{
+ uint16_t buffer[12];
+ object->Get(key)->ToString()->Write(buffer, 0, 12);
+ for(uint32_t i = 0; i < 12; ++i)
+ {
+ *p++ = (char) buffer[i];
+ }
+}
+
+void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char* string = (char*) malloc(allocationSize);
+ vsprintf(string, format, args);
+ va_end(args);
+
+ throw string;
+}
+
+void DataStream::CheckKey(const Local<String>& keyName)
+{
+ size_t keyLength = keyName->Utf8Length();
+ if(keyLength == 0) return;
+
+ char* keyStringBuffer = (char*) alloca(keyLength+1);
+ keyName->WriteUtf8(keyStringBuffer);
+
+ if(keyStringBuffer[0] == '$')
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer);
+ }
+
+ if(strchr(keyStringBuffer, '.') != NULL)
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer);
+ }
+}
+
+template<typename T> void BSONSerializer<T>::SerializeDocument(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+ Local<Object> object = bson->GetSerializeObject(value);
+
+ // Get the object property names
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> propertyNames = object->GetPropertyNames();
+ #else
+ Local<Array> propertyNames = object->GetOwnPropertyNames();
+ #endif
+
+ // Length of the property
+ int propertyLength = propertyNames->Length();
+ for(int i = 0; i < propertyLength; ++i)
+ {
+ const Local<String>& propertyName = propertyNames->Get(i)->ToString();
+ if(checkKeys) this->CheckKey(propertyName);
+
+ const Local<Value>& propertyValue = object->Get(propertyName);
+
+ if(serializeFunctions || !propertyValue->IsFunction())
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteString(propertyName);
+ SerializeValue(typeLocation, propertyValue);
+ }
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+template<typename T> void BSONSerializer<T>::SerializeArray(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+
+ Local<Array> array = Local<Array>::Cast(value->ToObject());
+ uint32_t arrayLength = array->Length();
+
+ for(uint32_t i = 0; i < arrayLength; ++i)
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteUInt32String(i);
+ SerializeValue(typeLocation, array->Get(i));
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes.
+// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths)
+// and ensures that there is always consistency between bytes counted and bytes written by design.
+template<typename T> void BSONSerializer<T>::SerializeValue(void* typeLocation, const Handle<Value>& value)
+{
+ if(value->IsNumber())
+ {
+ double doubleValue = value->NumberValue();
+ int intValue = (int) doubleValue;
+ if(intValue == doubleValue)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_INT);
+ this->WriteInt32(intValue);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(doubleValue);
+ }
+ }
+ else if(value->IsString())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_STRING);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsBoolean())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BOOLEAN);
+ this->WriteBool(value);
+ }
+ else if(value->IsArray())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_ARRAY);
+ SerializeArray(value);
+ }
+ else if(value->IsDate())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_DATE);
+ this->WriteInt64(value);
+ }
+ else if(value->IsRegExp())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_REGEXP);
+ const Handle<RegExp>& regExp = Handle<RegExp>::Cast(value);
+
+ this->WriteString(regExp->GetSource());
+
+ int flags = regExp->GetFlags();
+ if(flags & RegExp::kGlobal) this->WriteByte('s');
+ if(flags & RegExp::kIgnoreCase) this->WriteByte('i');
+ if(flags & RegExp::kMultiline) this->WriteByte('m');
+ this->WriteByte(0);
+ }
+ else if(value->IsFunction())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsObject())
+ {
+ const Local<Object>& object = value->ToObject();
+ if(object->Has(bson->_bsontypeString))
+ {
+ const Local<String>& constructorString = object->GetConstructorName();
+ if(bson->longString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_LONG);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->timestampString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->objectIDString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OID);
+ this->WriteObjectId(object, bson->_objectIDidString);
+ }
+ else if(bson->binaryString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ uint32_t length = object->Get(bson->_binaryPositionString)->Uint32Value();
+ Local<Object> bufferObj = object->Get(bson->_binaryBufferString)->ToObject();
+
+ this->WriteInt32(length);
+ this->WriteByte(object, bson->_binarySubTypeString); // write subtype
+ this->WriteData(Buffer::Data(bufferObj), length);
+ }
+ else if(bson->doubleString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(object, bson->_doubleValueString);
+ }
+ else if(bson->symbolString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_SYMBOL);
+ this->WriteLengthPrefixedString(object->Get(bson->_symbolValueString)->ToString());
+ }
+ else if(bson->codeString->StrictEquals(constructorString))
+ {
+ const Local<String>& function = object->Get(bson->_codeCodeString)->ToString();
+ const Local<Object>& scope = object->Get(bson->_codeScopeString)->ToObject();
+
+ // For Node < 0.6.X use the GetPropertyNames
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
+ #else
+ uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
+ #endif
+
+ if(propertyNameLength > 0)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE);
+ void* codeWidthScopeSize = this->BeginWriteSize();
+ this->WriteLengthPrefixedString(function->ToString());
+ SerializeDocument(scope);
+ this->CommitSize(codeWidthScopeSize);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(function->ToString());
+ }
+ }
+ else if(bson->dbrefString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+
+ void* dbRefSize = this->BeginWriteSize();
+
+ void* refType = this->BeginWriteType();
+ this->WriteData("$ref", 5);
+ SerializeValue(refType, object->Get(bson->_dbRefNamespaceString));
+
+ void* idType = this->BeginWriteType();
+ this->WriteData("$id", 4);
+ SerializeValue(idType, object->Get(bson->_dbRefOidString));
+
+ const Local<Value>& refDbValue = object->Get(bson->_dbRefDbString);
+ if(!refDbValue->IsUndefined())
+ {
+ void* dbType = this->BeginWriteType();
+ this->WriteData("$db", 4);
+ SerializeValue(dbType, refDbValue);
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(dbRefSize);
+ }
+ else if(bson->minKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MIN_KEY);
+ }
+ else if(bson->maxKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MAX_KEY);
+ }
+ }
+ else if(Buffer::HasInstance(value))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(value->ToObject());
+ uint32_t length = object->length();
+ #else
+ uint32_t length = Buffer::Length(value->ToObject());
+ #endif
+
+ this->WriteInt32(length);
+ this->WriteByte(0);
+ this->WriteData(Buffer::Data(value->ToObject()), length);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+ SerializeDocument(value);
+ }
+ }
+ else if(value->IsNull() || value->IsUndefined())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NULL);
+ }
+}
+
+// Data points to start of element list, length is length of entire document including '\0' but excluding initial size
+BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length)
+: bson(aBson),
+ pStart(data),
+ p(data),
+ pEnd(data + length - 1)
+{
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length)
+: bson(parentSerializer.bson),
+ pStart(parentSerializer.p),
+ p(parentSerializer.p),
+ pEnd(parentSerializer.p + length - 1)
+{
+ parentSerializer.p += length;
+ if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds");
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+Local<String> BSONDeserializer::ReadCString()
+{
+ char* start = p;
+ while(*p++) { }
+ return String::New(start, (int32_t) (p-start-1) );
+}
+
+int32_t BSONDeserializer::ReadRegexOptions()
+{
+ int32_t options = 0;
+ for(;;)
+ {
+ switch(*p++)
+ {
+ case '\0': return options;
+ case 's': options |= RegExp::kGlobal; break;
+ case 'i': options |= RegExp::kIgnoreCase; break;
+ case 'm': options |= RegExp::kMultiline; break;
+ }
+ }
+}
+
+uint32_t BSONDeserializer::ReadIntegerString()
+{
+ uint32_t value = 0;
+ while(*p)
+ {
+ if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array");
+ value = value * 10 + *p++ - '0';
+ }
+ ++p;
+ return value;
+}
+
+Local<String> BSONDeserializer::ReadString()
+{
+ uint32_t length = ReadUInt32();
+ char* start = p;
+ p += length;
+ return String::New(start, length-1);
+}
+
+Local<String> BSONDeserializer::ReadObjectId()
+{
+ uint16_t objectId[12];
+ for(size_t i = 0; i < 12; ++i)
+ {
+ objectId[i] = *reinterpret_cast<unsigned char*>(p++);
+ }
+ return String::New(objectId, 12);
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocument()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeDocumentInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocumentInternal()
+{
+ Local<Object> returnObject = Object::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ const Local<String>& name = ReadCString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnObject->ForceSet(name, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes");
+
+ // From JavaScript:
+ // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
+ if(returnObject->Has(bson->_dbRefIdRefString))
+ {
+ Local<Value> argv[] = { returnObject->Get(bson->_dbRefRefString), returnObject->Get(bson->_dbRefIdRefString), returnObject->Get(bson->_dbRefDbRefString) };
+ return bson->dbrefConstructor->NewInstance(3, argv);
+ }
+ else
+ {
+ return returnObject;
+ }
+}
+
+Handle<Value> BSONDeserializer::DeserializeArray()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeArrayInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeArrayInternal()
+{
+ Local<Array> returnArray = Array::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ uint32_t index = ReadIntegerString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnArray->Set(index, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes");
+
+ return returnArray;
+}
+
+Handle<Value> BSONDeserializer::DeserializeValue(BsonType type)
+{
+ switch(type)
+ {
+ case BSON_TYPE_STRING:
+ return ReadString();
+
+ case BSON_TYPE_INT:
+ return Integer::New(ReadInt32());
+
+ case BSON_TYPE_NUMBER:
+ return Number::New(ReadDouble());
+
+ case BSON_TYPE_NULL:
+ return Null();
+
+ case BSON_TYPE_UNDEFINED:
+ return Undefined();
+
+ case BSON_TYPE_TIMESTAMP:
+ {
+ int32_t lowBits = ReadInt32();
+ int32_t highBits = ReadInt32();
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->timestampConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_BOOLEAN:
+ return (ReadByte() != 0) ? True() : False();
+
+ case BSON_TYPE_REGEXP:
+ {
+ const Local<String>& regex = ReadCString();
+ int32_t options = ReadRegexOptions();
+ return RegExp::New(regex, (RegExp::Flags) options);
+ }
+
+ case BSON_TYPE_CODE:
+ {
+ const Local<Value>& code = ReadString();
+ const Local<Value>& scope = Object::New();
+ Local<Value> argv[] = { code, scope };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_CODE_W_SCOPE:
+ {
+ ReadUInt32();
+ const Local<Value>& code = ReadString();
+ const Handle<Value>& scope = DeserializeDocument();
+ Local<Value> argv[] = { code, scope->ToObject() };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_OID:
+ {
+ Local<Value> argv[] = { ReadObjectId() };
+ return bson->objectIDConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_BINARY:
+ {
+ uint32_t length = ReadUInt32();
+ uint32_t subType = ReadByte();
+ Buffer* buffer = Buffer::New(p, length);
+ p += length;
+
+ Handle<Value> argv[] = { buffer->handle_, Uint32::New(subType) };
+ return bson->binaryConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_LONG:
+ {
+ // Read 32 bit integers
+ int32_t lowBits = (int32_t) ReadInt32();
+ int32_t highBits = (int32_t) ReadInt32();
+
+ // If value is < 2^53 and >-2^53
+ if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
+ // Adjust the pointer and read as 64 bit value
+ p -= 8;
+ // Read the 64 bit value
+ int64_t finalValue = (int64_t) ReadInt64();
+ return Number::New(finalValue);
+ }
+
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->longConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_DATE:
+ return Date::New((double) ReadInt64());
+
+ case BSON_TYPE_ARRAY:
+ return DeserializeArray();
+
+ case BSON_TYPE_OBJECT:
+ return DeserializeDocument();
+
+ case BSON_TYPE_SYMBOL:
+ {
+ const Local<String>& string = ReadString();
+ Local<Value> argv[] = { string };
+ return bson->symbolConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_MIN_KEY:
+ return bson->minKeyConstructor->NewInstance();
+
+ case BSON_TYPE_MAX_KEY:
+ return bson->maxKeyConstructor->NewInstance();
+
+ default:
+ ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type);
+ }
+
+ return v8::Null();
+}
+
+
+static Handle<Value> VException(const char *msg)
+{
+ HandleScope scope;
+ return ThrowException(Exception::Error(String::New(msg)));
+}
+
+Persistent<FunctionTemplate> BSON::constructor_template;
+
+BSON::BSON() : ObjectWrap()
+{
+ // Setup pre-allocated comparision objects
+ _bsontypeString = Persistent<String>::New(String::New("_bsontype"));
+ _longLowString = Persistent<String>::New(String::New("low_"));
+ _longHighString = Persistent<String>::New(String::New("high_"));
+ _objectIDidString = Persistent<String>::New(String::New("id"));
+ _binaryPositionString = Persistent<String>::New(String::New("position"));
+ _binarySubTypeString = Persistent<String>::New(String::New("sub_type"));
+ _binaryBufferString = Persistent<String>::New(String::New("buffer"));
+ _doubleValueString = Persistent<String>::New(String::New("value"));
+ _symbolValueString = Persistent<String>::New(String::New("value"));
+ _dbRefRefString = Persistent<String>::New(String::New("$ref"));
+ _dbRefIdRefString = Persistent<String>::New(String::New("$id"));
+ _dbRefDbRefString = Persistent<String>::New(String::New("$db"));
+ _dbRefNamespaceString = Persistent<String>::New(String::New("namespace"));
+ _dbRefDbString = Persistent<String>::New(String::New("db"));
+ _dbRefOidString = Persistent<String>::New(String::New("oid"));
+ _codeCodeString = Persistent<String>::New(String::New("code"));
+ _codeScopeString = Persistent<String>::New(String::New("scope"));
+ _toBSONString = Persistent<String>::New(String::New("toBSON"));
+
+ longString = Persistent<String>::New(String::New("Long"));
+ objectIDString = Persistent<String>::New(String::New("ObjectID"));
+ binaryString = Persistent<String>::New(String::New("Binary"));
+ codeString = Persistent<String>::New(String::New("Code"));
+ dbrefString = Persistent<String>::New(String::New("DBRef"));
+ symbolString = Persistent<String>::New(String::New("Symbol"));
+ doubleString = Persistent<String>::New(String::New("Double"));
+ timestampString = Persistent<String>::New(String::New("Timestamp"));
+ minKeyString = Persistent<String>::New(String::New("MinKey"));
+ maxKeyString = Persistent<String>::New(String::New("MaxKey"));
+}
+
+void BSON::Initialize(v8::Handle<v8::Object> target)
+{
+ // Grab the scope of the call from Node
+ HandleScope scope;
+ // Define a new function template
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("BSON"));
+
+ // Instance methods
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream);
+
+ target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction());
+}
+
+// Create a new instance of BSON and passing it the existing context
+Handle<Value> BSON::New(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Check that we have an array
+ if(args.Length() == 1 && args[0]->IsArray())
+ {
+ // Cast the array to a local reference
+ Local<Array> array = Local<Array>::Cast(args[0]);
+
+ if(array->Length() > 0)
+ {
+ // Create a bson object instance and return it
+ BSON *bson = new BSON();
+
+ uint32_t foundClassesMask = 0;
+
+ // Iterate over all entries to save the instantiate funtions
+ for(uint32_t i = 0; i < array->Length(); i++)
+ {
+ // Let's get a reference to the function
+ Local<Function> func = Local<Function>::Cast(array->Get(i));
+ Local<String> functionName = func->GetName()->ToString();
+
+ // Save the functions making them persistant handles (they don't get collected)
+ if(functionName->StrictEquals(bson->longString))
+ {
+ bson->longConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 1;
+ }
+ else if(functionName->StrictEquals(bson->objectIDString))
+ {
+ bson->objectIDConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 2;
+ }
+ else if(functionName->StrictEquals(bson->binaryString))
+ {
+ bson->binaryConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 4;
+ }
+ else if(functionName->StrictEquals(bson->codeString))
+ {
+ bson->codeConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 8;
+ }
+ else if(functionName->StrictEquals(bson->dbrefString))
+ {
+ bson->dbrefConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x10;
+ }
+ else if(functionName->StrictEquals(bson->symbolString))
+ {
+ bson->symbolConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x20;
+ }
+ else if(functionName->StrictEquals(bson->doubleString))
+ {
+ bson->doubleConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x40;
+ }
+ else if(functionName->StrictEquals(bson->timestampString))
+ {
+ bson->timestampConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x80;
+ }
+ else if(functionName->StrictEquals(bson->minKeyString))
+ {
+ bson->minKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x100;
+ }
+ else if(functionName->StrictEquals(bson->maxKeyString))
+ {
+ bson->maxKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x200;
+ }
+ }
+
+ // Check if we have the right number of constructors otherwise throw an error
+ if(foundClassesMask != 0x3ff)
+ {
+ delete bson;
+ return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
+ }
+ else
+ {
+ bson->Wrap(args.This());
+ return args.This();
+ }
+ }
+ else
+ {
+ return VException("No types passed in");
+ }
+ }
+ else
+ {
+ return VException("Argument passed in must be an array of types");
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+
+Handle<Value> BSON::BSONDeserialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Ensure that we have an parameter
+ if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1.");
+ if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1.");
+ // Throw an exception if the argument is not of type Buffer
+ if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String.");
+
+ // Define pointer to data
+ Local<Object> obj = args[0]->ToObject();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
+ if(Buffer::HasInstance(obj))
+ {
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ char* data = buffer->data();
+ size_t length = buffer->length();
+#else
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+#endif
+
+ // Validate that we have at least 5 bytes
+ if(length < 5) return VException("corrupt bson message < 5 bytes long");
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, length);
+ return deserializer.DeserializeDocument();
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+
+ }
+ else
+ {
+ // The length of the data for this encoding
+ ssize_t len = DecodeBytes(args[0], BINARY);
+
+ // Validate that we have at least 5 bytes
+ if(len < 5) return VException("corrupt bson message < 5 bytes long");
+
+ // Let's define the buffer size
+ char* data = (char *)malloc(len);
+ DecodeWrite(data, len, args[0], BINARY);
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, len);
+ Handle<Value> result = deserializer.DeserializeDocument();
+ free(data);
+ return result;
+
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ free(data);
+ return error;
+ }
+ }
+}
+
+Local<Object> BSON::GetSerializeObject(const Handle<Value>& argValue)
+{
+ Local<Object> object = argValue->ToObject();
+ if(object->Has(_toBSONString))
+ {
+ const Local<Value>& toBSON = object->Get(_toBSONString);
+ if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function");
+
+ Local<Value> result = Local<Function>::Cast(toBSON)->Call(object, 0, NULL);
+ if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object");
+ return result->ToObject();
+ }
+ else
+ {
+ return object;
+ }
+}
+
+Handle<Value> BSON::BSONSerialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+ if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Calculate the total size of the document in binary form to ensure we only allocate memory once
+ // With serialize function
+ bool serializeFunctions = (args.Length() >= 4) && args[3]->BooleanValue();
+
+ char *serialized_object = NULL;
+ size_t object_size;
+ try
+ {
+ Local<Object> object = bson->GetSerializeObject(args[0]);
+
+ BSONSerializer<CountStream> counter(bson, false, serializeFunctions);
+ counter.SerializeDocument(object);
+ object_size = counter.GetSerializeSize();
+
+ // Allocate the memory needed for the serialization
+ serialized_object = (char *)malloc(object_size);
+
+ // Check if we have a boolean value
+ bool checkKeys = args.Length() >= 3 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ BSONSerializer<DataStream> data(bson, checkKeys, serializeFunctions, serialized_object);
+ data.SerializeDocument(object);
+ }
+ catch(char *err_msg)
+ {
+ free(serialized_object);
+ Handle<Value> error = VException(err_msg);
+ free(err_msg);
+ return error;
+ }
+
+ // If we have 3 arguments
+ if(args.Length() == 3 || args.Length() == 4)
+ {
+ Buffer *buffer = Buffer::New(serialized_object, object_size);
+ free(serialized_object);
+ return scope.Close(buffer->handle_);
+ }
+ else
+ {
+ Local<Value> bin_value = Encode(serialized_object, object_size, BINARY)->ToString();
+ free(serialized_object);
+ return bin_value;
+ }
+}
+
+Handle<Value> BSON::CalculateObjectSize(const Arguments &args)
+{
+ HandleScope scope;
+ // Ensure we have a valid object
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]");
+ if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+ bool serializeFunctions = (args.Length() >= 2) && args[1]->BooleanValue();
+ BSONSerializer<CountStream> countSerializer(bson, false, serializeFunctions);
+ countSerializer.SerializeDocument(args[0]);
+
+ // Return the object size
+ return scope.Close(Uint32::New((uint32_t) countSerializer.GetSerializeSize()));
+}
+
+Handle<Value> BSON::SerializeWithBufferAndIndex(const Arguments &args)
+{
+ HandleScope scope;
+
+ //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) {
+ // Ensure we have the correct values
+ if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]");
+ if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]");
+
+ uint32_t index;
+ size_t object_size;
+
+ try
+ {
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ Local<Object> obj = args[2]->ToObject();
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+
+ index = args[3]->Uint32Value();
+ bool checkKeys = args.Length() >= 4 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ bool serializeFunctions = (args.Length() == 5) && args[4]->BooleanValue();
+
+ BSONSerializer<DataStream> dataSerializer(bson, checkKeys, serializeFunctions, data+index);
+ dataSerializer.SerializeDocument(bson->GetSerializeObject(args[0]));
+ object_size = dataSerializer.GetSerializeSize();
+
+ if(object_size + index > length) return VException("Serious error - overflowed buffer!!");
+ }
+ catch(char *exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+
+ return scope.Close(Uint32::New((uint32_t) (index + object_size - 1)));
+}
+
+Handle<Value> BSON::BSONDeserializeStream(const Arguments &args)
+{
+ HandleScope scope;
+
+ // At least 3 arguments required
+ if(args.Length() < 5) return VException("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))");
+
+ // If the number of argumets equals 3
+ if(args.Length() >= 5)
+ {
+ if(!Buffer::HasInstance(args[0])) return VException("First argument must be Buffer instance");
+ if(!args[1]->IsUint32()) return VException("Second argument must be a positive index number");
+ if(!args[2]->IsUint32()) return VException("Third argument must be a positive number of documents to deserialize");
+ if(!args[3]->IsArray()) return VException("Fourth argument must be an array the size of documents to deserialize");
+ if(!args[4]->IsUint32()) return VException("Sixth argument must be a positive index number");
+ }
+
+ // If we have 4 arguments
+ if(args.Length() == 6 && !args[5]->IsObject()) return VException("Fifth argument must be an object with options");
+
+ // Define pointer to data
+ Local<Object> obj = args[0]->ToObject();
+ uint32_t numberOfDocuments = args[2]->Uint32Value();
+ uint32_t index = args[1]->Uint32Value();
+ uint32_t resultIndex = args[4]->Uint32Value();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Unpack the buffer variable
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ char* data = buffer->data();
+ size_t length = buffer->length();
+#else
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+#endif
+
+ // Fetch the documents
+ Local<Object> documents = args[3]->ToObject();
+
+ BSONDeserializer deserializer(bson, data+index, length-index);
+ for(uint32_t i = 0; i < numberOfDocuments; i++)
+ {
+ try
+ {
+ documents->Set(i + resultIndex, deserializer.DeserializeDocument());
+ }
+ catch (char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+ }
+
+ // Return new index of parsing
+ return scope.Close(Uint32::New((uint32_t) (index + deserializer.GetSerializeSize())));
+}
+
+// Exporting function
+extern "C" void init(Handle<Object> target)
+{
+ HandleScope scope;
+ BSON::Initialize(target);
+}
+
+NODE_MODULE(bson, BSON::Initialize);
diff --git a/node_modules/webworker-threads/src/bson.h b/node_modules/webworker-threads/src/bson.h new file mode 100644 index 0000000..6f484b1 --- /dev/null +++ b/node_modules/webworker-threads/src/bson.h @@ -0,0 +1,277 @@ +//===========================================================================
+
+#ifndef BSON_H_
+#define BSON_H_
+
+#ifdef __sun
+#include <alloca.h>
+#endif
+
+//===========================================================================
+
+#define USE_MISALIGNED_MEMORY_ACCESS 1
+
+#include <node.h>
+#include <node_object_wrap.h>
+#include <v8.h>
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+enum BsonType
+{
+ BSON_TYPE_NUMBER = 1,
+ BSON_TYPE_STRING = 2,
+ BSON_TYPE_OBJECT = 3,
+ BSON_TYPE_ARRAY = 4,
+ BSON_TYPE_BINARY = 5,
+ BSON_TYPE_UNDEFINED = 6,
+ BSON_TYPE_OID = 7,
+ BSON_TYPE_BOOLEAN = 8,
+ BSON_TYPE_DATE = 9,
+ BSON_TYPE_NULL = 10,
+ BSON_TYPE_REGEXP = 11,
+ BSON_TYPE_CODE = 13,
+ BSON_TYPE_SYMBOL = 14,
+ BSON_TYPE_CODE_W_SCOPE = 15,
+ BSON_TYPE_INT = 16,
+ BSON_TYPE_TIMESTAMP = 17,
+ BSON_TYPE_LONG = 18,
+ BSON_TYPE_MAX_KEY = 0x7f,
+ BSON_TYPE_MIN_KEY = 0xff
+};
+
+//===========================================================================
+
+template<typename T> class BSONSerializer;
+
+class BSON : public ObjectWrap {
+public:
+ BSON();
+ ~BSON() {}
+
+ static void Initialize(Handle<Object> target);
+ static Handle<Value> BSONDeserializeStream(const Arguments &args);
+
+ // JS based objects
+ static Handle<Value> BSONSerialize(const Arguments &args);
+ static Handle<Value> BSONDeserialize(const Arguments &args);
+
+ // Calculate size of function
+ static Handle<Value> CalculateObjectSize(const Arguments &args);
+ static Handle<Value> SerializeWithBufferAndIndex(const Arguments &args);
+
+ // Constructor used for creating new BSON objects from C++
+ static Persistent<FunctionTemplate> constructor_template;
+
+private:
+ static Handle<Value> New(const Arguments &args);
+ static Handle<Value> deserialize(BSON *bson, char *data, uint32_t dataLength, uint32_t startIndex, bool is_array_item);
+
+ // BSON type instantiate functions
+ Persistent<Function> longConstructor;
+ Persistent<Function> objectIDConstructor;
+ Persistent<Function> binaryConstructor;
+ Persistent<Function> codeConstructor;
+ Persistent<Function> dbrefConstructor;
+ Persistent<Function> symbolConstructor;
+ Persistent<Function> doubleConstructor;
+ Persistent<Function> timestampConstructor;
+ Persistent<Function> minKeyConstructor;
+ Persistent<Function> maxKeyConstructor;
+
+ // Equality Objects
+ Persistent<String> longString;
+ Persistent<String> objectIDString;
+ Persistent<String> binaryString;
+ Persistent<String> codeString;
+ Persistent<String> dbrefString;
+ Persistent<String> symbolString;
+ Persistent<String> doubleString;
+ Persistent<String> timestampString;
+ Persistent<String> minKeyString;
+ Persistent<String> maxKeyString;
+
+ // Equality speed up comparison objects
+ Persistent<String> _bsontypeString;
+ Persistent<String> _longLowString;
+ Persistent<String> _longHighString;
+ Persistent<String> _objectIDidString;
+ Persistent<String> _binaryPositionString;
+ Persistent<String> _binarySubTypeString;
+ Persistent<String> _binaryBufferString;
+ Persistent<String> _doubleValueString;
+ Persistent<String> _symbolValueString;
+
+ Persistent<String> _dbRefRefString;
+ Persistent<String> _dbRefIdRefString;
+ Persistent<String> _dbRefDbRefString;
+ Persistent<String> _dbRefNamespaceString;
+ Persistent<String> _dbRefDbString;
+ Persistent<String> _dbRefOidString;
+
+ Persistent<String> _codeCodeString;
+ Persistent<String> _codeScopeString;
+ Persistent<String> _toBSONString;
+
+public: Local<Object> GetSerializeObject(const Handle<Value>& object);
+
+ template<typename T> friend class BSONSerializer;
+ friend class BSONDeserializer;
+};
+
+//===========================================================================
+
+class CountStream
+{
+public:
+ CountStream() : count(0) { }
+
+ void WriteByte(int value) { ++count; }
+ void WriteByte(const Handle<Object>&, const Handle<String>&) { ++count; }
+ void WriteBool(const Handle<Value>& value) { ++count; }
+ void WriteInt32(int32_t value) { count += 4; }
+ void WriteInt32(const Handle<Value>& value) { count += 4; }
+ void WriteInt32(const Handle<Object>& object, const Handle<String>& key) { count += 4; }
+ void WriteInt64(int64_t value) { count += 8; }
+ void WriteInt64(const Handle<Value>& value) { count += 8; }
+ void WriteDouble(double value) { count += 8; }
+ void WriteDouble(const Handle<Value>& value) { count += 8; }
+ void WriteDouble(const Handle<Object>&, const Handle<String>&) { count += 8; }
+ void WriteUInt32String(uint32_t name) { char buffer[32]; count += sprintf(buffer, "%u", name) + 1; }
+ void WriteLengthPrefixedString(const Local<String>& value) { count += value->Utf8Length()+5; }
+ void WriteObjectId(const Handle<Object>& object, const Handle<String>& key) { count += 12; }
+ void WriteString(const Local<String>& value) { count += value->Utf8Length() + 1; } // This returns the number of bytes exclusive of the NULL terminator
+ void WriteData(const char* data, size_t length) { count += length; }
+
+ void* BeginWriteType() { ++count; return NULL; }
+ void CommitType(void*, BsonType) { }
+ void* BeginWriteSize() { count += 4; return NULL; }
+ void CommitSize(void*) { }
+
+ size_t GetSerializeSize() const { return count; }
+
+ // Do nothing. CheckKey is implemented for DataStream
+ void CheckKey(const Local<String>&) { }
+
+private:
+ size_t count;
+};
+
+class DataStream
+{
+public:
+ DataStream(char* aDestinationBuffer) : destinationBuffer(aDestinationBuffer), p(aDestinationBuffer) { }
+
+ void WriteByte(int value) { *p++ = value; }
+ void WriteByte(const Handle<Object>& object, const Handle<String>& key) { *p++ = object->Get(key)->Int32Value(); }
+#if USE_MISALIGNED_MEMORY_ACCESS
+ void WriteInt32(int32_t value) { *reinterpret_cast<int32_t*>(p) = value; p += 4; }
+ void WriteInt64(int64_t value) { *reinterpret_cast<int64_t*>(p) = value; p += 8; }
+ void WriteDouble(double value) { *reinterpret_cast<double*>(p) = value; p += 8; }
+#else
+ void WriteInt32(int32_t value) { memcpy(p, &value, 4); p += 4; }
+ void WriteInt64(int64_t value) { memcpy(p, &value, 8); p += 8; }
+ void WriteDouble(double value) { memcpy(p, &value, 8); p += 8; }
+#endif
+ void WriteBool(const Handle<Value>& value) { WriteByte(value->BooleanValue() ? 1 : 0); }
+ void WriteInt32(const Handle<Value>& value) { WriteInt32(value->Int32Value()); }
+ void WriteInt32(const Handle<Object>& object, const Handle<String>& key) { WriteInt32(object->Get(key)); }
+ void WriteInt64(const Handle<Value>& value) { WriteInt64(value->IntegerValue()); }
+ void WriteDouble(const Handle<Value>& value) { WriteDouble(value->NumberValue()); }
+ void WriteDouble(const Handle<Object>& object, const Handle<String>& key) { WriteDouble(object->Get(key)); }
+ void WriteUInt32String(uint32_t name) { p += sprintf(p, "%u", name) + 1; }
+ void WriteLengthPrefixedString(const Local<String>& value) { WriteInt32(value->Utf8Length()+1); WriteString(value); }
+ void WriteObjectId(const Handle<Object>& object, const Handle<String>& key);
+ void WriteString(const Local<String>& value) { p += value->WriteUtf8(p); } // This returns the number of bytes inclusive of the NULL terminator.
+ void WriteData(const char* data, size_t length) { memcpy(p, data, length); p += length; }
+
+ void* BeginWriteType() { void* returnValue = p; p++; return returnValue; }
+ void CommitType(void* beginPoint, BsonType value) { *reinterpret_cast<unsigned char*>(beginPoint) = value; }
+ void* BeginWriteSize() { void* returnValue = p; p += 4; return returnValue; }
+
+#if USE_MISALIGNED_MEMORY_ACCESS
+ void CommitSize(void* beginPoint) { *reinterpret_cast<int32_t*>(beginPoint) = (int32_t) (p - (char*) beginPoint); }
+#else
+ void CommitSize(void* beginPoint) { int32_t value = (int32_t) (p - (char*) beginPoint); memcpy(beginPoint, &value, 4); }
+#endif
+
+ size_t GetSerializeSize() const { return p - destinationBuffer; }
+
+ void CheckKey(const Local<String>& keyName);
+
+protected:
+ char *const destinationBuffer; // base, never changes
+ char* p; // cursor into buffer
+};
+
+template<typename T> class BSONSerializer : public T
+{
+private:
+ typedef T Inherited;
+
+public:
+ BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions) : Inherited(), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
+ BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, char* parentParam) : Inherited(parentParam), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
+
+ void SerializeDocument(const Handle<Value>& value);
+ void SerializeArray(const Handle<Value>& value);
+ void SerializeValue(void* typeLocation, const Handle<Value>& value);
+
+private:
+ bool checkKeys;
+ bool serializeFunctions;
+ BSON* bson;
+};
+
+//===========================================================================
+
+class BSONDeserializer
+{
+public:
+ BSONDeserializer(BSON* aBson, char* data, size_t length);
+ BSONDeserializer(BSONDeserializer& parentSerializer, size_t length);
+
+ Handle<Value> DeserializeDocument();
+
+ bool HasMoreData() const { return p < pEnd; }
+ Local<String> ReadCString();
+ uint32_t ReadIntegerString();
+ int32_t ReadRegexOptions();
+ Local<String> ReadString();
+ Local<String> ReadObjectId();
+
+ unsigned char ReadByte() { return *reinterpret_cast<unsigned char*>(p++); }
+#if USE_MISALIGNED_MEMORY_ACCESS
+ int32_t ReadInt32() { int32_t returnValue = *reinterpret_cast<int32_t*>(p); p += 4; return returnValue; }
+ uint32_t ReadUInt32() { uint32_t returnValue = *reinterpret_cast<uint32_t*>(p); p += 4; return returnValue; }
+ int64_t ReadInt64() { int64_t returnValue = *reinterpret_cast<int64_t*>(p); p += 8; return returnValue; }
+ double ReadDouble() { double returnValue = *reinterpret_cast<double*>(p); p += 8; return returnValue; }
+#else
+ int32_t ReadInt32() { int32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; }
+ uint32_t ReadUInt32() { uint32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; }
+ int64_t ReadInt64() { int64_t returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; }
+ double ReadDouble() { double returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; }
+#endif
+
+ size_t GetSerializeSize() const { return p - pStart; }
+
+private:
+ Handle<Value> DeserializeArray();
+ Handle<Value> DeserializeValue(BsonType type);
+ Handle<Value> DeserializeDocumentInternal();
+ Handle<Value> DeserializeArrayInternal();
+
+ BSON* bson;
+ char* const pStart;
+ char* p;
+ char* const pEnd;
+};
+
+//===========================================================================
+
+#endif // BSON_H_
+
+//===========================================================================
diff --git a/node_modules/webworker-threads/src/createPool.js b/node_modules/webworker-threads/src/createPool.js new file mode 100644 index 0000000..08dc9ca --- /dev/null +++ b/node_modules/webworker-threads/src/createPool.js @@ -0,0 +1,169 @@ +function createPool(n){ + var T, pool, idleThreads, q, poolObject, e, RUN, EMIT; + T = this; + n = Math.floor(n); + if (!(n > 0)) { + throw '.createPool( num ): number of threads must be a Number > 0'; + } + pool = []; + idleThreads = []; + q = { + first: null, + last: null, + length: 0 + }; + poolObject = { + on: onEvent, + load: poolLoad, + destroy: destroy, + pendingJobs: getPendingJobs, + idleThreads: getIdleThreads, + totalThreads: getNumThreads, + any: { + eval: evalAny, + emit: emitAny + }, + all: { + eval: evalAll, + emit: emitAll + } + }; + try { + while (n--) { + pool[n] = idleThreads[n] = T.create(); + } + } catch (e$) { + e = e$; + destroy('rudely'); + throw e; + } + return poolObject; + RUN = 1; + EMIT = 2; + function poolLoad(path, cb){ + var i; + i = pool.length; + while (i--) { + pool[i].load(path, cb); + } + } + function nextJob(t){ + var job; + job = qPull(); + if (job) { + if (job.type === RUN) { + t.eval(job.srcTextOrEventType, function(e, d){ + var f; + nextJob(t); + f = job.cbOrData; + if (f) { + return job.cbOrData.call(t, e, d); + } + }); + } else { + if (job.type === EMIT) { + t.emit(job.srcTextOrEventType, job.cbOrData); + nextJob(t); + } + } + } else { + idleThreads.push(t); + } + } + function qPush(srcTextOrEventType, cbOrData, type){ + var job; + job = { + srcTextOrEventType: srcTextOrEventType, + cbOrData: cbOrData, + type: type, + next: null + }; + if (q.last) { + q.last = q.last.next = job; + } else { + q.first = q.last = job; + } + q.length++; + } + function qPull(){ + var job; + job = q.first; + if (job) { + if (q.last === job) { + q.first = q.last = null; + } else { + q.first = job.next; + } + q.length--; + } + return job; + } + function evalAny(src, cb){ + qPush(src, cb, RUN); + if (idleThreads.length) { + nextJob(idleThreads.pop()); + } + return poolObject; + } + function evalAll(src, cb){ + pool.forEach(function(v, i, o){ + return v.eval(src, cb); + }); + return poolObject; + } + function emitAny(event, data){ + qPush(event, data, EMIT); + if (idleThreads.length) { + nextJob(idleThreads.pop()); + } + return poolObject; + } + function emitAll(event, data){ + pool.forEach(function(v, i, o){ + return v.emit(event, data); + }); + return poolObject; + } + function onEvent(event, cb){ + pool.forEach(function(v, i, o){ + return v.on(event, cb); + }); + return this; + } + function destroy(rudely){ + var err, beNice, beRude; + err = function(){ + throw 'This thread pool has been destroyed'; + }; + beNice = function(){ + if (q.length) { + return setTimeout(beNice, 666); + } else { + return beRude(); + } + }; + beRude = function(){ + q.length = 0; + q.first = null; + pool.forEach(function(v, i, o){ + return v.destroy(); + }); + return poolObject.eval = poolObject.totalThreads = poolObject.idleThreads = poolObject.pendingJobs = poolObject.destroy = err; + }; + if (rudely) { + beRude(); + } else { + beNice(); + } + } + function getNumThreads(){ + return pool.length; + } + function getIdleThreads(){ + return idleThreads.length; + } + function getPendingJobs(){ + return q.length; + } + return getPendingJobs; +} diff --git a/node_modules/webworker-threads/src/createPool.js.c b/node_modules/webworker-threads/src/createPool.js.c new file mode 100644 index 0000000..c0a4040 --- /dev/null +++ b/node_modules/webworker-threads/src/createPool.js.c @@ -0,0 +1 @@ +static const char* kCreatePool_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x72\x65\x61\x74\x65\x50\x6f\x6f\x6c\x28\x6e\x29\x7b\x76\x61\x72 \x54\x2c\x70\x6f\x6f\x6c\x2c\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2c\x71\x2c\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2c\x65\x2c\x52\x55\x4e\x2c\x45\x4d\x49\x54\x3b\x54\x3d\x74\x68\x69\x73\x3b\x6e\x3d\x4d\x61\x74\x68\x2e\x66\x6c\x6f\x6f\x72\x28\x6e\x29\x3b\x69\x66\x28\x21\x28\x6e\x3e\x30\x29\x29\x7b\x74\x68\x72\x6f\x77\x27\x2e\x63\x72\x65\x61\x74\x65\x50\x6f\x6f\x6c\x28 \x6e\x75\x6d \x29\x3a \x6e\x75\x6d\x62\x65\x72 \x6f\x66 \x74\x68\x72\x65\x61\x64\x73 \x6d\x75\x73\x74 \x62\x65 \x61 \x4e\x75\x6d\x62\x65\x72 \x3e \x30\x27\x3b\x7d\n\x70\x6f\x6f\x6c\x3d\x5b\x5d\x3b\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3d\x5b\x5d\x3b\x71\x3d\x7b\x66\x69\x72\x73\x74\x3a\x6e\x75\x6c\x6c\x2c\x6c\x61\x73\x74\x3a\x6e\x75\x6c\x6c\x2c\x6c\x65\x6e\x67\x74\x68\x3a\x30\x7d\x3b\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3d\x7b\x6f\x6e\x3a\x6f\x6e\x45\x76\x65\x6e\x74\x2c\x6c\x6f\x61\x64\x3a\x70\x6f\x6f\x6c\x4c\x6f\x61\x64\x2c\x64\x65\x73\x74\x72\x6f\x79\x3a\x64\x65\x73\x74\x72\x6f\x79\x2c\x70\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3a\x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x2c\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3a\x67\x65\x74\x49\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2c\x74\x6f\x74\x61\x6c\x54\x68\x72\x65\x61\x64\x73\x3a\x67\x65\x74\x4e\x75\x6d\x54\x68\x72\x65\x61\x64\x73\x2c\x61\x6e\x79\x3a\x7b\x65\x76\x61\x6c\x3a\x65\x76\x61\x6c\x41\x6e\x79\x2c\x65\x6d\x69\x74\x3a\x65\x6d\x69\x74\x41\x6e\x79\x7d\x2c\x61\x6c\x6c\x3a\x7b\x65\x76\x61\x6c\x3a\x65\x76\x61\x6c\x41\x6c\x6c\x2c\x65\x6d\x69\x74\x3a\x65\x6d\x69\x74\x41\x6c\x6c\x7d\x7d\x3b\x74\x72\x79\x7b\x77\x68\x69\x6c\x65\x28\x6e\x2d\x2d\x29\x7b\x70\x6f\x6f\x6c\x5b\x6e\x5d\x3d\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x5b\x6e\x5d\x3d\x54\x2e\x63\x72\x65\x61\x74\x65\x28\x29\x3b\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x64\x65\x73\x74\x72\x6f\x79\x28\x27\x72\x75\x64\x65\x6c\x79\x27\x29\x3b\x74\x68\x72\x6f\x77 \x65\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x52\x55\x4e\x3d\x31\x3b\x45\x4d\x49\x54\x3d\x32\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x70\x6f\x6f\x6c\x4c\x6f\x61\x64\x28\x70\x61\x74\x68\x2c\x63\x62\x29\x7b\x76\x61\x72 \x69\x3b\x69\x3d\x70\x6f\x6f\x6c\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x2d\x2d\x29\x7b\x70\x6f\x6f\x6c\x5b\x69\x5d\x2e\x6c\x6f\x61\x64\x28\x70\x61\x74\x68\x2c\x63\x62\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x71\x50\x75\x6c\x6c\x28\x29\x3b\x69\x66\x28\x6a\x6f\x62\x29\x7b\x69\x66\x28\x6a\x6f\x62\x2e\x74\x79\x70\x65\x3d\x3d\x3d\x52\x55\x4e\x29\x7b\x74\x2e\x65\x76\x61\x6c\x28\x6a\x6f\x62\x2e\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x64\x29\x7b\x76\x61\x72 \x66\x3b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x3b\x66\x3d\x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x3b\x69\x66\x28\x66\x29\x7b\x72\x65\x74\x75\x72\x6e \x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x2e\x63\x61\x6c\x6c\x28\x74\x2c\x65\x2c\x64\x29\x3b\x7d\x7d\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x69\x66\x28\x6a\x6f\x62\x2e\x74\x79\x70\x65\x3d\x3d\x3d\x45\x4d\x49\x54\x29\x7b\x74\x2e\x65\x6d\x69\x74\x28\x6a\x6f\x62\x2e\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x6a\x6f\x62\x2e\x63\x62\x4f\x72\x44\x61\x74\x61\x29\x3b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x74\x29\x3b\x7d\x7d\x7d\x65\x6c\x73\x65\x7b\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x75\x73\x68\x28\x74\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x71\x50\x75\x73\x68\x28\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x63\x62\x4f\x72\x44\x61\x74\x61\x2c\x74\x79\x70\x65\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x7b\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x3a\x73\x72\x63\x54\x65\x78\x74\x4f\x72\x45\x76\x65\x6e\x74\x54\x79\x70\x65\x2c\x63\x62\x4f\x72\x44\x61\x74\x61\x3a\x63\x62\x4f\x72\x44\x61\x74\x61\x2c\x74\x79\x70\x65\x3a\x74\x79\x70\x65\x2c\x6e\x65\x78\x74\x3a\x6e\x75\x6c\x6c\x7d\x3b\x69\x66\x28\x71\x2e\x6c\x61\x73\x74\x29\x7b\x71\x2e\x6c\x61\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x2e\x6e\x65\x78\x74\x3d\x6a\x6f\x62\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x3d\x6a\x6f\x62\x3b\x7d\n\x71\x2e\x6c\x65\x6e\x67\x74\x68\x2b\x2b\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x71\x50\x75\x6c\x6c\x28\x29\x7b\x76\x61\x72 \x6a\x6f\x62\x3b\x6a\x6f\x62\x3d\x71\x2e\x66\x69\x72\x73\x74\x3b\x69\x66\x28\x6a\x6f\x62\x29\x7b\x69\x66\x28\x71\x2e\x6c\x61\x73\x74\x3d\x3d\x3d\x6a\x6f\x62\x29\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x71\x2e\x6c\x61\x73\x74\x3d\x6e\x75\x6c\x6c\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x66\x69\x72\x73\x74\x3d\x6a\x6f\x62\x2e\x6e\x65\x78\x74\x3b\x7d\n\x71\x2e\x6c\x65\x6e\x67\x74\x68\x2d\x2d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x6a\x6f\x62\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x76\x61\x6c\x41\x6e\x79\x28\x73\x72\x63\x2c\x63\x62\x29\x7b\x71\x50\x75\x73\x68\x28\x73\x72\x63\x2c\x63\x62\x2c\x52\x55\x4e\x29\x3b\x69\x66\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x6f\x70\x28\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x76\x61\x6c\x41\x6c\x6c\x28\x73\x72\x63\x2c\x63\x62\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x65\x76\x61\x6c\x28\x73\x72\x63\x2c\x63\x62\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x6d\x69\x74\x41\x6e\x79\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x7b\x71\x50\x75\x73\x68\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x2c\x45\x4d\x49\x54\x29\x3b\x69\x66\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x6e\x65\x78\x74\x4a\x6f\x62\x28\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x70\x6f\x70\x28\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x65\x6d\x69\x74\x41\x6c\x6c\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x65\x6d\x69\x74\x28\x65\x76\x65\x6e\x74\x2c\x64\x61\x74\x61\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6f\x6e\x45\x76\x65\x6e\x74\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x64\x65\x73\x74\x72\x6f\x79\x28\x72\x75\x64\x65\x6c\x79\x29\x7b\x76\x61\x72 \x65\x72\x72\x2c\x62\x65\x4e\x69\x63\x65\x2c\x62\x65\x52\x75\x64\x65\x3b\x65\x72\x72\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x74\x68\x72\x6f\x77\x27\x54\x68\x69\x73 \x74\x68\x72\x65\x61\x64 \x70\x6f\x6f\x6c \x68\x61\x73 \x62\x65\x65\x6e \x64\x65\x73\x74\x72\x6f\x79\x65\x64\x27\x3b\x7d\x3b\x62\x65\x4e\x69\x63\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x69\x66\x28\x71\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x72\x65\x74\x75\x72\x6e \x73\x65\x74\x54\x69\x6d\x65\x6f\x75\x74\x28\x62\x65\x4e\x69\x63\x65\x2c\x36\x36\x36\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x72\x65\x74\x75\x72\x6e \x62\x65\x52\x75\x64\x65\x28\x29\x3b\x7d\x7d\x3b\x62\x65\x52\x75\x64\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3d\x30\x3b\x71\x2e\x66\x69\x72\x73\x74\x3d\x6e\x75\x6c\x6c\x3b\x70\x6f\x6f\x6c\x2e\x66\x6f\x72\x45\x61\x63\x68\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x76\x2c\x69\x2c\x6f\x29\x7b\x72\x65\x74\x75\x72\x6e \x76\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x29\x3b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x65\x76\x61\x6c\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x74\x6f\x74\x61\x6c\x54\x68\x72\x65\x61\x64\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x70\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3d\x70\x6f\x6f\x6c\x4f\x62\x6a\x65\x63\x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x3d\x65\x72\x72\x3b\x7d\x3b\x69\x66\x28\x72\x75\x64\x65\x6c\x79\x29\x7b\x62\x65\x52\x75\x64\x65\x28\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x62\x65\x4e\x69\x63\x65\x28\x29\x3b\x7d\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x4e\x75\x6d\x54\x68\x72\x65\x61\x64\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x70\x6f\x6f\x6c\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x49\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x69\x64\x6c\x65\x54\x68\x72\x65\x61\x64\x73\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x67\x65\x74\x50\x65\x6e\x64\x69\x6e\x67\x4a\x6f\x62\x73\x3b\x7d)"; diff --git a/node_modules/webworker-threads/src/createPool.ls b/node_modules/webworker-threads/src/createPool.ls new file mode 100644 index 0000000..36b7c47 --- /dev/null +++ b/node_modules/webworker-threads/src/createPool.ls @@ -0,0 +1,107 @@ +function create-pool (n) + T = this + n = Math.floor n + throw '.createPool( num ): number of threads must be a Number > 0' unless n > 0 + + pool = [] + idle-threads = [] + q = { first: null, last: null, length: 0 } + pool-object = { + on: on-event + load: pool-load + destroy: destroy + pending-jobs: get-pending-jobs + idle-threads: get-idle-threads + total-threads: get-num-threads + any: { eval: eval-any, emit: emit-any } + all: { eval: eval-all, emit: emit-all } + } + + try + while n-- => pool[n] = idle-threads[n] = T.create! + catch e + destroy \rudely + throw e + + return pool-object + + ### Helper Functions Start Here ### + + const RUN = 1 + const EMIT = 2 + + function pool-load (path, cb) + i = pool.length + while i-- + pool[i].load path, cb + return + + function next-job (t) + job = q-pull! + if job + if job.type is RUN + t.eval job.src-text-or-event-type, (e, d) -> + next-job t + f = job.cb-or-data + job.cb-or-data.call t, e, d if f + else + if job.type is EMIT + t.emit job.src-text-or-event-type, job.cb-or-data + next-job t + else + idle-threads.push t + return + + function q-push (src-text-or-event-type, cb-or-data, type) + job = { src-text-or-event-type, cb-or-data, type, next: null } + if q.last + q.last = q.last.next = job + else + q.first = q.last = job + q.length++ + return + + function q-pull + job = q.first + if job + if q.last is job then q.first = q.last = null else q.first = job.next + q.length-- + return job + + function eval-any (src, cb) + q-push src, cb, RUN + next-job idle-threads.pop! if idle-threads.length + return pool-object + + function eval-all (src, cb) + pool.for-each (v, i, o) -> v.eval src, cb + return pool-object + + function emit-any (event, data) + q-push event, data, EMIT + next-job idle-threads.pop! if idle-threads.length + return pool-object + + function emit-all (event, data) + pool.for-each (v, i, o) -> v.emit event, data + return pool-object + + function on-event (event, cb) + pool.for-each (v, i, o) -> v.on event, cb + return this + + function destroy (rudely) + err = -> throw 'This thread pool has been destroyed' + be-nice = -> if q.length then setTimeout be-nice, 666 else be-rude! + be-rude = -> + q.length = 0 + q.first = null + pool.for-each (v, i, o) -> v.destroy! + pool-object.eval = pool-object.total-threads = pool-object.idle-threads = + pool-object.pendingJobs = pool-object.destroy = err + if rudely then be-rude! else be-nice! + return + + function get-num-threads => pool.length + function get-idle-threads => idle-threads.length + function get-pending-jobs => q.length diff --git a/node_modules/webworker-threads/src/events.js b/node_modules/webworker-threads/src/events.js new file mode 100644 index 0000000..b38a30e --- /dev/null +++ b/node_modules/webworker-threads/src/events.js @@ -0,0 +1,53 @@ +function DispatchEvents(thread){ + thread = (this.on = function(e, f, q){ + if (q = thread._on[e]) { + q.push(f); + } else { + thread._on[e] = [f]; + } + return thread; + }, this.once = function(e, f, q){ + !(q = thread._on[e]) && (q = thread._on[e] = []); + if (q.once) { + q.once.push(f); + } else { + q.once = [f]; + } + return thread; + }, this.removeAllListeners = function(e){ + if (arguments_.length) { + delete thread._on[e]; + } else { + thread._on = {}; + } + return thread; + }, this.dispatchEvents = function(event, args, q, i, len){ + var e, results$ = []; + if (q = thread._on[event]) { + try { + i = 0; + len = q.length; + while (i < len) { + q[i++].apply(thread, args); + } + if (q = q.once) { + q.once = undefined; + i = 0; + len = q.length; + while (i < len) { + results$.push(q[i++].apply(thread, args)); + } + return results$; + } + } catch (e$) { + e = e$; + return __postError({ + message: e, + filename: '', + lineno: 0 + }); + } + } + }, this._on = {}, this); + return this.dispatchEvents; +} diff --git a/node_modules/webworker-threads/src/events.js.c b/node_modules/webworker-threads/src/events.js.c new file mode 100644 index 0000000..a21da23 --- /dev/null +++ b/node_modules/webworker-threads/src/events.js.c @@ -0,0 +1 @@ +static const char* kEvents_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x44\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x28\x74\x68\x72\x65\x61\x64\x29\x7b\x74\x68\x72\x65\x61\x64\x3d\x28\x74\x68\x69\x73\x2e\x6f\x6e\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x66\x2c\x71\x29\x7b\x69\x66\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x29\x7b\x71\x2e\x70\x75\x73\x68\x28\x66\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3d\x5b\x66\x5d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x6f\x6e\x63\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x2c\x66\x2c\x71\x29\x7b\x21\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x29\x26\x26\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3d\x5b\x5d\x29\x3b\x69\x66\x28\x71\x2e\x6f\x6e\x63\x65\x29\x7b\x71\x2e\x6f\x6e\x63\x65\x2e\x70\x75\x73\x68\x28\x66\x29\x3b\x7d\x65\x6c\x73\x65\x7b\x71\x2e\x6f\x6e\x63\x65\x3d\x5b\x66\x5d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x72\x65\x6d\x6f\x76\x65\x41\x6c\x6c\x4c\x69\x73\x74\x65\x6e\x65\x72\x73\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x29\x7b\x69\x66\x28\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x5f\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x64\x65\x6c\x65\x74\x65 \x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x5d\x3b\x7d\x65\x6c\x73\x65\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x3d\x7b\x7d\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x74\x68\x72\x65\x61\x64\x3b\x7d\x2c\x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x61\x72\x67\x73\x2c\x71\x2c\x69\x2c\x6c\x65\x6e\x29\x7b\x76\x61\x72 \x65\x2c\x72\x65\x73\x75\x6c\x74\x73\x24\x3d\x5b\x5d\x3b\x69\x66\x28\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6f\x6e\x5b\x65\x76\x65\x6e\x74\x5d\x29\x7b\x74\x72\x79\x7b\x69\x3d\x30\x3b\x6c\x65\x6e\x3d\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x3c\x6c\x65\x6e\x29\x7b\x71\x5b\x69\x2b\x2b\x5d\x2e\x61\x70\x70\x6c\x79\x28\x74\x68\x72\x65\x61\x64\x2c\x61\x72\x67\x73\x29\x3b\x7d\n\x69\x66\x28\x71\x3d\x71\x2e\x6f\x6e\x63\x65\x29\x7b\x71\x2e\x6f\x6e\x63\x65\x3d\x75\x6e\x64\x65\x66\x69\x6e\x65\x64\x3b\x69\x3d\x30\x3b\x6c\x65\x6e\x3d\x71\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x77\x68\x69\x6c\x65\x28\x69\x3c\x6c\x65\x6e\x29\x7b\x72\x65\x73\x75\x6c\x74\x73\x24\x2e\x70\x75\x73\x68\x28\x71\x5b\x69\x2b\x2b\x5d\x2e\x61\x70\x70\x6c\x79\x28\x74\x68\x72\x65\x61\x64\x2c\x61\x72\x67\x73\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x72\x65\x73\x75\x6c\x74\x73\x24\x3b\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x72\x65\x74\x75\x72\x6e \x5f\x5f\x70\x6f\x73\x74\x45\x72\x72\x6f\x72\x28\x7b\x6d\x65\x73\x73\x61\x67\x65\x3a\x65\x2c\x66\x69\x6c\x65\x6e\x61\x6d\x65\x3a\x27\x27\x2c\x6c\x69\x6e\x65\x6e\x6f\x3a\x30\x7d\x29\x3b\x7d\x7d\x7d\x2c\x74\x68\x69\x73\x2e\x5f\x6f\x6e\x3d\x7b\x7d\x2c\x74\x68\x69\x73\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x73\x3b\x7d)"; diff --git a/node_modules/webworker-threads/src/events.ls b/node_modules/webworker-threads/src/events.ls new file mode 100644 index 0000000..4e604b7 --- /dev/null +++ b/node_modules/webworker-threads/src/events.ls @@ -0,0 +1,29 @@ +function DispatchEvents (thread) + thread = this <<< { + on: (e, f, q) -> + if q = thread._on[e] then q.push f else thread._on[e] = [f] + return thread + once: (e, f, q) -> + not (q = thread._on[e]) and (q = thread._on[e] = []) + if q.once then q.once.push f else q.once = [f] + return thread + remove-all-listeners: (e) -> + if arguments_.length then delete! thread._on[e] else thread._on = {} + return thread + dispatch-events: (event, args, q, i, len) -> + if q = thread._on[event] => try + i = 0 + len = q.length + while i < len + q[i++].apply thread, args + if q = q.once + q.once = ``undefined`` + i = 0 + len = q.length + while i < len + q[i++].apply thread, args + catch + __postError { message: e, filename: '', lineno: 0 } + _on: {} + } + return @dispatch-events diff --git a/node_modules/webworker-threads/src/jslib.cc b/node_modules/webworker-threads/src/jslib.cc new file mode 100644 index 0000000..4476f22 --- /dev/null +++ b/node_modules/webworker-threads/src/jslib.cc @@ -0,0 +1,177 @@ +// Copyright(C) 2012 by RobertL +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include <errno.h> + +static const PropertyAttribute attribute_ro_dd = (PropertyAttribute)(ReadOnly | DontDelete); +static const PropertyAttribute attribute_ro_de_dd = (PropertyAttribute)(ReadOnly | DontEnum | DontDelete); +#define JSObjFn(obj, name, fnname) \ + obj->Set(String::New(name), FunctionTemplate::New(fnname)->GetFunction(), attribute_ro_dd); + +static void ReportException(TryCatch* try_catch) { + HandleScope scope; + + String::Utf8Value exception(try_catch->Exception()); + Handle<Message> message = try_catch->Message(); + + if (message.IsEmpty()) { + printf("%s\n", *exception); + + } else { + // Print (filename):(line number): (message). + String::Utf8Value filename(message->GetScriptResourceName()); + int linenum = message->GetLineNumber(); + printf("%s:%i: %s\n", *filename, linenum, *exception); + + String::Utf8Value sourceline(message->GetSourceLine()); + char *tmpbuf = *sourceline; + for (int i=0, n=sourceline.length(); i<n; ++i) { + if (tmpbuf[i] == '\t') { + putchar(' '); + } else { + putchar(tmpbuf[i]); + } + } + putchar('\n'); + + + int start = message->GetStartColumn(); + for (int i = 0; i < start; i++) { + putchar(' '); + } + int end = message->GetEndColumn(); + for (int i = start; i < end; i++) { + putchar('^'); + } + putchar('\n'); + + String::Utf8Value stack_trace(try_catch->StackTrace()); + if (stack_trace.length() > 0) { + printf("%s\n", *stack_trace); + } + } +} + +static Handle<Value> readFileSync_(const Arguments &args) { + HandleScope scope; + + FILE *f = fopen(*String::Utf8Value(Handle<String>::Cast(args[0])), "rb"); + if (f == NULL) { + char str[256]; + sprintf(str, "Error: readfile open failed. %d %s\n", errno, strerror(errno)); + return ThrowException(Exception::Error(String::New(str))); + } + fseek(f, 0, SEEK_END); + size_t s = ftell(f); + rewind(f); + + char *buf = (char*)malloc((s+1)*sizeof(char)); + size_t r = fread(buf, sizeof(char), s, f); + if (r < s) { + char str[256]; + sprintf(str, "Error: readfile read failed. %d %s\n", ferror(f), strerror(ferror(f))); + delete[] buf; + fclose(f); + ThrowException(Exception::Error(String::New(str))); + } + buf[s] = 0; + Handle<String> str = String::New(buf); + free(buf); + fclose(f); + + return scope.Close(str); +} + + + +// console section +static inline void console_common_1(const Handle<Value> &v, FILE* fd, const int deep) { + char indent[36] = {}; + int i, n; + int mark = 0; + for (i=0; i<deep; ++i) { + indent[mark++] = 0x20; + indent[mark++] = 0x20; + } + + Handle<Value> lv; + if (v->IsFunction()) { + fprintf(fd, "%s[Function]\n", indent); + } else if (v->IsObject()) { + Handle<Object> obj = Handle<Object>::Cast(v); + Handle<Array> ar = obj->GetPropertyNames(); + fprintf(fd, "%s{Object}\n", indent); + for (i=0, n=ar->Length(); i<n; ++i) { + lv = obj->Get(ar->Get(i)); + fprintf(fd, "%s%s: ", indent, *(String::Utf8Value(Handle<String>::Cast(ar->Get(i))))); + if (lv->IsFunction()) { + fprintf(fd, "%s[Function]\n", indent); + } else if (lv->IsObject() || lv->IsArray()) { + //fprintf(fd, "\n"); + console_common_1(lv, fd, deep+1); + } else { + fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(lv)))); + } + } + fprintf(fd, "%s{/Object}\n", indent); + + } else if (v->IsArray()) { + Handle<Array> obj = Handle<Array>::Cast(v); + fprintf(fd, "%s[Array]\n", indent); + for (i=0, n=obj->Length(); i<n; ++i) { + lv = obj->Get(i); + fprintf(fd, "%s%d: ", indent, i); + if (lv->IsFunction()) { + fprintf(fd, "%s[Function]\n", indent); + } else if (lv->IsObject() || lv->IsArray()) { + fprintf(fd, "\n"); + console_common_1(lv, fd, deep+1); + } else { + fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(lv)))); + } + } + fprintf(fd, "%s[/Array]\n", indent); + } else { + fprintf(fd, "%s%s\n", indent, *(String::Utf8Value(Handle<String>::Cast(v)))); + } +} + +static inline void console_common(const Arguments &args, FILE* fd) { + TryCatch trycatch; + + for (int i=0, n=args.Length(); i<n; ++i) { + console_common_1(args[i], stdout, 0); + } + + if (trycatch.HasCaught()) { + ReportException(&trycatch); + } +} + +static Handle<Value> console_log(const Arguments &args) { + HandleScope scope; + console_common(args, stdout); + return Undefined(); +} + +static Handle<Value> console_error(const Arguments &args) { + HandleScope scope; + console_common(args, stderr); + return Undefined(); +} diff --git a/node_modules/webworker-threads/src/load.js b/node_modules/webworker-threads/src/load.js new file mode 100644 index 0000000..ab705ed --- /dev/null +++ b/node_modules/webworker-threads/src/load.js @@ -0,0 +1,19 @@ +var onmessage, this$ = this; +function addEventListener(event, cb){ + return this.thread.on(event, cb); +} +function close(){ + return this.thread.emit('close'); +} +function importScripts(){ + var i$, len$, p, results$ = []; + for (i$ = 0, len$ = arguments.length; i$ < len$; ++i$) { + p = arguments[i$]; + results$.push(self.eval(native_fs_.readFileSync(p, 'utf8'))); + } + return results$; +} +onmessage = null; +thread.on('message', function(args){ + return typeof onmessage === 'function' ? onmessage(args) : void 8; +}); diff --git a/node_modules/webworker-threads/src/load.js.c b/node_modules/webworker-threads/src/load.js.c new file mode 100644 index 0000000..8424c21 --- /dev/null +++ b/node_modules/webworker-threads/src/load.js.c @@ -0,0 +1 @@ +static const char* kLoad_js= "\n\x76\x61\x72 \x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x2c\x74\x68\x69\x73\x24\x3d\x74\x68\x69\x73\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x61\x64\x64\x45\x76\x65\x6e\x74\x4c\x69\x73\x74\x65\x6e\x65\x72\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x6c\x6f\x73\x65\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x2e\x65\x6d\x69\x74\x28\x27\x63\x6c\x6f\x73\x65\x27\x29\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x69\x6d\x70\x6f\x72\x74\x53\x63\x72\x69\x70\x74\x73\x28\x29\x7b\x76\x61\x72 \x69\x24\x2c\x6c\x65\x6e\x24\x2c\x70\x2c\x72\x65\x73\x75\x6c\x74\x73\x24\x3d\x5b\x5d\x3b\x66\x6f\x72\x28\x69\x24\x3d\x30\x2c\x6c\x65\x6e\x24\x3d\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x69\x24\x3c\x6c\x65\x6e\x24\x3b\x2b\x2b\x69\x24\x29\x7b\x70\x3d\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x5b\x69\x24\x5d\x3b\x72\x65\x73\x75\x6c\x74\x73\x24\x2e\x70\x75\x73\x68\x28\x73\x65\x6c\x66\x2e\x65\x76\x61\x6c\x28\x6e\x61\x74\x69\x76\x65\x5f\x66\x73\x5f\x2e\x72\x65\x61\x64\x46\x69\x6c\x65\x53\x79\x6e\x63\x28\x70\x2c\x27\x75\x74\x66\x38\x27\x29\x29\x29\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x72\x65\x73\x75\x6c\x74\x73\x24\x3b\x7d\n\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x6e\x75\x6c\x6c\x3b\x74\x68\x72\x65\x61\x64\x2e\x6f\x6e\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x28\x61\x72\x67\x73\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b"; diff --git a/node_modules/webworker-threads/src/load.ls b/node_modules/webworker-threads/src/load.ls new file mode 100644 index 0000000..80650eb --- /dev/null +++ b/node_modules/webworker-threads/src/load.ls @@ -0,0 +1,9 @@ +function add-event-listener (event, cb) + @thread.on event, cb +function close () + @thread.emit \close +function importScripts () + for p in arguments + self.eval native_fs_.readFileSync(p, \utf8) +onmessage = null +thread.on \message (args) ~> onmessage? args diff --git a/node_modules/webworker-threads/src/queues_a_gogo.cc b/node_modules/webworker-threads/src/queues_a_gogo.cc new file mode 100644 index 0000000..d675bb1 --- /dev/null +++ b/node_modules/webworker-threads/src/queues_a_gogo.cc @@ -0,0 +1,160 @@ +//2011-11 Proyectos Equis Ka, s.l., jorge@jorgechamorro.com +//queues_a_gogo.cc + +#include <string.h> +#include <stdio.h> +#include <uv.h> +#include <stdlib.h> +#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) || defined(_AIX) +#include <unistd.h> +#endif + +enum types { + kItemTypeNONE, + kItemTypeNumber, + kItemTypePointer, + kItemTypeQUIT +}; + +struct typeQueueItem { + int itemType; + typeQueueItem* next; + union { + void* asPtr; + double asNumber; + }; +}; +typedef struct typeQueueItem typeQueueItem; + +typedef struct { + typeQueueItem* first; + typeQueueItem* last; + uv_mutex_t queueLock; + long int id; + volatile long int length; +} typeQueue; + +static typeQueue* queuesPool= NULL; +static typeQueue* freeItemsQueue= NULL; + + + + +static void queue_push (typeQueueItem* qitem, typeQueue* queue) { + qitem->next= NULL; + + uv_mutex_lock(&queue->queueLock); + if (queue->last) { + queue->last->next= qitem; + } + else { + queue->first= qitem; + } + queue->last= qitem; + queue->length++; + uv_mutex_unlock(&queue->queueLock); +} + + + + +static typeQueueItem* queue_pull (typeQueue* queue) { + typeQueueItem* qitem; + + uv_mutex_lock(&queue->queueLock); + if ((qitem= queue->first)) { + if (queue->last == qitem) { + queue->first= queue->last= NULL; + } + else { + queue->first= qitem->next; + } + queue->length--; + qitem->next= NULL; + } + uv_mutex_unlock(&queue->queueLock); + + return qitem; +} + + + + +static typeQueueItem* nuItem (int itemType, void* item) { + + typeQueueItem* qitem= queue_pull(freeItemsQueue); + if (!qitem) { + qitem= (typeQueueItem*) calloc(1, sizeof(typeQueueItem)); + } + + qitem->next= NULL; + qitem->itemType= itemType; + if (itemType == kItemTypeNumber) { + qitem->asNumber= *((double*) item); + } + else if (itemType == kItemTypePointer) { + qitem->asPtr= item; + } + + return qitem; +} + + + + +static void destroyItem (typeQueueItem* qitem) { + + if (freeItemsQueue) { + queue_push(qitem, freeItemsQueue); + } + else { + free(qitem); + } +} + + + + +static typeQueue* nuQueue (long int id) { + + typeQueue* queue= NULL; + typeQueueItem* qitem= NULL; + if (queuesPool && queuesPool->first) qitem= queue_pull(queuesPool); + if (qitem) { + queue= (typeQueue*) qitem->asPtr; + destroyItem(qitem); + } + else { + queue= (typeQueue*) calloc(1, sizeof(typeQueue)); + uv_mutex_init(&queue->queueLock); + } + + queue->id= id; + queue->length= 0; + queue->first= queue->last= NULL; + return queue; +} + + +/* + +static void destroyQueue (typeQueue* queue) { + if (queuesPool) { + queue_push(nuItem(kItemTypePointer, queue), queuesPool); + } + else { + free(queue); + } +} + +*/ + + +static void initQueues (void) { + freeItemsQueue= nuQueue(-2); //MUST be created before queuesPool + //queuesPool= nuQueue(-1); +} + + + + diff --git a/node_modules/webworker-threads/src/thread_nextTick.js b/node_modules/webworker-threads/src/thread_nextTick.js new file mode 100644 index 0000000..e8cf3c0 --- /dev/null +++ b/node_modules/webworker-threads/src/thread_nextTick.js @@ -0,0 +1,29 @@ +function ThreadNextTick(){ + function nextTick(cb){ + thread._ntq.push(cb); + return this; + } + function dispatchNextTicks(l, p, err, _ntq){ + var e; + if (l = (_ntq = thread._ntq).length) { + p = err = 0; + try { + for (;;) { + _ntq[p](); + if (!(++p < l)) { + break; + } + } + } catch (e$) { + e = e$; + thread._ntq = _ntq.slice(++p); + throw e; + } + return (thread._ntq = _ntq.slice(p)).length; + } + return 0; + } + thread._ntq = []; + thread.nextTick = nextTick; + return dispatchNextTicks; +} diff --git a/node_modules/webworker-threads/src/thread_nextTick.js.c b/node_modules/webworker-threads/src/thread_nextTick.js.c new file mode 100644 index 0000000..c84dfd9 --- /dev/null +++ b/node_modules/webworker-threads/src/thread_nextTick.js.c @@ -0,0 +1 @@ +static const char* kThread_nextTick_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x54\x68\x72\x65\x61\x64\x4e\x65\x78\x74\x54\x69\x63\x6b\x28\x29\x7b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x6e\x65\x78\x74\x54\x69\x63\x6b\x28\x63\x62\x29\x7b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x2e\x70\x75\x73\x68\x28\x63\x62\x29\x3b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x3b\x7d\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x64\x69\x73\x70\x61\x74\x63\x68\x4e\x65\x78\x74\x54\x69\x63\x6b\x73\x28\x6c\x2c\x70\x2c\x65\x72\x72\x2c\x5f\x6e\x74\x71\x29\x7b\x76\x61\x72 \x65\x3b\x69\x66\x28\x6c\x3d\x28\x5f\x6e\x74\x71\x3d\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x29\x2e\x6c\x65\x6e\x67\x74\x68\x29\x7b\x70\x3d\x65\x72\x72\x3d\x30\x3b\x74\x72\x79\x7b\x66\x6f\x72\x28\x3b\x3b\x29\x7b\x5f\x6e\x74\x71\x5b\x70\x5d\x28\x29\x3b\x69\x66\x28\x21\x28\x2b\x2b\x70\x3c\x6c\x29\x29\x7b\x62\x72\x65\x61\x6b\x3b\x7d\x7d\x7d\x63\x61\x74\x63\x68\x28\x65\x24\x29\x7b\x65\x3d\x65\x24\x3b\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5f\x6e\x74\x71\x2e\x73\x6c\x69\x63\x65\x28\x2b\x2b\x70\x29\x3b\x74\x68\x72\x6f\x77 \x65\x3b\x7d\n\x72\x65\x74\x75\x72\x6e\x28\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5f\x6e\x74\x71\x2e\x73\x6c\x69\x63\x65\x28\x70\x29\x29\x2e\x6c\x65\x6e\x67\x74\x68\x3b\x7d\n\x72\x65\x74\x75\x72\x6e \x30\x3b\x7d\n\x74\x68\x72\x65\x61\x64\x2e\x5f\x6e\x74\x71\x3d\x5b\x5d\x3b\x74\x68\x72\x65\x61\x64\x2e\x6e\x65\x78\x74\x54\x69\x63\x6b\x3d\x6e\x65\x78\x74\x54\x69\x63\x6b\x3b\x72\x65\x74\x75\x72\x6e \x64\x69\x73\x70\x61\x74\x63\x68\x4e\x65\x78\x74\x54\x69\x63\x6b\x73\x3b\x7d)()"; diff --git a/node_modules/webworker-threads/src/thread_nextTick.ls b/node_modules/webworker-threads/src/thread_nextTick.ls new file mode 100644 index 0000000..7ac3fe2 --- /dev/null +++ b/node_modules/webworker-threads/src/thread_nextTick.ls @@ -0,0 +1,19 @@ +function ThreadNextTick + function next-tick (cb) + thread._ntq.push cb + return this + function dispatch-next-ticks (l, p, err, _ntq) + if l = (_ntq = thread._ntq).length + p = err = 0 + try + while true + _ntq[p]! + break unless ++p < l + catch e + thread._ntq = _ntq.slice ++p + throw e + return (thread._ntq = _ntq.slice p).length + return 0 + thread._ntq = [] + thread.next-tick = next-tick + return dispatch-next-ticks diff --git a/node_modules/webworker-threads/src/worker.js b/node_modules/webworker-threads/src/worker.js new file mode 100644 index 0000000..004bb54 --- /dev/null +++ b/node_modules/webworker-threads/src/worker.js @@ -0,0 +1,46 @@ +function Worker(){ + var Threads; + Threads = this; + return (function(){ + var prototype = constructor.prototype; + function constructor(code){ + var t, this$ = this; + this.thread = t = Threads.create(); + t.on('message', function(args){ + return typeof this$.onmessage === 'function' ? this$.onmessage({ + data: args + }) : void 8; + }); + t.on('error', function(args){ + return typeof this$.onerror === 'function' ? this$.onerror(args) : void 8; + }); + t.on('close', function(){ + return t.destroy(); + }); + this.terminate = function(){ + return t.destroy(); + }; + this.addEventListener = function(event, cb){ + if (event === 'message') { + return this$.onmessage = cb; + } else { + return t.on(event, cb); + } + }; + this.dispatchEvent = function(event){ + return t.emitSerialized(event.type, event); + }; + this.postMessage = function(data){ + return t.emitSerialized('message', { + data: data + }); + }; + if (typeof code === 'function') { + t.eval("(" + code + ")()"); + } else if (code != null) { + t.load(code); + } + } + return constructor; + }()); +} diff --git a/node_modules/webworker-threads/src/worker.js.c b/node_modules/webworker-threads/src/worker.js.c new file mode 100644 index 0000000..1d97532 --- /dev/null +++ b/node_modules/webworker-threads/src/worker.js.c @@ -0,0 +1 @@ +static const char* kWorker_js= "(\n\x66\x75\x6e\x63\x74\x69\x6f\x6e \x57\x6f\x72\x6b\x65\x72\x28\x29\x7b\x76\x61\x72 \x54\x68\x72\x65\x61\x64\x73\x3b\x54\x68\x72\x65\x61\x64\x73\x3d\x74\x68\x69\x73\x3b\x72\x65\x74\x75\x72\x6e\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x76\x61\x72 \x70\x72\x6f\x74\x6f\x74\x79\x70\x65\x3d\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x2e\x70\x72\x6f\x74\x6f\x74\x79\x70\x65\x3b\x66\x75\x6e\x63\x74\x69\x6f\x6e \x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x28\x63\x6f\x64\x65\x29\x7b\x76\x61\x72 \x74\x2c\x74\x68\x69\x73\x24\x3d\x74\x68\x69\x73\x3b\x74\x68\x69\x73\x2e\x74\x68\x72\x65\x61\x64\x3d\x74\x3d\x54\x68\x72\x65\x61\x64\x73\x2e\x63\x72\x65\x61\x74\x65\x28\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x28\x7b\x64\x61\x74\x61\x3a\x61\x72\x67\x73\x7d\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x65\x72\x72\x6f\x72\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x61\x72\x67\x73\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x79\x70\x65\x6f\x66 \x74\x68\x69\x73\x24\x2e\x6f\x6e\x65\x72\x72\x6f\x72\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x3f\x74\x68\x69\x73\x24\x2e\x6f\x6e\x65\x72\x72\x6f\x72\x28\x61\x72\x67\x73\x29\x3a\x76\x6f\x69\x64 \x38\x3b\x7d\x29\x3b\x74\x2e\x6f\x6e\x28\x27\x63\x6c\x6f\x73\x65\x27\x2c\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x29\x3b\x74\x68\x69\x73\x2e\x74\x65\x72\x6d\x69\x6e\x61\x74\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x64\x65\x73\x74\x72\x6f\x79\x28\x29\x3b\x7d\x3b\x74\x68\x69\x73\x2e\x61\x64\x64\x45\x76\x65\x6e\x74\x4c\x69\x73\x74\x65\x6e\x65\x72\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x7b\x69\x66\x28\x65\x76\x65\x6e\x74\x3d\x3d\x3d\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x68\x69\x73\x24\x2e\x6f\x6e\x6d\x65\x73\x73\x61\x67\x65\x3d\x63\x62\x3b\x7d\x65\x6c\x73\x65\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x6f\x6e\x28\x65\x76\x65\x6e\x74\x2c\x63\x62\x29\x3b\x7d\x7d\x3b\x74\x68\x69\x73\x2e\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6e\x74\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x65\x76\x65\x6e\x74\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x65\x6d\x69\x74\x53\x65\x72\x69\x61\x6c\x69\x7a\x65\x64\x28\x65\x76\x65\x6e\x74\x2e\x74\x79\x70\x65\x2c\x65\x76\x65\x6e\x74\x29\x3b\x7d\x3b\x74\x68\x69\x73\x2e\x70\x6f\x73\x74\x4d\x65\x73\x73\x61\x67\x65\x3d\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x64\x61\x74\x61\x29\x7b\x72\x65\x74\x75\x72\x6e \x74\x2e\x65\x6d\x69\x74\x53\x65\x72\x69\x61\x6c\x69\x7a\x65\x64\x28\x27\x6d\x65\x73\x73\x61\x67\x65\x27\x2c\x7b\x64\x61\x74\x61\x3a\x64\x61\x74\x61\x7d\x29\x3b\x7d\x3b\x69\x66\x28\x74\x79\x70\x65\x6f\x66 \x63\x6f\x64\x65\x3d\x3d\x3d\x27\x66\x75\x6e\x63\x74\x69\x6f\x6e\x27\x29\x7b\x74\x2e\x65\x76\x61\x6c\x28\x22\x28\x22\x2b\x63\x6f\x64\x65\x2b\x22\x29\x28\x29\x22\x29\x3b\x7d\x65\x6c\x73\x65 \x69\x66\x28\x63\x6f\x64\x65\x21\x3d\x6e\x75\x6c\x6c\x29\x7b\x74\x2e\x6c\x6f\x61\x64\x28\x63\x6f\x64\x65\x29\x3b\x7d\x7d\n\x72\x65\x74\x75\x72\x6e \x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x3b\x7d\x28\x29\x29\x3b\x7d)"; diff --git a/node_modules/webworker-threads/src/worker.ls b/node_modules/webworker-threads/src/worker.ls new file mode 100644 index 0000000..4570bbb --- /dev/null +++ b/node_modules/webworker-threads/src/worker.ls @@ -0,0 +1,18 @@ +function Worker () => Threads = this; class + (code) -> + @thread = t = Threads.create! + t.on \message (args) ~> @onmessage? data: args + t.on \error (args) ~> @onerror? args + t.on \close -> t.destroy! + @terminate = -> t.destroy! + @add-event-listener = (event, cb) ~> + if event is \message + @onmessage = cb + else + t.on event, cb + @dispatch-event = (event) -> t.emitSerialized event.type, event + @post-message = (data) -> t.emitSerialized \message {data} + if typeof code is \function + t.eval "(#code)()" + else if code? + t.load code |
