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; }
/* static function run(timeout: Number = -1, oneEvent: Boolean = false): Boolean */ static EjsObj *app_run(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprTicks mark, remaining; int64 dispatcherMark; int rc, oneEvent, timeout; timeout = (argc > 0) ? ejsGetInt(ejs, argv[0]) : MAXINT; oneEvent = (argc > 1) ? ejsGetInt(ejs, argv[1]) : 0; if (ejs->hosted) { return ESV(true); } if (timeout < 0) { timeout = MAXINT; } mark = mprGetTicks(); remaining = timeout; dispatcherMark = mprGetEventMark(ejs->dispatcher); do { rc = mprWaitForEvent(ejs->dispatcher, remaining, dispatcherMark); remaining = mprGetRemainingTicks(mark, timeout); dispatcherMark = mprGetEventMark(ejs->dispatcher); } while (!ejs->exception && !oneEvent && !ejs->exiting && remaining > 0 && !mprIsStopping()); return (rc == 0) ? ESV(true) : ESV(false); }
/* function waitForMessage(timeout: Number = -1): Boolean */ static EjsBoolean *workerWaitForMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { MprTicks mark, remaining; int timeout; timeout = (argc > 0) ? ejsGetInt(ejs, argv[0]): MAXINT; if (timeout < 0) { timeout = MAXINT; } mark = mprGetTicks(); remaining = timeout; worker->gotMessage = 0; do { mprWaitForEvent(ejs->dispatcher, (int) remaining); remaining = mprGetRemainingTicks(mark, timeout); } while (!worker->gotMessage && remaining > 0 && !ejs->exception); if (worker->gotMessage) { worker->gotMessage = 0; return ESV(true); } else { return ESV(true); } }
/* function run(): Void */ static EjsVoid *hs_run(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { if (!sp->hosted) { while (!ejs->exiting && !mprIsStopping()) { mprWaitForEvent(ejs->dispatcher, MAXINT); } } return 0; }
/* function run(): Void */ static EjsVoid *hs_run(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { int64 dispatcherMark; if (!sp->hosted) { dispatcherMark = mprGetEventMark(ejs->dispatcher); while (!ejs->exiting && !mprIsStopping()) { mprWaitForEvent(ejs->dispatcher, MPR_MAX_TIMEOUT, dispatcherMark); dispatcherMark = mprGetEventMark(ejs->dispatcher); } } return 0; }
/* Pause the application. This services events while asleep. static function sleep(delay: Number = -1): void MOB - sleep currently throws if an exception is generated in an event callback (worker). It should not. */ static EjsObj *app_sleep(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprTicks mark, remaining; int timeout; timeout = (argc > 0) ? ejsGetInt(ejs, argv[0]) : MAXINT; if (timeout < 0) { timeout = MAXINT; } mark = mprGetTicks(); remaining = timeout; do { mprWaitForEvent(ejs->dispatcher, (int) remaining); remaining = mprGetRemainingTicks(mark, timeout); } while (!ejs->exiting && remaining > 0 && !mprIsStopping()); return 0; }
/* Wait for an event to complete signified by the 'completion' flag being set. This will wait for events on the dispatcher. The completion flag will be reset on return. */ PUBLIC bool mprWaitForCompletion(MprDispatcher *dispatcher, MprTicks timeout) { MprTicks mark; bool success; assert(timeout >= 0); if (dispatcher == 0) { dispatcher = MPR->dispatcher; } if (mprGetDebugMode()) { timeout *= 100; } for (mark = mprGetTicks(); !(dispatcher->flags & MPR_DISPATCHER_COMPLETE) && mprGetElapsedTicks(mark) < timeout; ) { mprWaitForEvent(dispatcher, 10, -1); } success = (dispatcher->flags & MPR_DISPATCHER_COMPLETE) ? 1 : 0; dispatcher->flags &= ~MPR_DISPATCHER_COMPLETE; return success; }
/* Wait for a command to complete. Return 0 if the command completed, otherwise it will return MPR_ERR_TIMEOUT. */ PUBLIC int mprWaitForCmd(MprCmd *cmd, MprTicks timeout) { MprTicks expires, remaining, delay; int64 dispatcherMark; assert(cmd); if (timeout < 0) { timeout = MAXINT; } if (mprGetDebugMode()) { timeout = MAXINT; } if (cmd->stopped) { timeout = 0; } expires = mprGetTicks() + timeout; remaining = timeout; /* Add root to allow callers to use mprRunCmd without first managing the cmd */ mprAddRoot(cmd); dispatcherMark = mprGetEventMark(cmd->dispatcher); while (!cmd->complete && remaining > 0) { if (mprShouldAbortRequests()) { break; } delay = (cmd->eofCount >= cmd->requiredEof) ? 10 : remaining; if (!MPR->eventing) { mprServiceEvents(delay, MPR_SERVICE_NO_BLOCK); delay = 0; } mprWaitForEvent(cmd->dispatcher, delay, dispatcherMark); remaining = (expires - mprGetTicks()); dispatcherMark = mprGetEventMark(cmd->dispatcher); } mprRemoveRoot(cmd); if (cmd->pid) { return MPR_ERR_TIMEOUT; } return 0; }
/* Wait for the connection to reach a given state. Should only be used on the client side. @param state Desired state. Set to zero if you want to wait for one I/O event. @param timeout Timeout in msec. If timeout is zero, wait forever. If timeout is < 0, use default inactivity and duration timeouts. */ PUBLIC int httpWait(HttpConn *conn, int state, MprTicks timeout) { HttpLimits *limits; MprTicks delay, start; int64 dispatcherMark; int justOne; limits = conn->limits; if (conn->endpoint) { assert(!conn->endpoint); return MPR_ERR_BAD_STATE; } if (conn->state <= HTTP_STATE_BEGIN) { return MPR_ERR_BAD_STATE; } if (state == 0) { /* Wait for just one I/O event */ state = HTTP_STATE_FINALIZED; justOne = 1; } else { justOne = 0; } if (conn->error) { if (conn->state >= state) { return 0; } return MPR_ERR_BAD_STATE; } if (timeout < 0) { timeout = limits->requestTimeout; } else if (timeout == 0) { timeout = MPR_MAX_TIMEOUT; } if (state > HTTP_STATE_CONTENT) { httpFinalizeOutput(conn); } start = conn->http->now; dispatcherMark = mprGetEventMark(conn->dispatcher); while (conn->state < state && !conn->error && !mprIsSocketEof(conn->sock)) { if (httpRequestExpired(conn, -1)) { return MPR_ERR_TIMEOUT; } httpEnableConnEvents(conn); delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout)); delay = max(delay, 0); mprWaitForEvent(conn->dispatcher, delay, dispatcherMark); if (justOne || (mprGetRemainingTicks(start, timeout) <= 0)) { break; } dispatcherMark = mprGetEventMark(conn->dispatcher); } if (conn->error) { return MPR_ERR_NOT_READY; } if (conn->state < state) { if (mprGetRemainingTicks(start, timeout) <= 0) { return MPR_ERR_TIMEOUT; } if (!justOne) { return MPR_ERR_CANT_READ; } } conn->lastActivity = conn->http->now; return 0; }
/* Read data. If sync mode, this will block. If async, will never block. Will return what data is available up to the requested size. Timeout in milliseconds to wait. Set to -1 to use the default inactivity timeout. Set to zero to wait forever. Returns a count of bytes read. Returns zero if no data. EOF if returns zero and conn->state is > HTTP_STATE_CONTENT. */ PUBLIC ssize httpReadBlock(HttpConn *conn, char *buf, ssize size, MprTicks timeout, int flags) { HttpPacket *packet; HttpQueue *q; HttpLimits *limits; MprBuf *content; MprTicks start, delay; ssize nbytes, len; int64 dispatcherMark; q = conn->readq; assert(q->count >= 0); assert(size >= 0); limits = conn->limits; if (flags == 0) { flags = conn->async ? HTTP_NON_BLOCK : HTTP_BLOCK; } if (timeout < 0) { timeout = limits->inactivityTimeout; } else if (timeout == 0) { timeout = MPR_MAX_TIMEOUT; } if (flags & HTTP_BLOCK) { start = conn->http->now; dispatcherMark = mprGetEventMark(conn->dispatcher); while (q->count <= 0 && !conn->error && (conn->state <= HTTP_STATE_CONTENT)) { if (httpRequestExpired(conn, -1)) { break; } delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout)); httpEnableConnEvents(conn); mprWaitForEvent(conn->dispatcher, delay, dispatcherMark); if (mprGetRemainingTicks(start, timeout) <= 0) { break; } dispatcherMark = mprGetEventMark(conn->dispatcher); } } for (nbytes = 0; size > 0 && q->count > 0; ) { if ((packet = q->first) == 0) { break; } content = packet->content; len = mprGetBufLength(content); len = min(len, size); assert(len <= q->count); if (len > 0) { len = mprGetBlockFromBuf(content, buf, len); assert(len <= q->count); } buf += len; size -= len; q->count -= len; assert(q->count >= 0); nbytes += len; if (mprGetBufLength(content) == 0) { httpGetPacket(q); } if (flags & HTTP_NON_BLOCK) { break; } } assert(q->count >= 0); if (nbytes < size) { buf[nbytes] = '\0'; } return nbytes; }
/* Wait for the connection to reach a given state. Should only be used on the client side. @param state Desired state. Set to zero if you want to wait for one I/O event. @param timeout Timeout in msec. If timeout is zero, wait forever. If timeout is < 0, use default inactivity and duration timeouts. */ PUBLIC int httpWait(HttpStream *stream, int state, MprTicks timeout) { HttpLimits *limits; MprTicks delay, start; int64 dispatcherMark; int justOne; limits = stream->limits; if (httpServerStream(stream)) { return MPR_ERR_BAD_STATE; } if (stream->state <= HTTP_STATE_BEGIN) { return MPR_ERR_BAD_STATE; } if (state == 0) { /* Wait for just one I/O event */ state = HTTP_STATE_FINALIZED; justOne = 1; } else { justOne = 0; } if (stream->error) { if (stream->state >= state) { return 0; } return MPR_ERR_BAD_STATE; } if (timeout < 0) { timeout = limits->requestTimeout; } else if (timeout == 0) { timeout = MPR_MAX_TIMEOUT; } if (state > HTTP_STATE_CONTENT) { httpFinalizeOutput(stream); } start = stream->http->now; dispatcherMark = mprGetEventMark(stream->dispatcher); // TODO - how does this work with http2? while (stream->state < state && !stream->error && !mprIsSocketEof(stream->sock)) { if (httpRequestExpired(stream, -1)) { return MPR_ERR_TIMEOUT; } // TODO - review httpEnableNetEvents(stream->net); delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout)); delay = max(delay, 0); mprWaitForEvent(stream->dispatcher, delay, dispatcherMark); if (justOne || (mprGetRemainingTicks(start, timeout) <= 0)) { break; } dispatcherMark = mprGetEventMark(stream->dispatcher); } if (stream->error) { return MPR_ERR_NOT_READY; } if (stream->state < state) { if (mprGetRemainingTicks(start, timeout) <= 0) { return MPR_ERR_TIMEOUT; } if (!justOne) { return MPR_ERR_CANT_READ; } } stream->lastActivity = stream->http->now; return 0; }