/* Invoke the next signal handler. Runs from the dispatcher so signal handlers don't have to be async-safe. */ static void signalEvent(MprSignal *sp, MprEvent *event) { MprSignal *np; mprAssert(sp); mprAssert(event); mprLog(7, "signalEvent signo %d, flags %x", sp->signo, sp->flags); np = sp->next; if (sp->flags & MPR_SIGNAL_BEFORE) { (sp->handler)(sp->data, sp); } if (sp->sigaction) { /* Call the original (foreign) action handler. Can't pass on siginfo, because there is no reliable and scalable way to save siginfo state when the signalHandler is reentrant for a given signal across multiple threads. */ (sp->sigaction)(sp->signo, NULL, NULL); } if (sp->flags & MPR_SIGNAL_AFTER) { (sp->handler)(sp->data, sp); } if (np) { /* Call all chained signal handlers. Create new event for each handler so we get the right dispatcher. WARNING: sp may have been removed and so sp->next may be null. That is why we capture np = sp->next above. */ mprCreateEvent(np->dispatcher, "signalEvent", 0, signalEvent, np, 0); } }
/* 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; }
PUBLIC int mprCreateEventOutside(MprDispatcher *dispatcher, cchar *name, void *proc, void *data, int flags) { if (mprCreateEvent(dispatcher, name, 0, proc, data, flags) == 0) { return MPR_ERR_CANT_CREATE; } 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 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; }
/* * 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; }
/* Read the output data from the CGI script and return it to the client. This is called by the MPR in response to I/O events from the CGI process for stdout/stderr data from the CGI script and for EOF from the CGI's stdin. IMPORTANT: This event runs on the connection's dispatcher. (ie. single threaded and safe) */ static void cgiCallback(MprCmd *cmd, int channel, void *data) { HttpConn *conn; Cgi *cgi; int suspended; if ((cgi = data) == 0) { return; } if ((conn = cgi->conn) == 0) { return; } conn->lastActivity = conn->http->now; switch (channel) { case MPR_CMD_STDIN: /* Stdin can absorb more data */ httpResumeQueue(cgi->writeq); break; case MPR_CMD_STDOUT: case MPR_CMD_STDERR: readFromCgi(cgi, channel); break; default: /* Child death notification */ if (cmd->status != 0) { httpError(cgi->conn, HTTP_CODE_BAD_GATEWAY, "Bad CGI process termination"); } break; } if (cgi->location) { httpRedirect(conn, conn->tx->status, cgi->location); } if (cmd->complete || cgi->location) { cgi->location = 0; httpFinalize(conn); mprCreateEvent(conn->dispatcher, "cgiComplete", 0, httpIOEvent, conn, 0); return; } suspended = httpIsQueueSuspended(conn->writeq); assert(!suspended || conn->tx->writeBlocked); mprEnableCmdOutputEvents(cmd, !suspended); mprCreateEvent(conn->dispatcher, "cgi", 0, httpIOEvent, conn, 0); }
/* Read the output data from the CGI script and return it to the client. This is called by the MPR in response to I/O events from the CGI process for stdout/stderr data from the CGI script and for EOF from the CGI's stdin. IMPORTANT: This event runs on the connection's dispatcher. (ie. single threaded and safe) */ static void cgiCallback(MprCmd *cmd, int channel, void *data) { HttpConn *conn; Cgi *cgi; int suspended; if ((cgi = data) == 0) { return; } if ((conn = cgi->conn) == 0) { return; } conn->lastActivity = conn->http->now; mprTrace(6, "CGI: cgiCallback event channel %d", channel); switch (channel) { case MPR_CMD_STDIN: /* Stdin can absorb more data */ httpResumeQueue(cgi->writeq); break; case MPR_CMD_STDOUT: case MPR_CMD_STDERR: readFromCgi(cgi, channel); break; default: /* Child death notification */ break; } if (cgi->location) { httpRedirect(conn, conn->tx->status, cgi->location); } if (cmd->complete || cgi->location) { cgi->location = 0; httpFinalize(conn); mprCreateEvent(conn->dispatcher, "cgiComplete", 0, httpIOEvent, conn, 0); return; } suspended = httpIsQueueSuspended(conn->writeq); mprTrace(6, "CGI: %s CGI: cgiCallback. Conn->writeq %d", suspended ? "DISABLE" : "ENABLE", conn->writeq->count); assert(!suspended || conn->tx->writeBlocked); mprEnableCmdOutputEvents(cmd, !suspended); mprCreateEvent(conn->dispatcher, "cgi", 0, httpIOEvent, conn, 0); }
PUBLIC void httpScheduleConnTimeout(HttpConn *conn) { if (!conn->timeoutEvent && !conn->destroyed) { /* Will run on the HttpConn dispatcher unless shutting down and it is destroyed already */ conn->timeoutEvent = mprCreateEvent(conn->dispatcher, "connTimeout", 0, connTimeout, conn, 0); } }
/* Worker thread main procedure. Worker is the inside worker. */ static int workerMain(EjsWorker *insideWorker, MprEvent *event) { Ejs *outside, *inside; EjsWorker *outsideWorker; MprDispatcher *dispatcher; Message *msg; assert(insideWorker->inside); outsideWorker = insideWorker->pair; assert(!outsideWorker->inside); assert(insideWorker->state == EJS_WORKER_BEGIN); outside = outsideWorker->ejs; inside = insideWorker->ejs; insideWorker->state = EJS_WORKER_STARTED; /* Run the script or file */ if (outsideWorker->scriptFile) { loadFile(insideWorker, outsideWorker->scriptFile); } else if (outsideWorker->scriptLiteral) { if (outside->service->loadScriptLiteral == 0) { ejsThrowIOError(outside, "worker: Compiling is not enabled"); return 0; } (outside->service->loadScriptLiteral)(inside, outsideWorker->scriptLiteral, NULL); } /* Check for exceptions */ if (inside->exception) { handleError(outside, outsideWorker, inside->exception, 0); inside->exception = 0; } ejsBlockGC(inside); if ((msg = createMessage()) == 0) { ejsThrowMemoryError(outside); return 0; } /* Post "onclose" finalization message */ msg->worker = outsideWorker; msg->callback = "onclose"; msg->callbackSlot = ES_Worker_onclose; insideWorker->state = EJS_WORKER_CLOSED; outsideWorker->state = EJS_WORKER_CLOSED; dispatcher = outside->dispatcher; mprCreateEvent(dispatcher, "doMessage", 0, (MprEventProc) doMessage, msg, 0); return 0; }
/* * Worker thread main procedure */ static void workerMain(EjsWorker *worker, MprWorker *mprWorker) { Ejs *ejs, *inside; EjsWorker *insideWorker; MprDispatcher *dispatcher; Message *msg; mprAssert(!worker->inside); insideWorker = worker->pair; mprAssert(insideWorker->state == EJS_WORKER_BEGIN); ejs = worker->ejs; inside = insideWorker->ejs; insideWorker->state = EJS_WORKER_STARTED; /* * Run the script or file */ if (worker->scriptFile) { loadFile(insideWorker, worker->scriptFile); } else if (worker->scriptLiteral) { if (ejs->service->loadScriptLiteral == 0) { ejsThrowIOError(ejs, "worker: Compiling is not enabled"); return; } (ejs->service->loadScriptLiteral)(inside, worker->scriptLiteral); } /* * Check for exceptions */ if (inside->exception) { handleError(ejs, worker, inside->exception); } if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return; } /* * Post "onclose" finalization message */ msg->worker = worker; msg->callback = "onclose"; msg->callbackSlot = ES_ejs_sys_Worker_onclose; insideWorker->state = EJS_WORKER_CLOSED; worker->state = EJS_WORKER_CLOSED; insideWorker->obj.var.permanent = 0; dispatcher = worker->ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); }
/* 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 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); }
PUBLIC void mprQueueIOEvent(MprWaitHandler *wp) { MprDispatcher *dispatcher; MprEvent *event; if (wp->flags & MPR_WAIT_NEW_DISPATCHER) { dispatcher = mprCreateDispatcher("IO", MPR_DISPATCHER_AUTO); } else if (wp->dispatcher) { dispatcher = wp->dispatcher; } else { dispatcher = mprGetDispatcher(); } event = mprCreateEvent(dispatcher, "IOEvent", 0, ioEvent, wp->handlerData, MPR_EVENT_DONT_QUEUE); event->mask = wp->presentMask; event->handler = wp; wp->event = event; mprQueueEvent(dispatcher, event); }
/* Event callback. Invoked for incoming web socket messages and other events of interest. */ static void chat_callback(HttpConn *conn, int event, int arg) { HttpPacket *packet; HttpConn *client; Msg *msg; int next; if (event == HTTP_EVENT_READABLE) { packet = httpGetPacket(conn->readq); if (packet->type == WS_MSG_TEXT || packet->type == WS_MSG_BINARY) { for (ITERATE_ITEMS(clients, client, next)) { msg = mprAllocObj(Msg, manageMsg); msg->conn = client; msg->packet = packet; mprCreateEvent(client->dispatcher, "chat", 0, chat, msg, 0); } } } else if (event == HTTP_EVENT_APP_CLOSE) {
static void testCriticalSection(MprTestGroup *gp) { MprCond *cond; MprEvent *event; int rc; cond = mprCreateCond(gp); assert(cond != 0); mprAssert(cond->triggered == 0); /* * Create an event to signal the condition var in 10 msec */ event = mprCreateEvent(mprGetDispatcher(gp), callback, 0, 0, (void*) cond, 0); assert(event != 0); rc = mprWaitForCondWithService(cond, MPR_TEST_TIMEOUT); assert(rc == 0); mprFree(cond); mprFree(event); }
/* * WARNING: the inside interpreter owns the exception object. Must fully extract all fields */ static void handleError(Ejs *ejs, EjsWorker *worker, EjsVar *exception) { EjsError *error; MprDispatcher *dispatcher; Message *msg; mprAssert(!worker->inside); mprAssert(exception); mprAssert(ejs == worker->ejs); if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return; } msg->worker = worker; msg->callback = "onerror"; msg->callbackSlot = ES_ejs_sys_Worker_onerror; /* * Inside interpreter owns the exception object, so must fully extract all exception. * Allocate into the outside worker's interpreter. */ if (ejsIsError(exception)) { error = (EjsError*) exception; msg->message = mprStrdup(ejs, error->message); msg->filename = mprStrdup(ejs, error->filename ? error->filename : "script"); msg->lineNumber = error->lineNumber; msg->stack = mprStrdup(ejs, error->stack); } else if (ejsIsString(exception)) { msg->message = mprStrdup(ejs, ejsGetString(exception)); } else { msg->message = mprStrdup(ejs, ejsGetString(ejsToString(ejs, exception))); } dispatcher = ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); }
/* Called by mprServiceEvents after a signal has been received. Create an event and queue on the appropriate dispatcher */ void mprServiceSignals() { MprSignalService *ssp; MprSignal *sp; MprSignalInfo *ip; int signo; ssp = MPR->signalService; ssp->hasSignals = 0; for (ip = ssp->info; ip < &ssp->info[MPR_MAX_SIGNALS]; ip++) { if (ip->triggered) { ip->triggered = 0; /* Create an event for the head of the signal handler chain for this signal Copy info from Thread.sigInfo to MprSignal structure. */ signo = (int) (ip - ssp->info); if ((sp = ssp->signals[signo]) != 0) { mprCreateEvent(sp->dispatcher, "signalEvent", 0, signalEvent, sp, 0); } } } }
/* Do a performance benchmark */ static void doBenchmark(void *thread) { MprTime start; MprList *list; int count, i; MprMutex *lock; MprSpin *spin; mprPrintf("Group\t%-30s\t%13s\t%12s\n", "Benchmark", "Microsec", "Elapsed-sec"); testMalloc(); if (!app->testAllocOnly) { /* Locking primitives */ mprPrintf("Lock Benchmarks\n"); lock = mprCreateLock(); count = 5000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprLock(lock); mprUnlock(lock); } endMark(start, count, "Mutex lock|unlock"); /* Locking primitives */ mprPrintf("Lock Benchmarks\n"); spin = mprCreateSpinLock(); count = 5000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprSpinLock(spin); mprSpinUnlock(spin); } endMark(start, count, "Spin lock|unlock"); /* Condition signal / wait */ mprPrintf("Cond Benchmarks\n"); count = 1000000 * app->iterations; start = startMark(); mprResetCond(app->complete); for (i = 0; i < count; i++) { mprSignalCond(app->complete); mprWaitForCond(app->complete, -1); } endMark(start, count, "Cond signal|wait"); /* List */ mprPrintf("List Benchmarks\n"); count = 2000000 * app->iterations; list = mprCreateList(count, 0); start = startMark(); for (i = 0; i < count; i++) { mprAddItem(list, (void*) (long) i); mprRemoveItem(list, (void*) (long) i); } endMark(start, count, "Link insert|remove"); /* Events */ mprPrintf("Event Benchmarks\n"); mprResetCond(app->complete); count = 30000 * app->iterations; app->markCount = count; start = startMark(); for (i = 0; i < count; i++) { mprCreateEvent(NULL, "eventBenchmark", 0, eventCallback, ITOP(i), MPR_EVENT_QUICK); } mprWaitForCond(app->complete, -1); endMark(start, count, "Event (create|run|delete)"); /* Test timer creation, run and remove These create a new dispatcher and run a worker thread. */ mprPrintf("Timer\n"); mprResetCond(app->complete); count = 20000 * app->iterations; app->markCount = count; start = startMark(); for (i = 0; i < count; i++) { mprCreateTimerEvent(NULL, "timerBenchmark", 0, timerCallback, (void*) (long) i, 0); } mprWaitForCond(app->complete, -1); endMark(start, count, "Timer (create|delete)"); /* Alloc (1K) */ mprPrintf("Alloc 1K Benchmarks\n"); count = 2000000 * app->iterations; start = startMark(); for (i = 0; i < count; i++) { mprAlloc(1024); if ((i % 128) == 0) { mprGC(0); } } endMark(start, count, "Alloc mprAlloc(1K)"); } testComplete = 1; }
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; }
PUBLIC void setTimeout(void *proc, MprTicks timeout, void *data) { mprCreateEvent(getStream()->dispatcher, "setTimeout", (int) timeout, proc, data, 0); }
/* Create an interval timer */ PUBLIC MprEvent *mprCreateTimerEvent(MprDispatcher *dispatcher, cchar *name, MprTicks period, void *proc, void *data, int flags) { return mprCreateEvent(dispatcher, name, period, proc, data, MPR_EVENT_CONTINUOUS | flags); }
/* Start the CGI command program. This commences the CGI gateway program. This will be called after content for form and upload requests (or if "RunHandler" before specified), otherwise it runs before receiving content data. */ static void startCgi(HttpQueue *q) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpConn *conn; MprCmd *cmd; Cgi *cgi; cchar *baseName, **argv, *fileName, **envv; ssize varCount; int argc, count; argv = 0; argc = 0; cgi = q->queueData; conn = q->conn; rx = conn->rx; route = rx->route; tx = conn->tx; /* The command uses the conn dispatcher. This serializes all I/O for both the connection and the CGI gateway. */ if ((cmd = mprCreateCmd(conn->dispatcher)) == 0) { return; } cgi->cmd = cmd; if (conn->http->forkCallback) { cmd->forkCallback = conn->http->forkCallback; cmd->forkData = conn->http->forkData; } argc = 1; /* argv[0] == programName */ buildArgs(conn, cmd, &argc, &argv); fileName = argv[0]; baseName = mprGetPathBase(fileName); /* nph prefix means non-parsed-header. Don't parse the CGI output for a CGI header */ if (strncmp(baseName, "nph-", 4) == 0 || (strlen(baseName) > 4 && strcmp(&baseName[strlen(baseName) - 4], "-nph") == 0)) { /* Pretend we've seen the header for Non-parsed Header CGI programs */ cgi->seenHeader = 1; tx->flags |= HTTP_TX_USE_OWN_HEADERS; } /* Build environment variables */ varCount = mprGetHashLength(rx->headers) + mprGetHashLength(rx->svars) + mprGetJsonLength(rx->params); if ((envv = mprAlloc((varCount + 1) * sizeof(char*))) != 0) { count = copyParams(conn, envv, 0, rx->params, route->envPrefix); count = copyVars(conn, envv, count, rx->svars, ""); count = copyVars(conn, envv, count, rx->headers, "HTTP_"); assert(count <= varCount); } #if !VXWORKS /* This will be ignored on VxWorks because there is only one global current directory for all tasks */ mprSetCmdDir(cmd, mprGetPathDir(fileName)); #endif mprSetCmdCallback(cmd, cgiCallback, cgi); if (mprStartCmd(cmd, argc, argv, envv, MPR_CMD_IN | MPR_CMD_OUT | MPR_CMD_ERR) < 0) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot run CGI process: %s, URI %s", fileName, rx->uri); return; } #if ME_WIN_LIKE mprCreateEvent(conn->dispatcher, "cgi-win", 10, waitForCgi, cgi, MPR_EVENT_CONTINUOUS); #endif }
/* * Do a performance benchmark */ static void doBenchmark(Mpr *mpr, void *thread) { MprTime start; MprList *list; void *mp; int count, i; #if BLD_FEATURE_MULTITHREAD MprMutex *lock; #endif complete = mprCreateCond(mpr); mprPrintf(mpr, "Group\t%-30s\t%13s\t%12s\n", "Benchmark", "Microsec", "Elapsed-sec"); /* * Alloc (1K) */ mprPrintf(mpr, "Alloc Benchmarks\n"); count = 2000000 * iterations; start = startMark(mpr); for (i = 0; i < count; i++) { mp = mprAlloc(mpr, 1024); memset(mp, 0, 1024); mprFree(mp); } endMark(mpr, start, count, "Alloc mprAlloc(1K)|mprFree"); start = startMark(mpr); #if BLD_FEATURE_MULTITHREAD /* * Locking primitives */ mprPrintf(mpr, "Lock Benchmarks\n"); lock = mprCreateLock(mpr); count = 5000000 * iterations; start = startMark(mpr); for (i = 0; i < count; i++) { mprLock(lock); mprUnlock(lock); } endMark(mpr, start, count, "Mutex lock|unlock"); mprFree(lock); /* * Condition signal / wait */ mprPrintf(mpr, "Cond Benchmarks\n"); count = 1000000 * iterations; start = startMark(mpr); mprResetCond(complete); for (i = 0; i < count; i++) { mprSignalCond(complete); mprWaitForCond(complete, -1); } endMark(mpr, start, count, "Cond signal|wait"); #endif /* * List */ mprPrintf(mpr, "List Benchmarks\n"); count = 500000 * iterations; list = mprCreateList(mpr); start = startMark(mpr); for (i = 0; i < count; i++) { mprAddItem(list, (void*) (long) i); mprRemoveItem(list, (void*) (long) i); } endMark(mpr, start, count, "Link insert|remove"); mprFree(list);; /* * Events */ mprPrintf(mpr, "Event Benchmarks\n"); mprResetCond(complete); count = 200000 * iterations; markCount = count; start = startMark(mpr); for (i = 0; i < count; i++) { mprCreateEvent(mprGetDispatcher(mpr), eventCallback, 0, 0, (void*) (long) i, 0); } endMark(mpr, start, count, "Event (create)"); mprWaitForCondWithService(complete, -1); endMark(mpr, start, count, "Event (run|delete)"); /* * Test timer creation, run and delete (make a million timers!) */ mprPrintf(mpr, "Timer\n"); mprResetCond(complete); count = 50000 * iterations; markCount = count; start = startMark(mpr); for (i = 0; i < count; i++) { mprCreateTimerEvent(mprGetDispatcher(mpr), timerCallback, 0, 0, (void*) (long) i, 0); } endMark(mpr, start, count, "Timer (create)"); mprWaitForCondWithService(complete, -1); endMark(mpr, start, count, "Timer (delete)"); testComplete = 1; }