/* * function preload(path: Path): String * NOTE: this blocks. */ static EjsVar *workerPreload(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *inside; EjsWorker *insideWorker; EjsVar *result; mprAssert(argc > 0 && ejsIsPath(argv[0])); mprAssert(!worker->inside); if (worker->state > EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has already started"); return 0; } insideWorker = worker->pair; inside = insideWorker->ejs; loadFile(worker->pair, ((EjsPath*) argv[0])->path); if (inside->exception) { handleError(ejs, worker, inside->exception); return 0; } result = ejsSerialize(ejs, inside->result, -1, 0, 0); if (result == 0) { return ejs->nullValue; } return ejsDeserialize(ejs, (EjsString*) result); }
/* * Post a message to this worker. Note: the worker is the destination worker which may be the parent. * * function postMessage(data: Object, ports: Array = null): Void */ static EjsVar *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { EjsVar *data; EjsWorker *target; MprDispatcher *dispatcher; Message *msg; if (worker->state >= EJS_WORKER_CLOSED) { ejsThrowStateError(ejs, "Worker has completed"); return 0; } /* * Create the event with serialized data in the originating interpreter. It owns the data. */ if ((data = ejsSerialize(ejs, argv[0], -1, 0, 0)) == 0) { ejsThrowArgError(ejs, "Can't serialize message data"); return 0; } if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = mprStrdup(target->ejs, ejsGetString(data)); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_ejs_sys_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); return 0; }
/* Interpret from the console or from a literal command */ static int interpretCommands(EcCompiler *cp, cchar *cmd) { Ejs *ejs; EjsString *result; char *tmpArgv[1]; int err; ejs = cp->ejs; cp->interactive = 1; if (ecOpenConsoleStream(cp, (cmd) ? commandGets: consoleGets, cmd) < 0) { mprError("Cannot open input"); return EJS_ERR; } tmpArgv[0] = EC_INPUT_STREAM; while (!cp->stream->eof && !mprIsStopping()) { err = 0; cp->uid = 0; ejs->result = ESV(undefined); if (ecCompile(cp, 1, tmpArgv) < 0) { mprRawLog(0, "%s", cp->errorMsg); ejs->result = ESV(undefined); err++; } if (!err && cp->errorCount == 0) { if (ejsRunProgram(ejs, NULL, NULL) < 0) { ejsReportError(ejs, "Error in script"); } } if (!ejs->exception && ejs->result != ESV(undefined)) { if (ejsIs(ejs, ejs->result, Date) /* MOB || ejsIsType(ejs, ejs->result) */) { if ((result = (EjsString*) ejsToString(ejs, ejs->result)) != 0) { mprPrintf("%@\n", result); } } else if (ejs->result != ESV(null)) { if ((result = (EjsString*) ejsSerialize(ejs, ejs->result, EJS_JSON_SHOW_PRETTY)) != 0) { mprPrintf("%@\n", result); } } } ecResetInput(cp); cp->errorCount = 0; cp->fatalError = 0; } ecCloseStream(cp); return 0; }
/* WARNING: the inside interpreter owns the exception object. Must fully extract all fields */ static void handleError(Ejs *ejs, EjsWorker *worker, EjsObj *exception, int throwOutside) { Ejs *inside; EjsObj *e; MprDispatcher *dispatcher; Message *msg; assert(!worker->inside); assert(exception); assert(ejs == worker->ejs); ejsBlockGC(ejs); if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return; } msg->worker = worker; msg->callback = "onerror"; msg->callbackSlot = ES_Worker_onerror; inside = worker->pair->ejs; inside->exception = 0; e = ejsDeserialize(ejs, ejsSerialize(inside, exception, 0)); inside->exception = exception; /* Inside interpreter owns the exception object, so must fully extract all exception. Allocate into the outside worker's interpreter. */ if (ejsIsError(inside, exception)) { msg->message = ejsGetPropertyByName(ejs, e, EN("message")); msg->stack = ejsGetPropertyByName(ejs, e, EN("stack")); } else { msg->message = e; msg->stack = 0; } if (throwOutside) { if (msg->stack) { ejsThrowStateError(ejs, "%@\n%@", ejsToString(ejs, msg->message), ejsToString(ejs, msg->stack)); } else { ejsThrowStateError(ejs, "%@", ejsToString(ejs, msg->message)); } } dispatcher = ejs->dispatcher; mprCreateEvent(dispatcher, "doMessage-error", 0, (MprEventProc) doMessage, msg, 0); }
/* * Start a worker thread. This is called by eval() and load(). Not by preload() or by Worker() * It always joins. */ static EjsVar *startWorker(Ejs *ejs, EjsWorker *worker, int timeout) { Ejs *inside; EjsVar *result; mprAssert(ejs); mprAssert(worker); mprAssert(worker->state == EJS_WORKER_BEGIN); if (worker->state > EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has already started"); return 0; } mprAssert(worker->pair->state == EJS_WORKER_BEGIN); addWorker(ejs, worker); worker->state = EJS_WORKER_STARTED; worker->obj.var.permanent = 1; if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) { ejsThrowStateError(ejs, "Can't start worker"); worker->obj.var.permanent = 0; return 0; } if (timeout == 0) { return ejs->undefinedValue; } if (timeout < 0) { timeout = MAXINT; } if (join(ejs, (EjsVar*) worker, timeout) < 0) { ejsThrowStateError(ejs, "Timeout (%d)", timeout); return ejs->undefinedValue; } mprAssert(worker->pair); mprAssert(worker->pair->ejs); inside = worker->pair->ejs; result = ejsSerialize(ejs, inside->result, -1, 0, 0); if (result == 0) { return ejs->nullValue; } return ejsDeserialize(ejs, (EjsString*) result); }