OJInt32_t WindowsProcess::join(OJInt32_t time) { if (isRunning()) WaitForSingleObject(processHandle_, time); return getExitCode(); }
STDMETHODIMP ProcessWrap::COMGETTER(ExitCode)(LONG *aExitCode) { LogRelFlow(("{%p} %s: enter aExitCode=%p\n", this, "Process::getExitCode", aExitCode)); VirtualBoxBase::clearError(); HRESULT hrc; try { CheckComArgOutPointerValidThrow(aExitCode); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) throw autoCaller.rc(); hrc = getExitCode(aExitCode); } catch (HRESULT hrc2) { hrc = hrc2; } catch (...) { hrc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); } LogRelFlow(("{%p} %s: leave *aExitCode=%RI32 hrc=%Rhrc\n", this, "Process::getExitCode", *aExitCode, hrc)); return hrc; }
OJInt32_t WindowsProcess::start() { ILogger *logger = LoggerFactory::getLogger(LoggerId::AppInitLoggerId); //加到作业中 if (!jobHandle_.assinProcess(processHandle_)) { logger->logErrorX(OJStr("[process] - can't assign process to job! error:%u"), GetLastError()); kill(); return -1; } //启动线程 ResumeThread(threadHandle_); //关闭不使用的句柄。让进程执行完毕后立即退出。 SAFE_CLOSE_HANDLE_AND_RESET(threadHandle_); SAFE_CLOSE_HANDLE_AND_RESET(inputFileHandle_) SAFE_CLOSE_HANDLE_AND_RESET(outputFileHandle_) result_ = AppConfig::JudgeCode::Accept; DWORD ExecuteResult = -1; ULONG completeKey; LPOVERLAPPED processInfo; bool done = false; while(!done) { if(!jobHandle_.getState(ExecuteResult, completeKey, processInfo)) { DEBUG_MSG(OJStr("get job State faild!")); OJSleep(1); continue; } DWORD dwCode = (DWORD)processInfo; switch (ExecuteResult) { case JOB_OBJECT_MSG_NEW_PROCESS: //DEBUG_MSG_VS(OJStr("[WindowsProcess]new process: %u"), dwCode); break; case JOB_OBJECT_MSG_END_OF_JOB_TIME: //job超时 DEBUG_MSG(OJStr("[WindowsProcess]Job time limit reached")); result_ = AppConfig::JudgeCode::TimeLimitExceed; done = true; break; case JOB_OBJECT_MSG_END_OF_PROCESS_TIME: //线程超时 DEBUG_MSG(OJStr("[WindowsProcess]process time limit reached")); result_ = AppConfig::JudgeCode::TimeLimitExceed; done = true; break; case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: //进程内存超限 DEBUG_MSG(OJStr("[WindowsProcess]Process exceeded memory limit")); result_ = AppConfig::JudgeCode::MemoryLimitExceed; done = true; break; case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT: //job内存超限 { OJInt32_t mem = getRunMemory(); DebugMessage(OJStr("[WindowsProcess]exceeded job memory limit with %dkb"), mem); result_ = AppConfig::JudgeCode::MemoryLimitExceed; done = true; } break; case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: //超出运行的进程数量 DEBUG_MSG(OJStr("[WindowsProcess]Too many active processes in job")); result_ = AppConfig::JudgeCode::RuntimeError; done = true; break; case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: DEBUG_MSG(OJStr("[WindowsProcess]Job contains no active processes")); done = true; break; case JOB_OBJECT_MSG_EXIT_PROCESS: //进程退出 //DEBUG_MSG_VS(OJStr("[WindowsProcess]Process %u exit."), dwCode); if(::GetProcessId(processHandle_) == dwCode) { done = true; } break; case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: //进程异常结束 DEBUG_MSG(OJStr("[WindowsProcess]Process terminated abnormally")); result_ = AppConfig::JudgeCode::RuntimeError; done = true; break; default: DEBUG_MSG(OJStr("[WindowsProcess]Unknown notification")); result_ = AppConfig::JudgeCode::UnknownError; break; } } { FILETIME ftime, temp; ::GetProcessTimes(processHandle_, &temp, &temp, &temp, &ftime); ULARGE_INTEGER time2; time2.LowPart = ftime.dwLowDateTime; time2.HighPart = ftime.dwHighDateTime; runTime_ = time2.QuadPart / 10000; } { PROCESS_MEMORY_COUNTERS info; ::GetProcessMemoryInfo(processHandle_, &info, sizeof(info)); runMemory_ = info.PeakPagefileUsage; } while(!jobHandle_.terminate())//强制关闭作业 { DEBUG_MSG(OJStr("Terminate job faild!")); OJSleep(10); } alive_ = false;//进程结束 //正常退出。即不是超时等状况。 if(result_ == AppConfig::JudgeCode::Accept) { DWORD code = getExitCode();//获取进程返回值,以判断进程是否执行成功。 if(code != 0) { result_ = AppConfig::JudgeCode::RuntimeError; DEBUG_MSG_VS(OJStr("process exit with code : %u, last error: %u"), code, GetLastError()); } } SAFE_CLOSE_HANDLE_AND_RESET(processHandle_); return 0; }
int MprCmd::start(char *program, char **argv, char **envp, MprCmdProc fn, void *fnData, int userFlags) { char dir[MPR_MAX_FNAME]; int pid, i, err; mprAssert(program != 0); mprAssert(argv != 0); mprLog(4, log, "start: %s\n", program); reset(); flags |= (userFlags & MPR_CMD_USER_FLAGS); for (i = 0; argv[i]; i++) { mprLog(6, log, " arg[%d]: %s\n", i, argv[i]); } if (envp) { for (i = 0; envp[i]; i++) { mprLog(6, log, " envp[%d]: %s\n", i, envp[i]); } } if (access(program, X_OK) < 0) { mprLog(5, log, "start: can't access %s, errno %d\n", program, mprGetOsError()); return MPR_ERR_CANT_ACCESS; } data = fnData; cmdDoneProc = fn; reapIndex = -1; // // Create the child // pid = vfork(); if (pid < 0) { mprLog(0, log, "Can't fork a new process to run %s\n", program); return MPR_ERR_CANT_INITIALIZE; } else if (pid == 0) { // // Child // umask(022); if (flags & MPR_CMD_NEW_SESSION) { setsid(); } if (flags & MPR_CMD_CHDIR) { if (cwd) { chdir(cwd); } else { mprGetDirName(dir, sizeof(dir), program); chdir(dir); } } // // FUTURE -- could chroot as a security feature (perhaps cgi-bin) // if (files.clientFd[MPR_CMD_OUT] >= 0) { dup2(files.clientFd[MPR_CMD_OUT], 0); // Client stdin } else { close(0); } if (files.clientFd[MPR_CMD_IN] >= 0) { dup2(files.clientFd[MPR_CMD_IN], 1); // Client stdout dup2(files.clientFd[MPR_CMD_IN], 2); // Client stderr } else { close(1); close(2); } // // FUTURE -- need to get a better max file limit than this // for (i = 3; i < 128; i++) { close(i); } if (envp) { execve(program, argv, envp); } else { // // Do this rather than user execv to avoid errors in valgrind // char *env[2]; env[0] = "_appweb=1"; env[1] = 0; execve(program, argv, (char**) &env); } err = errno; getcwd(dir, sizeof(dir)); mprStaticPrintf("Can't exec %s, err %d, cwd %s\n", program, err, dir); mprAssert(0); exit(-(MPR_ERR_CANT_INITIALIZE)); } else { // // Close the client handles // for (i = 0; i < MPR_CMD_MAX_FD; i++) { if (files.clientFd[i] >= 0) { close(files.clientFd[i]); files.clientFd[i] = -1; } } data = fnData; cmdDoneProc = fn; process = (ulong) pid; if (flags & MPR_CMD_DETACHED) { process = 0; return 0; } else if (flags & MPR_CMD_WAIT) { waitForChild(INT_MAX); if (getExitCode() < 0) { return MPR_ERR_BAD_STATE; } return exitStatus; } else { mprGetMpr()->cmdService->startWatcher(); } } return 0; }
int MprCmd::start(char *program, char **argv, char **envp, MprCmdProc completionFn, void *fnData, int userFlags) { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; char dirBuf[MPR_MAX_FNAME], *systemRoot; char *envBuf, **ep, *cmdBuf, **ap, *destp, *cp, *dir, *key; char progBuf[MPR_MAX_STRING], *localArgv[2], *saveArg0; int argc, len, inheritFiles; mprAssert(program); mprAssert(argv); reset(); flags |= (userFlags & MPR_CMD_USER_FLAGS); exitStatus = -1; mprStrcpy(progBuf, sizeof(progBuf), program); progBuf[sizeof(progBuf) - 1] = '\0'; program = progBuf; // // Sanitize the command line (program name only) // for (cp = program; *cp; cp++) { if (*cp == '/') { *cp = '\\'; } else if (*cp == '\r' || *cp == '\n') { *cp = ' '; } } if (*program == '"') { if ((cp = strrchr(++program, '"')) != 0) { *cp = '\0'; } } saveArg0 = argv[0]; if (argv == 0) { argv = localArgv; argv[1] = 0; } argv[0] = program; // // Determine the command line length and arg count // argc = 0; for (len = 0, ap = argv; *ap; ap++) { len += strlen(*ap) + 1 + 2; // Space and possible quotes argc++; } cmdBuf = (char*) mprMalloc(len + 1); cmdBuf[len] = '\0'; // // Add quotes to all args that have spaces in them including "program" // destp = cmdBuf; for (ap = &argv[0]; *ap; ) { cp = *ap; if ((strchr(cp, ' ') != 0) && cp[0] != '\"') { *destp++ = '\"'; strcpy(destp, cp); destp += strlen(cp); *destp++ = '\"'; } else { strcpy(destp, cp); destp += strlen(cp); } if (*++ap) { *destp++ = ' '; } } *destp = '\0'; mprAssert((int) strlen(destp) < (len - 1)); mprAssert(cmdBuf[len] == '\0'); argv[0] = saveArg0; envBuf = 0; if (envp) { for (len = 0, ep = envp; *ep; ep++) { len += strlen(*ep) + 1; } key = "SYSTEMROOT"; systemRoot = getenv(key); if (systemRoot) { len += strlen(key) + 1 + strlen(systemRoot) + 1; } envBuf = (char*) mprMalloc(len + 2); // Win requires two nulls destp = envBuf; for (ep = envp; *ep; ep++) { strcpy(destp, *ep); mprLog(6, log, "Set CGI variable: %s\n", destp); destp += strlen(*ep) + 1; } strcpy(destp, key); destp += strlen(key); *destp++ = '='; strcpy(destp, systemRoot); destp += strlen(systemRoot) + 1; *destp++ = '\0'; *destp++ = '\0'; // WIN requires two nulls } memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; if (flags & MPR_CMD_SHOW) { startInfo.wShowWindow = SW_SHOW; } else { startInfo.wShowWindow = SW_HIDE; } // // CMD_OUT is stdin for the client. CMD_IN is stdout for the client // if (files.clientFd[MPR_CMD_OUT] > 0) { startInfo.hStdInput = (HANDLE) _get_osfhandle(files.clientFd[MPR_CMD_OUT]); } if (files.clientFd[MPR_CMD_IN] > 0) { startInfo.hStdOutput = (HANDLE)_get_osfhandle(files.clientFd[MPR_CMD_IN]); } #if UNUSED if (files.clientFd[MPR_CMD_ERR] > 0) { startInfo.hStdError = (HANDLE) _get_osfhandle(files.clientFd[MPR_CMD_ERR]); } #endif #if UNUSED SECURITY_ATTRIBUTES secAtt; memset(&secAtt, 0, sizeof(secAtt)); secAtt.nLength = sizeof(SECURITY_ATTRIBUTES); secAtt.bInheritHandle = TRUE; #endif if (userFlags & MPR_CMD_CHDIR) { if (cwd) { dir = cwd; } else { mprGetDirName(dirBuf, sizeof(dirBuf), argv[0]); dir = dirBuf; } } else { dir = 0; } inheritFiles = (flags & MPR_CMD_STDIO_MADE) ? 1 : 0; flags &= ~(MPR_CMD_STDIO_MADE); mprLog(5, log, "Running: %s\n", cmdBuf); if (! CreateProcess(0, cmdBuf, 0, 0, inheritFiles, CREATE_NEW_CONSOLE, envBuf, dir, &startInfo, &procInfo)) { mprError(MPR_L, MPR_LOG, "Can't create process: %s, %d", cmdBuf, mprGetOsError()); return MPR_ERR_CANT_CREATE; } process = (int) procInfo.hProcess; // // Wait for the child to initialize // WaitForInputIdle((HANDLE) process, 1000); if (procInfo.hThread != 0) { CloseHandle(procInfo.hThread); } mprFree(cmdBuf); mprFree(envBuf); cmdDoneProc = completionFn; data = fnData; if (flags & MPR_CMD_DETACHED) { CloseHandle((HANDLE) process); process = 0; } else if (userFlags & MPR_CMD_WAIT) { waitForChild(INT_MAX); if (getExitCode() < 0) { return MPR_ERR_BAD_STATE; } return exitStatus; } else { mprGetMpr()->cmdService->startWatcher(); } return 0; }