/* function passRequest(req: Request, worker: Worker): Void */ static EjsVoid *hs_passRequest(Ejs *ejs, EjsHttpServer *server, int argc, EjsAny **argv) { Ejs *nejs; EjsRequest *req, *nreq; EjsWorker *worker; HttpConn *conn; MprEvent *event; req = argv[0]; worker = argv[1]; nejs = worker->pair->ejs; conn = req->conn; conn->ejs = nejs; if ((nreq = ejsCloneRequest(nejs, req, 1)) == 0) { ejsThrowStateError(ejs, "Cannot clone request"); return 0; } httpSetConnContext(conn, nreq); if ((nreq->server = ejsCloneHttpServer(nejs, req->server, 1)) == 0) { ejsThrowStateError(ejs, "Cannot clone request"); return 0; } event = mprCreateEvent(conn->dispatcher, "RequestWorker", 0, receiveRequest, nreq, MPR_EVENT_DONT_QUEUE); httpUseWorker(conn, nejs->dispatcher, event); return 0; }
/* Read data bytes from a file function readBytes(count: Number = -1): ByteArray */ static EjsObj *readFileBytes(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *result; MprPath info; ssize count, totalRead; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } result = ejsCreateByteArray(ejs, count); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } totalRead = readData(ejs, fp, result, 0, count); if (totalRead < 0) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } else if (totalRead == 0) { return ESV(null); } ejsSetByteArrayPositions(ejs, result, 0, totalRead); return (EjsObj*) result; }
/* Read data bytes from a file. If offset is < 0, then append to the write position. function read(buffer: ByteArray, offset: Number = 0, count: Number = -1): Number */ static EjsNumber *readFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *buffer; MprPath info; ssize offset, count, totalRead; assert(1 <= argc && argc <= 3); buffer = (EjsByteArray*) argv[0]; offset = (argc >= 2) ? ejsGetInt(ejs, argv[1]): 0; count = (argc >= 3) ? ejsGetInt(ejs, argv[2]): -1; if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (offset >= buffer->size) { ejsThrowOutOfBoundsError(ejs, "Bad read offset value"); return 0; } if (offset < 0) { offset = buffer->writePosition; } else if (offset == 0) { ejsSetByteArrayPositions(ejs, buffer, 0, 0); } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } totalRead = readData(ejs, fp, buffer, offset, count); if (totalRead < 0) { return 0; } else if (totalRead == 0) { return ESV(zero); } ejsSetByteArrayPositions(ejs, buffer, -1, offset + totalRead); return ejsCreateNumber(ejs, (MprNumber) totalRead); }
/* Exit the application static function exit(status: Number, how: String = "default"): void MOB - status is not implemented */ static EjsObj *app_exit(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { cchar *how; int status, mode; if (ejs->dontExit) { ejsThrowStateError(ejs, "App.exit has been disabled"); return 0; } status = argc >= 1 ? ejsGetInt(ejs, argv[0]) : 0; how = ejsToMulti(ejs, argc >= 2 ? ejsToString(ejs, argv[1]): ESV(empty)); if (scmp(how, "default") == 0) { mode = MPR_EXIT_DEFAULT; } else if (scmp(how, "immediate") == 0) { mode = MPR_EXIT_IMMEDIATE; } else if (scmp(how, "graceful") == 0) { mode = MPR_EXIT_GRACEFUL; } else { mode = MPR_EXIT_NORMAL; } mprTerminate(mode, status); ejsAttention(ejs); return 0; }
/* * 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; }
/* * 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); }
/* function preeval(script: String): Object NOTE: this blocks. */ static EjsObj *workerPreeval(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { Ejs *inside; EjsWorker *insideWorker; EjsString *result; assert(!worker->inside); if (worker->state > EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has already started"); return 0; } insideWorker = worker->pair; assert(insideWorker->inside); inside = insideWorker->ejs; (inside->service->loadScriptLiteral)(inside, (EjsString*) argv[0], NULL); if (inside->exception) { handleError(ejs, worker, inside->exception, 1); return 0; } result = ejsToJSON(inside, inside->result, NULL); if (result == 0) { return ESV(null); } return ejsDeserialize(ejs, result); }
static int join(Ejs *ejs, EjsObj *workers, int timeout) { MprTicks mark; int result, remaining; mprTrace(5, "Worker.join: joining %d", ejs->joining); mark = mprGetTicks(); remaining = timeout; do { ejs->joining = !reapJoins(ejs, workers); if (!ejs->joining) { break; } if (mprShouldAbortRequests()) { ejsThrowStateError(ejs, "Program instructed to exit"); break; } mprWaitForEvent(ejs->dispatcher, remaining); remaining = (int) mprGetRemainingTicks(mark, timeout); } while (remaining > 0 && !ejs->exception); if (ejs->exception) { return 0; } result = (ejs->joining) ? MPR_ERR_TIMEOUT: 0; ejs->joining = 0; mprTrace(7, "Worker.join: result %d", result); return result; }
/* function preload(path: Path): Object NOTE: this blocks. */ static EjsObj *workerPreload(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { Ejs *inside; EjsWorker *insideWorker; EjsString *result; assert(argc > 0 && ejsIs(ejs, argv[0], Path)); assert(!worker->inside); if (worker->state > EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has already started"); return 0; } insideWorker = worker->pair; assert(insideWorker->inside); inside = insideWorker->ejs; loadFile(worker->pair, ((EjsPath*) argv[0])->value); if (inside->exception) { handleError(ejs, worker, inside->exception, 1); return 0; } result = ejsToJSON(inside, inside->result, NULL); if (result == 0) { return ESV(null); } return ejsDeserialize(ejs, 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 EjsObj *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { EjsString *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. */ ejsBlockGC(ejs); if ((data = ejsToJSON(ejs, argv[0], NULL)) == 0) { ejsThrowArgError(ejs, "Cannot serialize message data"); return 0; } if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = ejsToMulti(ejs, data); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, "postMessage", 0, doMessage, msg, 0); return 0; }
/* Get the current I/O position in the file. function get position(): Number */ static EjsObj *getFilePosition(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { if (fp->file == 0) { ejsThrowStateError(ejs, "File not opened"); return 0; } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) mprGetFilePosition(fp->file)); }
/* 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); }
/* Read data as a string function readString(count: Number = -1): String */ static EjsString *readFileString(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsString *result; MprPath info; ssize totalRead; int count; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } if ((result = ejsCreateBareString(ejs, count)) == NULL) { ejsThrowMemoryError(ejs); return 0; } totalRead = mprReadFile(fp->file, result->value, count); if (totalRead != count) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } return ejsInternString(result); }
/* Start a worker thread. This is called by eval() and load(). Not by preload() or by Worker(). It always joins. */ static EjsObj *startWorker(Ejs *ejs, EjsWorker *outsideWorker, int timeout) { EjsWorker *insideWorker; Ejs *inside; EjsString *result; assert(ejs); assert(outsideWorker); assert(!outsideWorker->inside); assert(outsideWorker->state == EJS_WORKER_BEGIN); assert(outsideWorker->pair); assert(outsideWorker->pair->ejs); mprTrace(5, "Worker.startWorker"); if (outsideWorker->state > EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has already started"); return 0; } insideWorker = outsideWorker->pair; assert(insideWorker->inside); assert(insideWorker->state == EJS_WORKER_BEGIN); inside = insideWorker->ejs; outsideWorker->state = EJS_WORKER_STARTED; if (mprCreateEvent(inside->dispatcher, "workerMain", 0, (MprEventProc) workerMain, insideWorker, 0) < 0) { ejsThrowStateError(ejs, "Cannot create worker event"); return 0; } if (timeout == 0) { return ESV(undefined); } if (timeout < 0) { timeout = MAXINT; } if (join(ejs, (EjsObj*) outsideWorker, timeout) < 0) { return ESV(undefined); } result = ejsToJSON(inside, inside->result, NULL); if (result == 0) { return ESV(null); } return ejsDeserialize(ejs, result); }
/* * 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); }
/* Write data to the file function write(data: Object): Number */ PUBLIC EjsObj *writeFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ap; EjsObj *vp; EjsString *str; cchar *buf; ssize len, written; int i; assert(argc == 1 && ejsIs(ejs, argv[0], Array)); args = (EjsArray*) argv[0]; if (!(fp->mode & EJS_FILE_WRITE)) { ejsThrowStateError(ejs, "File not opened for writing"); return 0; } written = 0; for (i = 0; i < args->length; i++) { vp = ejsGetProperty(ejs, (EjsObj*) args, i); assert(vp); switch (TYPE(vp)->sid) { case S_ByteArray: ap = (EjsByteArray*) vp; // TODO UNICODE ENCODING buf = (cchar*) &ap->value[ap->readPosition]; len = ap->writePosition - ap->readPosition; break; case S_String: // UNICODE #if UNICODE && FUTURE buf = awtom(((EjsString*) vp)->value, &len); #else buf = ((EjsString*) vp)->value; len = ((EjsString*) vp)->length; #endif break; default: str = ejsToString(ejs, vp); buf = awtom(((EjsString*) str)->value, &len); break; } if (mprWriteFile(fp->file, buf, len) != len) { ejsThrowIOError(ejs, "Cannot write to %s", fp->path); return 0; } written += len; /* Use GC to free buf as it may not be allocated */ } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) written); }
/* Seek to a new location in the file and set the File marker to a new read/write position. function set position(value: Number): void */ static EjsObj *setFilePosition(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { MprOff pos; assert(argc == 1 && ejsIs(ejs, argv[0], Number)); pos = ejsGetInt(ejs, argv[0]); if (fp->file == 0) { ejsThrowStateError(ejs, "File not opened"); return 0; } pos = ejsGetInt(ejs, argv[0]); if (mprSeekFile(fp->file, SEEK_SET, pos) != pos) { ejsThrowIOError(ejs, "Cannot seek to %Ld", pos); } return 0; }
/* function terminate(): Void */ static EjsObj *workerTerminate(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { if (worker->state == EJS_WORKER_BEGIN) { ejsThrowStateError(ejs, "Worker has not yet started"); return 0; } if (worker->state >= EJS_WORKER_COMPLETE) { return 0; } /* Switch to the inside worker if called from outside */ assert(worker->pair && worker->pair->ejs); ejs = (!worker->inside) ? worker->pair->ejs : ejs; ejs->exiting = 1; mprSignalDispatcher(ejs->dispatcher); return 0; }
/* Exit the application static function exit(status: Number, how: String = "immediate"): void TODO - status is not implemented */ static EjsObj *app_exit(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprTicks timeout; cchar *how; int status, mode; if (ejs->dontExit) { ejsThrowStateError(ejs, "App.exit has been disabled"); return 0; } status = argc >= 1 ? ejsGetInt(ejs, argv[0]) : 0; timeout = argc >= 2 ? ejsGetInt(ejs, argv[1]) : 0; how = ejsToMulti(ejs, argc >= 2 ? ejsToString(ejs, argv[1]): ESV(empty)); if (scmp(how, "normal") == 0) { mode = 0; } else if (scmp(how, "abort") == 0) { mode = MPR_EXIT_ABORT; } else if (scmp(how, "safe") == 0) { mode = MPR_EXIT_SAFE; } else if (scmp(how, "restart") == 0) { mode = MPR_EXIT_RESTART; #if DEPRECATED || 1 } else if (scmp(how, "immediate") == 0) { mode = 0; } else if (scmp(how, "graceful") == 0) { mode = 0; if (argc <= 2) { timeout = 30 * 3000; } } else if (scmp(how, "default") == 0) { mode = 0; #endif } else { mode = 0; } mprShutdown(mode, status, timeout); ejsAttention(ejs); return 0; }
static void receiveRequest(EjsRequest *req, MprEvent *event) { Ejs *ejs; EjsAny *argv[1]; EjsFunction *onrequest; HttpConn *conn; conn = req->conn; ejs = req->ejs; assert(ejs); onrequest = ejsGetProperty(ejs, req->server, ES_ejs_web_HttpServer_onrequest); if (!ejsIsFunction(ejs, onrequest)) { ejsThrowStateError(ejs, "HttpServer.onrequest is not a function"); return; } argv[0] = req; ejsRunFunction(ejs, onrequest, req->server, 1, argv); if (conn->state == HTTP_STATE_BEGIN) { conn->ejs = 0; httpUsePrimary(conn); } httpEnableConnEvents(conn); }
/* function [get|put|delete|post...](uri = null, ...data): Http */ static EjsHttp *startHttpRequest(Ejs *ejs, EjsHttp *hp, char *method, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *data; EjsNumber *written; EjsUri *uriObj; HttpConn *conn; ssize nbytes; conn = hp->conn; hp->responseCache = 0; hp->requestContentCount = 0; mprFlushBuf(hp->responseContent); if (argc >= 1 && !ejsIs(ejs, argv[0], Null)) { uriObj = (EjsUri*) argv[0]; hp->uri = httpUriToString(uriObj->uri, HTTP_COMPLETE_URI); } if (argc == 2 && ejsIs(ejs, argv[1], Array)) { args = (EjsArray*) argv[1]; if (args->length > 0) { data = ejsCreateByteArray(ejs, -1); written = ejsWriteToByteArray(ejs, data, 1, &argv[1]); mprPutBlockToBuf(hp->requestContent, (char*) data->value, (int) written->value); mprAddNullToBuf(hp->requestContent); assert(written > 0); } } if (hp->uri == 0) { ejsThrowArgError(ejs, "URL is not defined"); return 0; } if (method && strcmp(hp->method, method) != 0) { hp->method = sclone(method); } if (hp->method == 0) { ejsThrowArgError(ejs, "HTTP Method is not defined"); return 0; } if (hp->certFile) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprSetSslCertFile(hp->ssl, hp->certFile); if (!hp->keyFile) { ejsThrowStateError(ejs, "Must define a Http.key to use with a certificate"); } mprSetSslKeyFile(hp->ssl, hp->keyFile); } if (hp->caFile) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprSetSslCaFile(hp->ssl, hp->caFile); } if (httpConnect(conn, hp->method, hp->uri, hp->ssl) < 0) { ejsThrowIOError(ejs, "Cannot issue request for \"%s\"", hp->uri); return 0; } if (mprGetBufLength(hp->requestContent) > 0) { nbytes = httpWriteBlock(conn->writeq, mprGetBufStart(hp->requestContent), mprGetBufLength(hp->requestContent), HTTP_BLOCK); if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot write request data for \"%s\"", hp->uri); return 0; } else if (nbytes > 0) { assert(nbytes == mprGetBufLength(hp->requestContent)); mprAdjustBufStart(hp->requestContent, nbytes); hp->requestContentCount += nbytes; } httpFinalize(conn); } httpNotify(conn, HTTP_EVENT_WRITABLE, 0); if (conn->async) { httpEnableConnEvents(hp->conn); } return hp; }
/* * function Worker(script: String = null, options: Object = null) * * Script is optional. If supplied, the script is run immediately by a worker thread. This call * does not block. Options are: search and name. */ static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *wejs; EjsVar *options, *value; EjsName qname; EjsWorker *self; cchar *search, *name; worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; options = (argc == 2) ? (EjsVar*) argv[1]: NULL; name = 0; search = ejs->ejsPath; if (options) { value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search")); if (ejsIsString(value)) { search = ejsGetString(value); } value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name")); if (ejsIsString(value)) { name = ejsGetString(value); } } if (name) { worker->name = mprStrdup(worker, name); } else { worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers)); } /* * Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. */ wejs = ejsCreate(ejs->service, NULL, search, 0); if (wejs == 0) { ejsThrowMemoryError(ejs); return 0; } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = mprStrcat(self, -1, "inside-", worker->name, NULL); ejsSetProperty(ejs, (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name)); ejsSetProperty(wejs, (EjsVar*) self, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name)); ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self); /* * Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE); /* * Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid */ self->obj.var.permanent = 1; if (argc > 0 && ejsIsPath(argv[0])) { addWorker(ejs, worker); worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path); 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; } } return (EjsVar*) worker; }
static EjsWorker *initWorker(Ejs *ejs, EjsWorker *worker, Ejs *baseVM, cchar *name, EjsArray *search, cchar *scriptFile) { Ejs *wejs; EjsWorker *self; EjsName sname; static int workerSeqno = 0; ejsBlockGC(ejs); if (worker == 0) { worker = ejsCreateWorker(ejs); } worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; if (name) { worker->name = sclone(name); } else { lock(ejs); worker->name = sfmt("worker-%d", workerSeqno++); unlock(ejs); } /* Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. The worker interpreter gets a new dispatcher */ if (baseVM) { if ((wejs = ejsCloneVM(baseVM)) == 0) { ejsThrowMemoryError(ejs); return 0; } } else { if ((wejs = ejsCreateVM(0, 0, ejs->flags)) == 0) { ejsThrowMemoryError(ejs); return 0; } if (ejsLoadModules(wejs, 0, 0) < 0) { return 0; } } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = sjoin("inside-", worker->name, NULL); #if MOB mprEnableDispatcher(wejs->dispatcher); #endif if (search) { ejsSetSearchPath(ejs, (EjsArray*) search); } // TODO - these should be don't delete ejsSetProperty(ejs, worker, ES_Worker_name, ejsCreateStringFromAsc(ejs, self->name)); ejsSetProperty(wejs, self, ES_Worker_name, ejsCreateStringFromAsc(wejs, self->name)); sname = ejsName(wejs, EJS_WORKER_NAMESPACE, "self"); ejsSetPropertyByName(wejs, wejs->global, sname, self); /* Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->global, NULL, EJS_WORKER_NAMESPACE); addWorker(ejs, worker); if (scriptFile) { worker->scriptFile = sclone(scriptFile); worker->state = EJS_WORKER_STARTED; if (mprCreateEvent(wejs->dispatcher, "workerMain", 0, (MprEventProc) workerMain, self, 0) < 0) { mprRemoveItem(ejs->workers, worker); ejsThrowStateError(ejs, "Cannot create worker event"); return 0; } } return worker; }