/* Wait for I/O on all registered descriptors. Timeout is in milliseconds. Return the number of events serviced. Should only be called by the thread that calls mprServiceEvents */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { MSG msg; assert(ws->hwnd); if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if BIT_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } SetTimer(ws->hwnd, 0, (UINT) timeout, NULL); mprYield(MPR_YIELD_STICKY); if (GetMessage(&msg, NULL, 0, 0) == 0) { mprResetYield(); mprTerminate(MPR_EXIT_DEFAULT, -1); } else { mprClearWaiting(); mprResetYield(); TranslateMessage(&msg); DispatchMessage(&msg); } ws->wakeRequested = 0; }
/* Wait for I/O on all registered file descriptors. Timeout is in milliseconds. Return the number of events detected. */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { struct epoll_event events[ME_MAX_EVENTS]; int nevents; if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if ME_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } mprYield(MPR_YIELD_STICKY); if ((nevents = epoll_wait(ws->epoll, events, sizeof(events) / sizeof(struct epoll_event), timeout)) < 0) { if (errno != EINTR) { mprLog("error mpr event", 0, "epoll returned %d, errno %d", nevents, mprGetOsError()); } } mprClearWaiting(); mprResetYield(); if (nevents > 0) { serviceIO(ws, events, nevents); } ws->wakeRequested = 0; }
/* Windows only routine to wait for I/O on the channels to the gateway and the child process. This will queue events on the dispatcher queue when I/O occurs or the process dies. NOTE: NamedPipes cannot use WaitForMultipleEvents, so we dedicate a thread to polling. WARNING: this should not be called from a dispatcher other than cmd->dispatcher. */ static void pollWinCmd(MprCmd *cmd, MprTicks timeout) { MprTicks mark, delay; MprWaitHandler *wp; int i, rc, nbytes; mark = mprGetTicks(); if (cmd->stopped) { timeout = 0; } slock(cmd); for (i = MPR_CMD_STDOUT; i < MPR_CMD_MAX_PIPE; i++) { if (cmd->files[i].handle) { wp = cmd->handlers[i]; if (wp && wp->desiredMask & MPR_READABLE) { rc = PeekNamedPipe(cmd->files[i].handle, NULL, 0, NULL, &nbytes, NULL); if (rc && nbytes > 0 || cmd->process == 0) { wp->presentMask |= MPR_READABLE; mprQueueIOEvent(wp); } } } } if (cmd->files[MPR_CMD_STDIN].handle) { wp = cmd->handlers[MPR_CMD_STDIN]; if (wp && wp->desiredMask & MPR_WRITABLE) { wp->presentMask |= MPR_WRITABLE; mprQueueIOEvent(wp); } } if (cmd->process) { delay = (cmd->eofCount == cmd->requiredEof && cmd->files[MPR_CMD_STDIN].handle == 0) ? timeout : 0; do { mprYield(MPR_YIELD_STICKY); if (WaitForSingleObject(cmd->process, (DWORD) delay) == WAIT_OBJECT_0) { mprResetYield(); reapCmd(cmd, 0); break; } else { mprResetYield(); } delay = mprGetRemainingTicks(mark, timeout); } while (cmd->eofCount == cmd->requiredEof); } sunlock(cmd); }
/* Wait for an event to occur on the dispatcher and service the event. This is not called by mprServiceEvents. The dispatcher may be "started" and owned by the thread, or it may be unowned. WARNING: the event may have already happened by the time this API is invoked. WARNING: this will enable GC while sleeping. */ PUBLIC int mprWaitForEvent(MprDispatcher *dispatcher, MprTicks timeout, int64 mark) { MprEventService *es; MprTicks expires, delay; int runEvents, changed; if (dispatcher == NULL) { dispatcher = MPR->dispatcher; } if (dispatcher->flags & MPR_DISPATCHER_DESTROYED) { return 0; } if ((runEvents = (dispatcher->owner == mprGetCurrentOsThread())) != 0) { /* Called from an event on a running dispatcher */ assert(isRunning(dispatcher) || (dispatcher->flags & MPR_DISPATCHER_DESTROYED)); if (dispatchEvents(dispatcher)) { return 0; } } es = MPR->eventService; es->now = mprGetTicks(); expires = timeout < 0 ? MPR_MAX_TIMEOUT : (es->now + timeout); if (expires < 0) { expires = MPR_MAX_TIMEOUT; } delay = expires - es->now; lock(es); delay = getDispatcherIdleTicks(dispatcher, delay); dispatcher->flags |= MPR_DISPATCHER_WAITING; changed = dispatcher->mark != mark && mark != -1; unlock(es); if (changed) { return 0; } mprYield(MPR_YIELD_STICKY); mprWaitForCond(dispatcher->cond, delay); mprResetYield(); es->now = mprGetTicks(); lock(es); dispatcher->flags &= ~MPR_DISPATCHER_WAITING; unlock(es); if (runEvents) { dispatchEvents(dispatcher); assert(isRunning(dispatcher) || (dispatcher->flags & MPR_DISPATCHER_DESTROYED)); } return 0; }
/* Wait for I/O on a single file descriptor. Return a mask of events found. Mask is the events of interest. timeout is in milliseconds. */ PUBLIC int mprWaitForSingleIO(int fd, int mask, MprTicks timeout) { struct epoll_event ev, events[2]; int epfd, rc, result; if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } memset(&ev, 0, sizeof(ev)); memset(events, 0, sizeof(events)); ev.data.fd = fd; if ((epfd = epoll_create(ME_MAX_EVENTS)) < 0) { mprLog("error mpr event", 0, "Epoll_create failed, errno=%d", errno); return MPR_ERR_CANT_INITIALIZE; } ev.events = 0; if (mask & MPR_READABLE) { ev.events = EPOLLIN | EPOLLHUP; } if (mask & MPR_WRITABLE) { ev.events = EPOLLOUT | EPOLLHUP; } if (ev.events) { epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); } mprYield(MPR_YIELD_STICKY); rc = epoll_wait(epfd, events, sizeof(events) / sizeof(struct epoll_event), timeout); mprResetYield(); close(epfd); result = 0; if (rc < 0) { mprLog("error mpr event", 0, "Epoll returned %d, errno %d", rc, errno); } else if (rc > 0) { if (rc > 0) { if ((events[0].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) && (mask & MPR_READABLE)) { result |= MPR_READABLE; } if ((events[0].events & (EPOLLOUT | EPOLLHUP)) && (mask & MPR_WRITABLE)) { result |= MPR_WRITABLE; } } } return result; }
/* Read input from the console (stdin) */ static int consoleGets(EcStream *stream) { char prompt[MPR_MAX_STRING], *line, *cp; int level; if (stream->flags & EC_STREAM_EOL) { return 0; } level = stream->compiler->state ? stream->compiler->state->blockNestCount : 0; fmt(prompt, sizeof(prompt), "%s-%d> ", EJS_NAME, level); mprYield(MPR_YIELD_STICKY); line = readline(prompt); mprResetYield(); if (line == NULL) { stream->eof = 1; mprPrintf("\n"); return -1; } cp = strim(line, "\r\n", MPR_TRIM_BOTH); ecSetStreamBuf(stream, cp, slen(cp)); stream->flags |= EC_STREAM_EOL; return (int) slen(cp); }
PUBLIC void mprSleep(MprTicks timeout) { mprYield(MPR_YIELD_STICKY); mprNap(timeout); mprResetYield(); }