/* * Service I/O and return a count of characters that can be read without blocking. If the proces has completed, * then return 1 to indicate that read can be called. */ static int serviceCmdEvents(MprCmd *cmd, int channel, int timeout) { int rc, count, status; if (mprGetDebugMode(cmd)) { timeout = MAXINT; } if (cmd->files[channel].handle) { rc = PeekNamedPipe(cmd->files[channel].handle, NULL, 0, NULL, &count, NULL); if (rc && count > 0) { return count; } } if (cmd->process == 0) { return 1; } if ((status = WaitForSingleObject(cmd->process, timeout)) == WAIT_OBJECT_0) { if (cmd->requiredEof == 0) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); mprSignalCond(cmd->completeCond); return 0; } return 1; } return 0; }
/* * Close a command channel. Must be able to be called redundantly. */ void mprCloseCmdFd(MprCmd *cmd, int channel) { mprAssert(0 <= channel && channel <= MPR_CMD_MAX_PIPE); /* * Disconnect but don't free. This prevents some races with callbacks. */ if (cmd->handlers[channel]) { mprDisconnectWaitHandler(cmd->handlers[channel]); } if (cmd->files[channel].fd != -1) { close(cmd->files[channel].fd); cmd->files[channel].fd = -1; #if BLD_WIN_LIKE cmd->files[channel].handle = 0; #endif if (channel != MPR_CMD_STDIN) { if (++cmd->eofCount >= cmd->requiredEof) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); mprSignalCond(cmd->completeCond); } } } }
static void resetCmd(MprCmd *cmd) { MprCmdFile *files; int i; files = cmd->files; for (i = 0; i < MPR_CMD_MAX_PIPE; i++) { if (cmd->handlers[i]) { mprFree(cmd->handlers[i]); cmd->handlers[i] = 0; } if (files[i].clientFd >= 0) { close(files[i].clientFd); files[i].clientFd = -1; } if (files[i].fd >= 0) { close(files[i].fd); files[i].fd = -1; } } cmd->eofCount = 0; cmd->status = -1; mprResetCond(cmd->completeCond); if (cmd->pid && !(cmd->flags & MPR_CMD_DETACH)) { mprStopCmd(cmd); mprReapCmd(cmd, 0); mprSignalCond(cmd->completeCond); } }
int mprGetCmdExitStatus(MprCmd *cmd, int *statusp) { mprAssert(statusp); if (cmd->pid) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); if (cmd->pid) { return MPR_ERR_NOT_READY; } } *statusp = cmd->status; return 0; }
/* * Wait for a command to complete. Return 0 if the command completed, otherwise return MPR_ERR_TIMEOUT. * This will call mprReapCmd if requried. */ int mprWaitForCmd(MprCmd *cmd, int timeout) { MprTime mark; int complete, rc; if (timeout < 0) timeout = MAXINT; if (mprGetDebugMode(cmd)) timeout = MAXINT; mark = mprGetTime(cmd); complete = 0; do { if (cmd->requiredEof == 0) { if (mprReapCmd(cmd, 10) == 0) { mprSignalCond(cmd->completeCond); return 0; } } mprPollCmdPipes(cmd, timeout); rc = mprWaitForCondWithService(cmd->completeCond, 10); if (rc == 0) { complete++; break; } else if (rc != MPR_ERR_TIMEOUT) { mprAssert(0); } } while (mprGetElapsedTime(cmd, mark) <= timeout); if (!complete) { mprLog(cmd, 7, "cmd: mprWaitForCmd: timeout waiting for command to complete"); return MPR_ERR_TIMEOUT; } if (cmd->pid) { mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); } mprLog(cmd, 7, "cmd: waitForChild: status %d", cmd->status); return 0; }
/* This routine runs after all incoming data has been received */ static void runCgi(MaQueue *q) { MaResponse *resp; MaConn *conn; MprCmd *cmd; conn = q->conn; resp = conn->response; cmd = (MprCmd*) q->queueData; if (cmd == 0) { startCgi(q); cmd = (MprCmd*) q->queueData; if (q->pair->count > 0) { writeToCGI(q->pair); } } /* Close the CGI program's stdin. This will allow it to exit if it was expecting input data. */ mprCloseCmdFd(cmd, MPR_CMD_STDIN); if (conn->requestFailed) { maPutForService(q, maCreateEndPacket(q), 1); return; } while (mprWaitForCmd(cmd, 1000) < 0) { if (mprGetElapsedTime(cmd, cmd->lastActivity) >= conn->host->timeout) { break; } } if (cmd->pid == 0) { maPutForService(q, maCreateEndPacket(q), 1); } else { mprStopCmd(cmd); mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); cmd->status = 255; } }