void limitMem( size_t limit ) { static HANDLE hJob = NULL; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo; jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024; if (NULL == hJob) { if (NULL == (hJob = CreateJobObject(NULL, NULL))) { REPORT("Can't assign create job object: %ld\n", GetLastError()); exit(1); } if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) { REPORT("Can't assign process to job object: %ld\n", GetLastError()); exit(1); } } if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) { REPORT("Can't set limits: %ld\n", GetLastError()); exit(1); } }
/* This could be interesting to expose in public API */ static void _g_test_watcher_add_pid (GPid pid) { static gsize started = 0; HANDLE job; if (g_once_init_enter (&started)) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; job = CreateJobObjectW (NULL, NULL); memset (&info, 0, sizeof (info)); info.BasicLimitInformation.LimitFlags = 0x2000 /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE */; if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof (info))) g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError())); g_once_init_leave (&started,(gsize)job); } job = (HANDLE)started; if (!AssignProcessToJobObject(job, pid)) g_warning ("Can't assign process to job: %s", g_win32_error_message (GetLastError())); }
void CJobObject::AssignProcess(CProcess& Process) { BOOL bRet; CMutex::CEnter MutexEnter(m_Mutex); bRet = AssignProcessToJobObject(GetHandle(), Process.GetHandle()); if (bRet == 0) { throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__); } }
/// <summary> /// Creates a console object and starts the child process </summary> /// /// <param name="ac"> /// Uninitialized console object </param> /// <param name="tzClientPath"> /// Path to client, in an inject environment this should not be relative </param> /// /// <returns> /// If child could be created </returns> BOOL ImAllocConsole(OUT IM_CONSOLE* ac, IN const TCHAR* tzClientPath) { SecureZeroMemory(ac->tzClientPipe, MAX_NAME); // generate a random name (tmpnam has a forward slash and is not necessarily alphanumeric) for (register size_t i = 0; i < rand() % MAX_NAME; ++i) { ac->tzClientPipe[i] = rand() % 26 + 'A'; // make random letter ac->tzClientPipe[i] ^= rand() % 1 << 5; // randomly toggle 0x20 (upper/lowercase) } { // create job object and set information JOBOBJECT_EXTENDED_LIMIT_INFORMATION joELI; ac->hJob = CreateJobObject(NULL, ac->tzClientPipe); if (ac->hJob == NULL) return FALSE; joELI.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if(!SetInformationJobObject(ac->hJob, JobObjectExtendedLimitInformation, &joELI, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } } { // create child process SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; // sa.lpSecurityDescriptor = NULL; if (!CreatePipe(&ac->hRead, &ac->hWrite, &sa, BUFSIZ)) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } STARTUPINFO siCon = {0}; PROCESS_INFORMATION piCon = {0}; siCon.cb = sizeof(siCon); siCon.hStdInput = ac->hRead; siCon.dwFlags |= STARTF_USESTDHANDLES; if (!CreateProcess(tzClientPath, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &siCon, &piCon)) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } DuplicateHandle(GetCurrentProcess(), piCon.hProcess, GetCurrentProcess(), &ac->hChildProcess, 0, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(piCon.hThread); CloseHandle(piCon.hProcess); } return AssignProcessToJobObject(ac->hJob, ac->hChildProcess); }
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { AttachConsole(ATTACH_PARENT_PROCESS); // Create a named pipe that we can be signaled on for early termination wchar_t buf[512]; wsprintf(buf, L"\\\\.\\pipe\\jobber-%d", GetCurrentProcessId()); HANDLE hPipe = CreateNamedPipe(buf, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 256, 256, 100000, NULL); OVERLAPPED io = { 0 }; io.hEvent = CreateEvent(NULL, true, true, NULL); if (!ConnectNamedPipe(hPipe, &io) && GetLastError() != ERROR_IO_PENDING) { DWORD dwLastError = GetLastError(); return -1; } STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; si.cb = sizeof(STARTUPINFO); si.wShowWindow = nCmdShow; if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, true, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { DWORD dwLastError = GetLastError(); return -1; } HANDLE hJob = CreateJobObject(NULL, NULL); AssignProcessToJobObject(hJob, pi.hProcess); ResumeThread(pi.hThread); HANDLE handles[2]; handles[0] = io.hEvent; handles[1] = pi.hProcess; int result = WaitForMultipleObjects(2, handles, false, INFINITE); TerminateJobObject(hJob, -1); if (result == WAIT_OBJECT_0) { return -1; } else { DWORD dwExit; GetExitCodeProcess(pi.hProcess, &dwExit); return dwExit; } }
int ActivePet::launch(std::wstring exePath, std::wstring originalDocPath){ wchar_t commandLine[4096] = { '\0' }; if (originalDocPath != L"") { // Build the command line. std::wstring editableDocPath = edit(originalDocPath); wcscat(commandLine, L"\""); wcscat(commandLine, exePath.c_str()); wcscat(commandLine, L"\" \""); wcscat(commandLine, editableDocPath.c_str()); wcscat(commandLine, L"\""); } auto_close<void*, &::DestroyEnvironmentBlock> environment(NULL); if (!CreateEnvironmentBlock(&environment, m_session.get(), FALSE)) { printf("CreateEnvironmentBlock() failed: %d", GetLastError()); return -30; } STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi = {}; if (!CreateProcessAsUser(m_session.get(), exePath.c_str(), commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, environment.get(), NULL, // lpCurrentDirectory, &si, &pi)) { printf("CreateProcessAsUser() failed: %d", GetLastError()); return -30; } if (!AssignProcessToJobObject(m_job.get(), pi.hProcess)) { printf("AssignProcessToJobObject() failed: %d", GetLastError()); return -30; } if (!ResumeThread(pi.hThread)) { printf("ResumeThread() failed: %d", GetLastError()); return -30; } if (WaitForInputIdle(pi.hProcess, INFINITE) != ERROR_SUCCESS) { printf("WaitForInputIdle() failed: %d", GetLastError()); return -30; } InjectAndCall(pi.hProcess, "ApplyHooks", 10000); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; }
void Job::assignMainProcess(const Process &process) { hMainProcess = process.processHandle(); tryApi(_T("AssignProcessToJobObject"), AssignProcessToJobObject(hJob,hMainProcess) != 0); gatherInfo(); initialElapsedTimeCounter = elapsedTimeCounter.getLargeValue(); millisecondsIdle = 0; prevJobTime = -1; prevElapsedTime = -1; res = JobResult(); jobactive = true; }
int main( int argc , char* argv[] ) { #if defined(WIN32) && defined(MAX_MEMORY_GB) if( MAX_MEMORY_GB>0 ) { SIZE_T peakMemory = 1; peakMemory <<= 30; peakMemory *= MAX_MEMORY_GB; printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); HANDLE h = CreateJobObject( NULL , NULL ); AssignProcessToJobObject( h , GetCurrentProcess() ); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; jeli.JobMemoryLimit = peakMemory; if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) fprintf( stderr , "Failed to set memory limit\n" ); }
void mpk_import_create_process(mpk_import_command_line *cmdl, HANDLE process_group, memory_arena *memory_arena) { m_memory_arena_undo_allocations_at_scope_exit(memory_arena); STARTUPINFO su_info = { sizeof(su_info) }; su_info.dwFlags = STARTF_USESHOWWINDOW; su_info.wShowWindow = SW_HIDE; PROCESS_INFORMATION ps_info; int n = snprintf(nullptr, 0, m_mpk_import_command_line_parse_str, m_mpk_import_command_line_snprintf_unpack(cmdl)); char *cmdl_str = memory_arena_allocate<char>(memory_arena, n + 1); snprintf(cmdl_str, n + 1, m_mpk_import_command_line_parse_str, m_mpk_import_command_line_snprintf_unpack(cmdl)); if (!CreateProcessA("mpk_import.exe", cmdl_str, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &su_info, &ps_info)) { m_last_error_str(err); m_die("cannot create new mpk import process, %s", err); } if (!AssignProcessToJobObject(process_group, ps_info.hProcess)) { m_last_error_str(err); m_die("cannot assign new mpk import process to process group, %s", err); } CloseHandle(ps_info.hProcess); }
void runner::set_allow_breakaway(bool allow) { if (allow_breakaway == allow) { return; } if (main_job_object == handle_default_value) { main_job_object = CreateJobObject(NULL, NULL); AssignProcessToJobObject(main_job_object, GetCurrentProcess()); } JOBOBJECT_EXTENDED_LIMIT_INFORMATION extended_limit_information; memset(&extended_limit_information, 0, sizeof(extended_limit_information)); if (allow) { extended_limit_information.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } if (!SetInformationJobObject(main_job_object, JobObjectExtendedLimitInformation, &extended_limit_information, sizeof(extended_limit_information))) { DWORD le = GetLastError(); return; } allow_breakaway = allow; }
HANDLE create_child_process(const char *cmd) { PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {sizeof(si)}; hJOB = CreateJobObject(NULL, NULL); if(!hJOB) { return NULL; } /*JOBOBJECT_SECURITY_LIMIT_INFORMATION security_info = {0}; security_info.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN; if(!SetInformationJobObject(hJOB, JobObjectSecurityLimitInformation, &security_info, sizeof security_info)) { CloseHandle(hJOB); return NULL; }*/ freopen("err.out", "w", stderr); freopen("cmpr.out", "w", stdout); BOOL bSuccess = CreateProcess(NULL, (LPSTR)(void*)cmd, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); if(!bSuccess) { CloseHandle(hJOB); return NULL; } if(!AssignProcessToJobObject(hJOB, pi.hProcess)) { CloseHandle(hJOB); CloseHandle(pi.hThread); TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); return NULL; } if(-1 == ResumeThread(pi.hThread)) { CloseHandle(hJOB); CloseHandle(pi.hThread); TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); return NULL; } CloseHandle(pi.hThread); return pi.hProcess; }
/* 结束进程方案2 TerminateJobObject */ BOOL KillProcessMethod_2(DWORD dwProcessID) { BOOL bRet; HANDLE hProcess, hJob; hProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessID); if (hProcess == NULL) { return FALSE; } hJob = CreateJobObject(NULL, _T("TestJob")); if (!AssignProcessToJobObject(hJob, hProcess)) { return FALSE; } bRet = TerminateJobObject(hJob, 0); CloseHandle(hProcess); CloseHandle(hJob); return bRet; }
bool JobObject::addProcessToJob(const QProcess *proc) { if(!m_hJobObject) { qWarning("Cannot assign process to job: No job bject available!"); return false; } if(Q_PID pid = proc->pid()) { DWORD exitCode; if(!GetExitCodeProcess(pid->hProcess, &exitCode)) { qWarning("Cannot assign process to job: Failed to query process status!"); return false; } if(exitCode != STILL_ACTIVE) { qWarning("Cannot assign process to job: Process is not running anymore!"); return false; } if(!AssignProcessToJobObject(m_hJobObject, pid->hProcess)) { qWarning("Failed to assign process to job object!"); return false; } return true; } else { qWarning("Cannot assign process to job: Process handle not available!"); return false; } }
bool WindowsJob::assinProcess(HANDLE handel) { return !!AssignProcessToJobObject(jobHandle_, handel); }
void EngineProcess::start(const QString& program, const QStringList& arguments, OpenMode mode) { if (m_started) close(); m_started = false; m_finished = false; m_exitCode = 0; m_exitStatus = NormalExit; m_errRead = createFile(m_stdErrFile, m_stdErrFileMode); // Temporary handles for the child process' end of the pipes HANDLE outWrite; HANDLE inRead; // Security attributes. Use the same one for both pipes. SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; CreatePipe(&m_outRead, &outWrite, &saAttr, 0); CreatePipe(&inRead, &m_inWrite, &saAttr, 0); STARTUPINFO startupInfo; ZeroMemory(&startupInfo, sizeof(startupInfo)); startupInfo.cb = sizeof(startupInfo); startupInfo.hStdError = m_errRead; startupInfo.hStdOutput = outWrite; startupInfo.hStdInput = inRead; startupInfo.dwFlags |= STARTF_USESTDHANDLES; // Call DuplicateHandle with a NULL target to get non-inheritable // handles for the parent process' ends of the pipes DuplicateHandle(GetCurrentProcess(), m_outRead, // child's stdout read end GetCurrentProcess(), NULL, // no target 0, // flags FALSE, // not inheritable DUPLICATE_SAME_ACCESS); // same handle access DuplicateHandle(GetCurrentProcess(), m_inWrite, // child's stdin write end GetCurrentProcess(), NULL, // no target 0, // flags FALSE, // not inheritable DUPLICATE_SAME_ACCESS); // same handle access BOOL ok = FALSE; QString cmd = cmdLine(m_workDir, program, arguments); QString wdir = QDir::toNativeSeparators(m_workDir); ZeroMemory(&m_processInfo, sizeof(m_processInfo)); #ifdef UNICODE ok = CreateProcessW(NULL, (WCHAR*)cmd.utf16(), NULL, // process attributes NULL, // thread attributes TRUE, // inherit handles CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, // creation flags NULL, // environment wdir.isEmpty() ? NULL : (WCHAR*)wdir.utf16(), &startupInfo, &m_processInfo); #else // not UNICODE ok = CreateProcessA(NULL, cmd.toLocal8Bit().data(), NULL, // process attributes NULL, // thread attributes TRUE, // inherit handles CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, // creation flags NULL, // environment wdir.isEmpty() ? NULL : wdir.toLocal8Bit().data(), &startupInfo, &m_processInfo); #endif // not UNICODE m_started = (bool)ok; if (ok) { // Assign the engine process to the main job to make sure it's // terminated when CuteChess terminates. AssignProcessToJobObject(mainJob(), m_processInfo.hProcess); // Close the child process' ends of the pipes to make sure // that ReadFile and WriteFile will return when the child // terminates and closes its pipes killHandle(&outWrite); killHandle(&inRead); killHandle(&m_processInfo.hThread); // Start reading input from the child m_reader = new PipeReader(m_outRead, this); connect(m_reader, SIGNAL(finished()), this, SLOT(onFinished())); connect(m_reader, SIGNAL(finished()), this, SIGNAL(readChannelFinished())); connect(m_reader, SIGNAL(readyRead()), this, SIGNAL(readyRead())); m_reader->start(); // Make QIODevice aware that the device is now open QIODevice::open(mode); } else cleanup(); }
static intptr_t do_spawnv(rktio_t *rktio, const char *command, int argc, const char * const *argv, int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid, int new_process_group, int chain_termination_here_to_child, void *env, const char *wd) { intptr_t i, l, len = 0; int use_jo; intptr_t cr_flag; char *cmdline; wchar_t *cmdline_w, *wd_w, *command_w; STARTUPINFOW startup; PROCESS_INFORMATION info; if (exact_cmdline) { cmdline = (char *)argv[1]; } else { for (i = 0; i < argc; i++) { len += strlen(argv[i]) + 1; } cmdline = malloc(len); len = 0; for (i = 0; i < argc; i++) { l = strlen(argv[i]); memcpy(cmdline + len, argv[i], l); cmdline[len + l] = ' '; len += l + 1; } --len; cmdline[len] = 0; } memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESTDHANDLES; startup.hStdInput = (HANDLE)sin; startup.hStdOutput = (HANDLE)sout; startup.hStdError = (HANDLE)serr; /* If none of the stdio handles are consoles, specifically create the subprocess without a console: */ if (!rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdInput) && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdOutput) && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdError)) cr_flag = CREATE_NO_WINDOW; else cr_flag = 0; if (new_process_group) cr_flag |= CREATE_NEW_PROCESS_GROUP; cr_flag |= CREATE_UNICODE_ENVIRONMENT; use_jo = chain_termination_here_to_child; if (use_jo) { /* Use a job object to ensure that the new process will be terminated if this process ends for any reason (including a crash) */ if (!rktio->process_job_object) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; rktio->process_job_object = CreateJobObject(NULL, NULL); memset(&jeli, 0, sizeof(jeli)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(rktio->process_job_object, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); } } cmdline_w = WIDE_PATH_copy(cmdline); if (!exact_cmdline) free(cmdline); wd_w = WIDE_PATH_copy(wd); command_w = WIDE_PATH_temp(command); if (cmdline_w && wd_w && command_w && CreateProcessW(command_w, cmdline_w, NULL, NULL, 1 /*inherit*/, cr_flag, env, wd_w, &startup, &info)) { if (use_jo) AssignProcessToJobObject(rktio->process_job_object, info.hProcess); CloseHandle(info.hThread); *pid = info.dwProcessId; free(cmdline_w); free(wd_w); return (intptr_t)info.hProcess; } else { if (cmdline_w) free(cmdline_w); if (wd_w) free(wd_w); return -1; } }
BOOL CreateBuilderProcess(HANDLE job, PCTSTR appName, PTSTR cmdLine, PCTSTR workDir, H2BOperation& op) { BOOL ret = TRUE; DWORD err = ERROR_SUCCESS; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; if( CreateProcess(appName, cmdLine, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB , NULL, workDir, &si, &pi) ) { HANDLE openProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pi.dwProcessId); if( openProc ) { if( AssignProcessToJobObject(job, openProc) ) { if( (int) ResumeThread(pi.hThread) != -1 ) { DWORD wait = ERROR_TIMEOUT; const DWORD waitStep = 200; op.SetStatusMessageDescription(_T("Esse processo pode demorar vários ") _T("minutos, dependendo da velocidade de seu computador.")); for( DWORD i = 0; i * waitStep < BAB_BUILD_TIMEOUT; ++i ) { wait = WaitForSingleObject(openProc, waitStep); if( wait == WAIT_OBJECT_0 ) break; else if( op.Cancel() ) { err = ERROR_CANCELLED; break; } } if( err == ERROR_CANCELLED ) { Log("Babylon builder process cancellation."); } else if( wait == WAIT_OBJECT_0 ) { GetExitCodeProcess(openProc, &err); Log("Babylon builder process return: %d", err); } else { err = ERROR_TIMEOUT; Log("Babylon builder timeout"); } } else { err = GetLastError(); Log("Error resuming builder process"); } } else { err = GetLastError(); Log("Error assigning builder process to job"); TerminateProcess(openProc, -1); } CloseHandle(openProc); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { err = GetLastError(); Log("Error creating Babylon Builder process"); } if( err != ERROR_SUCCESS ) { SetLastError(err); ret = FALSE; } return ret; }
BOOL Go(const char *commandLine) { HANDLE stdInRead, stdInWrite; if (!CreatePipes(&stdInRead, &stdInWrite)) return FALSE; PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bSuccess = FALSE; ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); siStartInfo.hStdInput = stdInRead; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; siStartInfo.wShowWindow = SW_HIDE; siStartInfo.dwFlags |= STARTF_USESHOWWINDOW; // Create the child process. if (!CreateProcess(NULL, const_cast<char *>(commandLine), // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited CREATE_BREAKAWAY_FROM_JOB, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo)) // receives PROCESS_INFORMATION { return FALSE; } HANDLE ghJob = CreateJobObject( NULL, NULL); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if( ghJob == NULL || SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == FALSE) { std::cerr << "Error initializing close-process job"; return 1; } if (!AssignProcessToJobObject( ghJob, piProcInfo.hProcess)) { DWORD error = GetLastError(); std::cerr << "AssignProcessToJobObject failed: " << error << std::endl; return FALSE; } // Close handles to the child process and its primary thread. // Some applications might keep these handles to monitor the status // of the child process, for example. CloseHandle(piProcInfo.hThread); MonitorProcessClose(piProcInfo.hProcess); WriteToPipe(stdInWrite, piProcInfo.hProcess); CloseHandle(piProcInfo.hProcess); CloseHandle(stdInRead); CloseHandle(stdInWrite); return 0; }
int main(){ DWORD exit_code, terminated; STARTUPINFO child_1_si; STARTUPINFO child_2_si; PROCESS_INFORMATION child_1_pi; PROCESS_INFORMATION child_2_pi; HANDLE job_handle = CreateJobObject(NULL, "job"); memset(&child_1_si, 0, sizeof(STARTUPINFO)); child_1_si.cb=sizeof(child_1_si); memset(&child_2_si, 0, sizeof(STARTUPINFO)); child_2_si.cb=sizeof(child_2_si); get_warning_alert("\nTrying to create the first child process..."); DWORD child_1_created = CreateProcess(NULL, "child.exe ChildOne GrandChildOne", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &child_1_si, &child_1_pi); if(!child_1_created){ get_error_alert("\nError on creating process / code #%ld", GetLastError()); exit(1); } get_success_alert("\nProcess created!"); get_warning_alert("\nTrying to create the second child process..."); DWORD child_2_created = CreateProcess(NULL, "child.exe ChildTwo GrandChildTwo", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &child_2_si, &child_2_pi); if(!child_2_created){ get_error_alert("\nError on creating process / code #%ld", GetLastError()); exit(1); } get_success_alert("\nProcess created!"); AssignProcessToJobObject(job_handle, child_2_pi.hProcess); for(int i = 0; i <= 20; i++){ get_error_alert("Parent: "); printf("on step %d\n", i); if(i == 7) { GetExitCodeProcess(child_1_pi.hProcess, &exit_code); terminated = TerminateProcess(child_1_pi.hProcess, (UINT) exit_code); if(!terminated) { get_error_alert("\nTerminating error %d\n", GetLastError()); } else { get_success_alert("\nThe first child process terminated\n"); } } if(i == 10) { GetExitCodeProcess(job_handle, &exit_code); terminated = TerminateJobObject(job_handle, (UINT) exit_code); if(!terminated) { get_error_alert("\nJob terminating error %d\n", GetLastError()); } else { get_success_alert("\nJob terminated\n"); } } Sleep(3000); } return 0; }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { int i; int err = 0; WCHAR* path = NULL, *alloc_path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; uv_process_init(loop, process); process->exit_cb = options->exit_cb; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { return UV_ENOTSUP; } if (options->file == NULL || options->args == NULL) { return UV_EINVAL; } if (options->cpumask != NULL) { if (options->cpumask_size < (size_t)uv_cpumask_size()) { return UV_EINVAL; } } assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); err = uv_utf8_to_utf16_alloc(options->file, &application); if (err) goto done; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err) goto done; if (options->env) { err = make_program_env(options->env, &env); if (err) goto done; } if (options->cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); if (err) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = GetLastError(); goto done; } cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = ERROR_OUTOFMEMORY; goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = GetLastError(); goto done; } } /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = GetLastError(); goto done; } alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); if (alloc_path == NULL) { err = ERROR_OUTOFMEMORY; goto done; } path = alloc_path; r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = GetLastError(); goto done; } } err = uv__stdio_create(loop, options, &process->child_stdio_buffer); if (err) goto done; application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = ERROR_FILE_NOT_FOUND; goto done; } startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); process_flags = CREATE_UNICODE_ENVIRONMENT; if (options->flags & UV_PROCESS_WINDOWS_HIDE) { /* Avoid creating console window if stdio is not inherited. */ for (i = 0; i < options->stdio_count; i++) { if (options->stdio[i].flags & UV_INHERIT_FD) break; if (i == options->stdio_count - 1) process_flags |= CREATE_NO_WINDOW; } /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { startup.wShowWindow = SW_SHOWDEFAULT; } if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That * means that libuv might not let you create a fully daemonized process * when run under job control. However the type of job control that libuv * itself creates doesn't trickle down to subprocesses so they can still * daemonize. * * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the * CreateProcess call fail if we're under job control that doesn't allow * breakaway. */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (options->cpumask != NULL) { /* Create the child in a suspended state so we have a chance to set its process affinity before it runs. */ process_flags |= CREATE_SUSPENDED; } if (!CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* CreateProcessW failed. */ err = GetLastError(); goto done; } if (options->cpumask != NULL) { /* The child is currently suspended. Set its process affinity or terminate it if we can't. */ int i; int cpumasksize; DWORD_PTR sysmask; DWORD_PTR oldmask; DWORD_PTR newmask; cpumasksize = uv_cpumask_size(); if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } newmask = 0; for (i = 0; i < cpumasksize; i++) { if (options->cpumask[i]) { if (oldmask & (((DWORD_PTR)1) << i)) { newmask |= ((DWORD_PTR)1) << i; } else { err = UV_EINVAL; TerminateProcess(info.hProcess, 1); goto done; } } } if (!SetProcessAffinityMask(info.hProcess, newmask)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } /* The process affinity of the child is set. Let it run. */ if (ResumeThread(info.hThread) == ((DWORD)-1)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } } /* Spawn succeeded */ /* Beyond this point, failure is reported asynchronously. */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* If the process isn't spawned as detached, assign to the global job */ /* object so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { /* AssignProcessToJobObject might fail if this process is under job * control and the job doesn't have the * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version * that doesn't support nested jobs. * * When that happens we just swallow the error and continue without * establishing a kill-child-on-parent-exit relationship, otherwise * there would be no way for libuv applications run under job control * to spawn processes at all. */ DWORD err = GetLastError(); if (err != ERROR_ACCESS_DENIED) uv_fatal_error(err, "AssignProcessToJobObject"); } } /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options->stdio_count; i++) { const uv_stdio_container_t* fdopt = &options->stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject(&process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); assert(!err); /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ done: uv__free(application); uv__free(application_path); uv__free(arguments); uv__free(cwd); uv__free(env); uv__free(alloc_path); if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } return uv_translate_sys_error(err); }
apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, fcgid_procnode *procnode) { HANDLE *finish_event, listen_handle; SECURITY_ATTRIBUTES SecurityAttributes; fcgid_server_conf *sconf; apr_procattr_t *proc_attr; apr_status_t rv; apr_file_t *file; const char * const *proc_environ; char sock_path[FCGID_PATH_MAX]; int argc; char const * wargv[APACHE_ARG_MAX + 1], *word; /* For wrapper */ const char *tmp; /* Build wrapper args */ argc = 0; tmp = cmdline; while (1) { word = ap_getword_white(procnode->proc_pool, &tmp); if (word == NULL || *word == '\0') break; if (argc >= APACHE_ARG_MAX) break; wargv[argc++] = word; } wargv[argc] = NULL; memset(&SecurityAttributes, 0, sizeof(SecurityAttributes)); /* Prepare finish event */ finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE)); *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (*finish_event == NULL || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE)) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create mutex for subprocess"); return APR_ENOLOCK; } apr_pool_cleanup_register(procnode->proc_pool, finish_event, close_finish_event, apr_pool_cleanup_null); /* For proc_kill_gracefully() */ apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME, NULL, procnode->proc_pool); /* Pass the finish event id to subprocess */ apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME, apr_ltoa(procnode->proc_pool, (long) *finish_event)); /* Prepare the listen namedpipe file name (no check for truncation) */ apr_snprintf(sock_path, sizeof sock_path, "\\\\.\\pipe\\fcgidpipe-%lu.%d", GetCurrentProcessId(), g_process_counter++); /* Prepare the listen namedpipe handle */ SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; listen_handle = CreateNamedPipe(sock_path, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192, 0, &SecurityAttributes); if (listen_handle == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create namedpipe for subprocess"); return APR_ENOSOCKET; } apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path)); apr_cpystrn(procnode->executable_path, wargv[0], sizeof(procnode->executable_path)); /* Build environment variables */ proc_environ = (const char * const *) ap_create_environment(procnode->proc_pool, procinfo->proc_environ); if (!proc_environ) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't build environment variables"); return APR_ENOMEM; } /* Create process now */ if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_dir_set(proc_attr, ap_make_dirstr_parent(procnode->proc_pool, wargv[0]))) != APR_SUCCESS || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM)) != APR_SUCCESS || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE, APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS || (rv = apr_os_file_put(&file, &listen_handle, 0, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_child_in_set(proc_attr, file, NULL)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, "mod_fcgid: can't create FastCGI process attribute"); CloseHandle(listen_handle); return APR_ENOPROC; } /* fork and exec now */ rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, proc_environ, proc_attr, procnode->proc_pool); /* OK, I created the process, now put it back to idle list */ CloseHandle(listen_handle); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, "mod_fcgid: can't run %s", wargv[0]); return rv; } /* FcgidWin32PreventOrphans feature */ sconf = ap_get_module_config(procinfo->main_server->module_config, &fcgid_module); if (sconf->hJobObjectForAutoCleanup != NULL) { /* Associate cgi process to current process */ if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup, procnode->proc_id.hproc) == 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: unable to assign child process to " "job object"); } } return APR_SUCCESS; }
static void run_child(wchar_t * cmdline) { HANDLE job; JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; DWORD rc; BOOL ok; STARTUPINFOW si; PROCESS_INFORMATION pi; #if defined(_WINDOWS) // When explorer launches a Windows (GUI) application, it displays // the "app starting" (the "pointer + hourglass") cursor for a number // of seconds, or until the app does something UI-ish (eg, creating a // window, or fetching a message). As this launcher doesn't do this // directly, that cursor remains even after the child process does these // things. We avoid that by doing a simple post+get message. // See http://bugs.python.org/issue17290 and // https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running MSG msg; PostMessage(0, 0, 0, 0); GetMessage(&msg, 0, 0, 0); #endif job = CreateJobObject(NULL, NULL); ok = QueryInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info), &rc); if (!ok || (rc != sizeof(info)) || !job) error(RC_CREATE_PROCESS, L"Job information querying failed"); info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; ok = SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info)); if (!ok) error(RC_CREATE_PROCESS, L"Job information setting failed"); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ok = safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput); if (!ok) error(RC_NO_STD_HANDLES, L"stdin duplication failed"); ok = safe_duplicate_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput); if (!ok) error(RC_NO_STD_HANDLES, L"stdout duplication failed"); ok = safe_duplicate_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError); if (!ok) error(RC_NO_STD_HANDLES, L"stderr duplication failed"); ok = SetConsoleCtrlHandler(ctrl_c_handler, TRUE); if (!ok) error(RC_CREATE_PROCESS, L"control handler setting failed"); si.dwFlags = STARTF_USESTDHANDLES; ok = CreateProcessW(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (!ok) error(RC_CREATE_PROCESS, L"Unable to create process using '%ls'", cmdline); AssignProcessToJobObject(job, pi.hProcess); CloseHandle(pi.hThread); WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE); ok = GetExitCodeProcess(pi.hProcess, &rc); if (!ok) error(RC_CREATE_PROCESS, L"Failed to get exit code of process"); exit(rc); }
bool LaunchProcess(const string16& cmdline, const LaunchOptions& options, ProcessHandle* process_handle) { STARTUPINFO startup_info = {}; startup_info.cb = sizeof(startup_info); if(options.empty_desktop_name) { startup_info.lpDesktop = L""; } startup_info.dwFlags = STARTF_USESHOWWINDOW; startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; PROCESS_INFORMATION process_info; DWORD flags = 0; if(options.job_handle) { flags |= CREATE_SUSPENDED; // If this code is run under a debugger, the launched process is // automatically associated with a job object created by the debugger. // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. flags |= CREATE_BREAKAWAY_FROM_JOB; } if(options.as_user) { flags |= CREATE_UNICODE_ENVIRONMENT; void* enviroment_block = NULL; if(!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { return false; } BOOL launched = CreateProcessAsUser(options.as_user, NULL, const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, options.inherit_handles, flags, enviroment_block, NULL, &startup_info, &process_info); DestroyEnvironmentBlock(enviroment_block); if(!launched) { return false; } } else { if(!CreateProcess(NULL, const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, options.inherit_handles, flags, NULL, NULL, &startup_info, &process_info)) { return false; } } if(options.job_handle) { if(0 == AssignProcessToJobObject(options.job_handle, process_info.hProcess)) { LOG(ERROR) << "Could not AssignProcessToObject."; KillProcess(process_info.hProcess, kProcessKilledExitCode, true); return false; } ResumeThread(process_info.hThread); } // Handles must be closed or they will leak. CloseHandle(process_info.hThread); if(options.wait) { WaitForSingleObject(process_info.hProcess, INFINITE); } // If the caller wants the process handle, we won't close it. if(process_handle) { *process_handle = process_info.hProcess; } else { CloseHandle(process_info.hProcess); } return true; }
bool AI::init(int engine) { bool engine_started = false; bool b64bit = isOS64Bit(); bool jobSuccess = false; m_engine = engine; memset(m_engine_path, 0, sizeof(m_engine_path)); // set up the security attributes m_sa.bInheritHandle = true; m_sa.lpSecurityDescriptor = NULL; m_sa.nLength = sizeof(SECURITY_ATTRIBUTES); // setup job to kill the child process when calling process terminates m_hJob = CreateJobObject(NULL, NULL); if(m_hJob != NULL){ m_jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; jobSuccess = SetInformationJobObject(m_hJob, JobObjectExtendedLimitInformation, &m_jeli, sizeof(m_jeli)); } // open a pipe to the AI engine if(!CreatePipe(&m_child_stdin, &m_hWrite, &m_sa, 0)){ throw std::runtime_error("CreatePipe - stdin"); return false; } if(!CreatePipe(&m_hRead, &m_child_stdout, &m_sa, 0)){ throw std::runtime_error("CreatePipe - stdout"); cleanup(); return false; } // prepare to launch the process GetStartupInfo(&m_si); m_si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; m_si.wShowWindow = SW_HIDE; m_si.hStdOutput = m_child_stdout; m_si.hStdError = m_child_stdout; m_si.hStdInput = m_child_stdin; for(;!engine_started;){ switch(m_engine){ case ENGINE_HOUDINI: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Houdini_x64.exe"); checkProcess("Houdini_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Houdini_x86.exe"); checkProcess("Houdini_x86.exe"); } break; case ENGINE_STOCKFISH: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Stockfish_x64.exe"); checkProcess("Stockfish_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Stockfish_x86.exe"); checkProcess("Stockfish_x86.exe"); } break; case ENGINE_CRITTER: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Critter_x64.exe"); checkProcess("Critter_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Critter_x86.exe"); checkProcess("Critter_x86.exe"); } break; case ENGINE_CUSTOM: strcpy(m_engine_path, "Data/Engines/Custom.exe"); break; default: throw std::runtime_error("No valid engine found"); cleanup(); return false; } // attempt to launch the process engine_started = CreateProcess(m_engine_path, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &m_si, &m_pi); if(!engine_started){ if(engine > 0) engine = 0; else ++engine; continue; } break; } // assign the job to the process if(jobSuccess){ jobSuccess = AssignProcessToJobObject(m_hJob, m_pi.hProcess); } // change states //m_active = true; //m_thinking = true; // set process priority to below normal to prevent destruction of the CPU SetPriorityClass(m_pi.hProcess, BELOW_NORMAL_PRIORITY_CLASS); // set AI to active if(engine_started){ m_active = true; // start the state machine thread (void)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&InitThread, this, 0, 0); } return true; }
int main(int argc, char** argv) { enum { envbufsize = 1024*32 ,exebufsize = 1024 ,cmdbufsize = envbufsize }; char *envbuf, *sep, *resbuf, *cmdbuf; DWORD len, exitCode; STARTUPINFO si; PROCESS_INFORMATION pi; DIE_IF_FALSE( (envbuf = malloc(envbufsize)) ); DIE_IF_FALSE( (cmdbuf = malloc(cmdbufsize)) ); *cmdbuf = 0; DIE_IF_FALSE( GetEnvironmentVariable("PATH", envbuf, envbufsize) ); dbg_printf("env: %s\n", envbuf); DIE_IF_FALSE( GetModuleFileName(0, cmdbuf, exebufsize) ); dbg_printf("curdir: %s\n", cmdbuf); DIE_IF_FALSE( (sep = strrchr(cmdbuf, '\\')) ); *(sep+1) = 0; strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR); dbg_printf("sep: %s\n", cmdbuf); len = strlen(envbuf)+strlen(cmdbuf) +1 /* for envronment separator */ +1; /* for zero-terminator */ DIE_IF_FALSE( (resbuf = malloc(len)) ); DIE_IF_FALSE( (snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0) ); dbg_printf("PATH: %s\n", resbuf); DIE_IF_FALSE( SetEnvironmentVariable("PATH", resbuf) ); *(sep+1) = 0; strcat(cmdbuf, PYTHONHOME_REL_DIR); dbg_printf("PYTHONHOME: %s\n", cmdbuf); DIE_IF_FALSE( SetEnvironmentVariable("PYTHONHOME", cmdbuf) ); *(sep+1) = 0; strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" "); if ( argc > 1 ) { for ( ++argv; *argv; ++argv ) { len = strlen(cmdbuf); snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv); } } dbg_printf("cmd: %s\n", cmdbuf); HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/); if ( ghJob == NULL ) { dbg_printf("Could not create job object\n"); } else { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; // Configure all child processes associated with the job to terminate when the last handle to the job is closed jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) { dbg_printf("Could not SetInformationJobObject\n"); } } memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); memset(&pi, 0, sizeof(pi)); DIE_IF_FALSE( CreateProcess( 0 // exe name ,cmdbuf // command line ,0 // process security attributes ,0 // primary thread security attributes ,TRUE // handles are inherited ,0 // creation flags ,0 // use parent's environment ,0 // use parent's current directory ,&si // STARTUPINFO pointer ,&pi // receives PROCESS_INFORMATION ) ); if ( ghJob != NULL && AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) { dbg_printf("Could not AssignProcessToObject\n"); } // Do not handle Ctrl-C in the wrapper SetConsoleCtrlHandler(NULL, TRUE); WaitForSingleObject(pi.hProcess, INFINITE); DIE_IF_FALSE( GetExitCodeProcess(pi.hProcess, &exitCode) ); if ( ghJob != NULL ) CloseHandle(ghJob); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); free(envbuf); free(resbuf); free(cmdbuf); dbg_printf("exiting with exitCode %d", exitCode); return exitCode; }
/****************************************************************************** * * * Function: zbx_waitpid * * * * Purpose: this function waits for process to change state * * * * Parameters: pid - [IN] child process PID * * * * Return value: on success, PID is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * ******************************************************************************/ static int zbx_waitpid(pid_t pid) { const char *__function_name = "zbx_waitpid"; int rc, status; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); do { #ifdef WCONTINUED static int wcontinued = WCONTINUED; retry: if (-1 == (rc = waitpid(pid, &status, WUNTRACED | wcontinued))) { if (EINVAL == errno && 0 != wcontinued) { wcontinued = 0; goto retry; } #else if (-1 == (rc = waitpid(pid, &status, WUNTRACED))) { #endif zabbix_log(LOG_LEVEL_DEBUG, "%s() waitpid failure: %s", __function_name, zbx_strerror(errno)); goto exit; } if (WIFEXITED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() exited, status:%d", __function_name, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() killed by signal %d", __function_name, WTERMSIG(status)); else if (WIFSTOPPED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() stopped by signal %d", __function_name, WSTOPSIG(status)); #ifdef WIFCONTINUED else if (WIFCONTINUED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() continued", __function_name); #endif } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; } #endif /* _WINDOWS */ /****************************************************************************** * * * Function: zbx_execute * * * * Purpose: this function executes a script and returns result from stdout * * * * Parameters: command - [IN] command for execution * * buffer - [OUT] buffer for output, if NULL - ignored * * error - [OUT] error string if function fails * * max_error_len - [IN] length of error buffer * * * * Return value: SUCCEED if processed successfully, TIMEOUT_ERROR if * * timeout occurred or FAIL otherwise * * * * Author: Alexander Vladishev * * * ******************************************************************************/ int zbx_execute(const char *command, char **buffer, char *error, size_t max_error_len, int timeout) { size_t buf_size = PIPE_BUFFER_SIZE, offset = 0; int ret = FAIL; #ifdef _WINDOWS STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; HANDLE job = NULL, hWrite = NULL, hRead = NULL; char *cmd = NULL; wchar_t *wcmd = NULL; struct _timeb start_time, current_time; #else pid_t pid; int fd; #endif *error = '\0'; if (NULL != buffer) { *buffer = zbx_realloc(*buffer, buf_size); **buffer = '\0'; } #ifdef _WINDOWS /* set the bInheritHandle flag so pipe handles are inherited */ sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* create a pipe for the child process's STDOUT */ if (0 == CreatePipe(&hRead, &hWrite, &sa, 0)) { zbx_snprintf(error, max_error_len, "unable to create a pipe: %s", strerror_from_system(GetLastError())); goto close; } /* create a new job where the script will be executed */ if (0 == (job = CreateJobObject(&sa, NULL))) { zbx_snprintf(error, max_error_len, "unable to create a job: %s", strerror_from_system(GetLastError())); goto close; } /* fill in process startup info structure */ memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = hWrite; si.hStdError = hWrite; /* use cmd command to support scripts */ cmd = zbx_dsprintf(cmd, "cmd /C \"%s\"", command); wcmd = zbx_utf8_to_unicode(cmd); /* create the new process */ if (0 == CreateProcess(NULL, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { zbx_snprintf(error, max_error_len, "unable to create process [%s]: %s", cmd, strerror_from_system(GetLastError())); goto close; } CloseHandle(hWrite); hWrite = NULL; /* assign the new process to the created job */ if (0 == AssignProcessToJobObject(job, pi.hProcess)) { zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s", cmd, strerror_from_system(GetLastError())); if (0 == TerminateProcess(pi.hProcess, 0)) { zabbix_log(LOG_LEVEL_ERR, "failed to terminate [%s]: %s", cmd, strerror_from_system(GetLastError())); } } else if (-1 == ResumeThread(pi.hThread)) { zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s", cmd, strerror_from_system(GetLastError())); } else ret = SUCCEED; if (FAIL == ret) goto close; _ftime(&start_time); timeout *= 1000; ret = zbx_read_from_pipe(hRead, buffer, &buf_size, &offset, timeout); if (TIMEOUT_ERROR != ret) { _ftime(¤t_time); if (0 < (timeout -= zbx_get_timediff_ms(&start_time, ¤t_time)) && WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, timeout)) { ret = TIMEOUT_ERROR; } } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); close: if (NULL != job) { /* terminate the child process and it's childs */ if (0 == TerminateJobObject(job, 0)) zabbix_log(LOG_LEVEL_ERR, "failed to terminate job [%s]: %s", cmd, strerror_from_system(GetLastError())); CloseHandle(job); } if (NULL != hWrite) CloseHandle(hWrite); if (NULL != hRead) CloseHandle(hRead); zbx_free(cmd); zbx_free(wcmd); #else /* not _WINDOWS */ alarm(timeout); if (-1 != (fd = zbx_popen(&pid, command))) { int rc; char tmp_buf[PIPE_BUFFER_SIZE]; while (0 < (rc = read(fd, tmp_buf, sizeof(tmp_buf) - 1)) && MAX_EXECUTE_OUTPUT_LEN > offset + rc) { if (NULL != buffer) { tmp_buf[rc] = '\0'; zbx_strcpy_alloc(buffer, &buf_size, &offset, tmp_buf); } } close(fd); if (-1 == rc || -1 == zbx_waitpid(pid)) { if (EINTR == errno) ret = TIMEOUT_ERROR; else zbx_snprintf(error, max_error_len, "zbx_waitpid() failed: %s", zbx_strerror(errno)); /* kill the whole process group, pid must be the leader */ if (-1 == kill(-pid, SIGTERM)) zabbix_log(LOG_LEVEL_ERR, "failed to kill [%s]: %s", command, zbx_strerror(errno)); zbx_waitpid(pid); } else if (MAX_EXECUTE_OUTPUT_LEN <= offset + rc) { zabbix_log(LOG_LEVEL_ERR, "command output exceeded limit of %d KB", MAX_EXECUTE_OUTPUT_LEN / ZBX_KIBIBYTE); } else ret = SUCCEED; } else zbx_strlcpy(error, zbx_strerror(errno), max_error_len); alarm(0); #endif /* _WINDOWS */ if (TIMEOUT_ERROR == ret) zbx_strlcpy(error, "Timeout while executing a shell script.", max_error_len); else if ('\0' != *error) zabbix_log(LOG_LEVEL_WARNING, "%s", error); if (SUCCEED != ret && NULL != buffer) zbx_free(*buffer); return ret; }
void CPCD::Process::do_exec() { unsigned i; #ifdef _WIN32 Vector<BaseString> saved; char *cwd = 0; save_environment(m_env.c_str(), saved); #endif setup_environment(m_env.c_str()); char **argv = BaseString::argify(m_path.c_str(), m_args.c_str()); if(strlen(m_cwd.c_str()) > 0) { #ifdef _WIN32 cwd = getcwd(0, 0); if(!cwd) { logger.critical("Couldn't getcwd before spawn"); } #endif int err = chdir(m_cwd.c_str()); if(err == -1) { BaseString err; logger.error("%s: %s\n", m_cwd.c_str(), strerror(errno)); _exit(1); } } #ifndef _WIN32 Vector<BaseString> ulimit; m_ulimit.split(ulimit); for(i = 0; i<ulimit.size(); i++){ if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){ _exit(1); } } #endif const char *nul = IF_WIN("nul:", "/dev/null"); int fdnull = open(nul, O_RDWR, 0); if(fdnull == -1) { logger.error("Cannot open `%s': %s\n", nul, strerror(errno)); _exit(1); } BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr }; int fds[3]; #ifdef _WIN32 int std_dups[3]; #endif for (i = 0; i < 3; i++) { #ifdef _WIN32 std_dups[i] = dup(i); #endif if (redirects[i]->empty()) { #ifndef DEBUG dup2(fdnull, i); #endif continue; } if((* redirects[i]) == "2>&1" && i == 2){ dup2(fds[1], 2); continue; } /** * Make file */ int flags = 0; int mode = S_IRUSR | S_IWUSR ; if(i == 0){ flags |= O_RDONLY; } else { flags |= O_WRONLY | O_CREAT | O_APPEND; } int f = fds[i]= open(redirects[i]->c_str(), flags, mode); if(f == -1){ logger.error("Cannot redirect %u to/from '%s' : %s\n", i, redirects[i]->c_str(), strerror(errno)); _exit(1); } dup2(f, i); #ifdef _WIN32 close(f); #endif } #ifndef _WIN32 /* Close all filedescriptors */ for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++) close(i); execv(m_path.c_str(), argv); /* XXX If we reach this point, an error has occurred, but it's kind of hard * to report it, because we've closed all files... So we should probably * create a new logger here */ logger.error("Exec failed: %s\n", strerror(errno)); /* NOTREACHED */ #else // Get full path to cygwins shell FILE *fpipe = _popen("sh -c 'cygpath -w `which sh`'", "rt"); char buf[MAX_PATH]; require(fgets(buf, MAX_PATH - 1, fpipe)); fclose(fpipe); BaseString sh; sh.assign(buf); sh.trim("\n"); sh.append(".exe"); BaseString shcmd; shcmd.assfmt("%s -c '%s %s'", sh.c_str(), m_path.c_str(), m_args.c_str()); PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {sizeof(STARTUPINFO), 0}; si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = (HANDLE)_get_osfhandle(0); si.hStdOutput = (HANDLE)_get_osfhandle(1); si.hStdError = (HANDLE)_get_osfhandle(2); if(!CreateProcessA(sh.c_str(), (LPSTR)shcmd.c_str(), NULL, NULL, TRUE, CREATE_SUSPENDED, // Resumed after assigned to Job NULL, NULL, &si, &pi)) { char* message; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, NULL ); logger.error("CreateProcess failed, error: %d, message: '%s'", err, message); LocalFree(message); } HANDLE proc = pi.hProcess; require(proc); // Job control require(m_job = CreateJobObject(0, 0)); require(AssignProcessToJobObject(m_job, proc)); // Resum process after it has been added to Job ResumeThread(pi.hThread); CloseHandle(pi.hThread); // go back up to original cwd if(chdir(cwd)) { logger.critical("Couldn't go back to saved cwd after spawn()"); logger.critical("errno: %d, strerror: %s", errno, strerror(errno)); } free(cwd); // get back to original std i/o for(i = 0; i < 3; i++) { dup2(std_dups[i], i); close(std_dups[i]); } for (i = 0; i < saved.size(); i++) { putenv(saved[i].c_str()); } logger.debug("'%s' has been started", shcmd.c_str()); DWORD exitcode; BOOL result = GetExitCodeProcess(proc, &exitcode); //maybe a short running process if (result && exitcode != 259) { m_status = STOPPED; logger.warning("Process terminated early"); } int pid = GetProcessId(proc); if (!pid) logger.critical("GetProcessId failed, error: %d!", GetLastError()); logger.debug("new pid %d", pid); CloseHandle(proc); m_status = RUNNING; writePid(pid); #endif close(fdnull); }
/* Uninstall NSIS */ MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall ) { DWORD rv = ERROR_SUCCESS; // lookup the NSISUNINSTALL property value LPTSTR cNsisUninstall = _T("NSISUNINSTALL"); HANDLE hIo = NULL; DWORD dwSize = 0; LPTSTR strPathUninst = NULL; HANDLE hJob = NULL; STARTUPINFO sInfo; PROCESS_INFORMATION pInfo; pInfo.hProcess = NULL; pInfo.hThread = NULL; rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize ); if(rv != ERROR_MORE_DATA) goto _cleanup; strPathUninst = new TCHAR[ ++dwSize ]; rv = MsiGetProperty( hInstall, cNsisUninstall, strPathUninst, &dwSize ); if(rv != ERROR_SUCCESS) goto _cleanup; // Create a process for the uninstaller sInfo.cb = sizeof(sInfo); sInfo.lpReserved = NULL; sInfo.lpDesktop = _T(""); sInfo.lpTitle = _T("Foo"); sInfo.dwX = 0; sInfo.dwY = 0; sInfo.dwXSize = 0; sInfo.dwYSize = 0; sInfo.dwXCountChars = 0; sInfo.dwYCountChars = 0; sInfo.dwFillAttribute = 0; sInfo.dwFlags = 0; sInfo.wShowWindow = 0; sInfo.cbReserved2 = 0; sInfo.lpReserved2 = 0; sInfo.hStdInput = 0; sInfo.hStdOutput = 0; sInfo.hStdError = 0; if(!CreateProcess( strPathUninst, _T("Uninstall /S"), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sInfo, &pInfo)) { pInfo.hProcess = NULL; pInfo.hThread = NULL; rv = 40; goto _cleanup; }; // Create a job object to contain the NSIS uninstall process tree JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp; acp.CompletionKey = 0; hJob = CreateJobObject(NULL, _T("NSISUninstallObject")); if(!hJob) { rv = 41; goto _cleanup; } hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); if(!hIo) { rv = 42; goto _cleanup; } acp.CompletionPort = hIo; SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation, &acp, sizeof(acp)); AssignProcessToJobObject( hJob, pInfo.hProcess ); ResumeThread( pInfo.hThread ); DWORD a,b,c; for(;;) { if(!GetQueuedCompletionStatus(hIo, &a, (PULONG_PTR) &b, (LPOVERLAPPED *) &c, INFINITE)) { Sleep(1000); continue; } if(a == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { break; } } rv = ERROR_SUCCESS; _cleanup: if(hIo) CloseHandle(hIo); if(pInfo.hProcess) CloseHandle( pInfo.hProcess ); if(pInfo.hThread) CloseHandle( pInfo.hThread ); if(hJob) CloseHandle(hJob); if(strPathUninst) delete[] strPathUninst; if(rv != ERROR_SUCCESS) { ShowMsiError( hInstall, ERR_NSS_FAILED, rv ); } return rv; }
int main() { int argc; wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc); // Make sure that we've been passed the right number of arguments if (argc < 8) { _tprintf(_T("Usage: %s (four inheritable event handles) (CommandLineToSpawn)\n"), argv[0]); return(0); } // Construct the full command line int nCmdLineLength= MAX_CMD_LINE_LENGTH; wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t)); szCmdLine[0]= 0; int nPos = 0; for(int i = 8; i < argc; ++i) { int nCpyLen; int len= wcslen(argv[i]); int requiredSize= nPos+len+2; if (requiredSize > 32*1024) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Command line too long!\n")); #endif return 0; } ensureSize(&szCmdLine, &nCmdLineLength, requiredSize); if (NULL == szCmdLine) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Not enough memory to build cmd line!\n")); #endif return 0; } if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos))) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Not enough space to build command line\n")); #endif return 0; } nPos += nCpyLen; szCmdLine[nPos] = _T(' '); ++nPos; } szCmdLine[nPos] = _T('\0'); STARTUPINFOW si = {sizeof(si)}; PROCESS_INFORMATION pi = {0}; DWORD dwExitCode = 0; #ifdef DEBUG_MONITOR int currentPID = GetCurrentProcessId(); wchar_t buffer[MAX_CMD_LINE_LENGTH]; #endif BOOL exitProc = FALSE; HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]); HANDLE h[5]; h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]); // simulated SIGINT (CTRL-C or Cygwin 'kill -SIGINT') // h[1] we reserve for the process handle h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // simulated SIGTERM h[3] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[6]); // simulated SIGKILL h[4] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[7]); // CTRL-C, in all cases SetConsoleCtrlHandler(HandlerRoutine, TRUE); int parentPid = wcstol(argv[1], NULL, 10); int nCounter = wcstol(argv[2], NULL, 10); wchar_t inPipeName[PIPE_NAME_LENGTH]; wchar_t outPipeName[PIPE_NAME_LENGTH]; wchar_t errPipeName[PIPE_NAME_LENGTH]; swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter); swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter); swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter); #ifdef DEBUG_MONITOR swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName); OutputDebugStringW(buffer); #endif HANDLE stdHandles[3]; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) || (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) || (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa)))) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError()); OutputDebugStringW(buffer); #endif CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); return -1;; } SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE); SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE); SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE); if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) || !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) || !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError()); OutputDebugStringW(buffer); #endif CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); return -1;; } #ifdef DEBUG_MONITOR wchar_t * lpvEnv = GetEnvironmentStringsW(); // If the returned pointer is NULL, exit. if (lpvEnv == NULL) OutputDebugStringW(_T("Cannot Read Environment\n")); else { // Variable strings are separated by NULL byte, and the block is // terminated by a NULL byte. OutputDebugStringW(_T("Starter: Environment\n")); for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) { swprintf(buffer, _T("%s\n"), lpszVariable); OutputDebugStringW(buffer); } FreeEnvironmentStringsW(lpvEnv); } #endif #ifdef DEBUG_MONITOR swprintf(buffer, _T("Starting: %s\n"), szCmdLine); OutputDebugStringW(buffer); #endif // Create job object HANDLE hJob = CreateJobObject(NULL, NULL); // Spawn the other processes as part of this Process Group BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); // We don't need them any more CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); if (f) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId); OutputDebugStringW(buffer); #endif SetEvent(waitEvent); // Means thar process has been spawned CloseHandle(pi.hThread); h[1] = pi.hProcess; if(NULL != hJob) { if(!AssignProcessToJobObject(hJob, pi.hProcess)) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId); OutputDebugStringW(buffer); DisplayErrorMessage(); #endif } } while(!exitProc) { // Wait for the spawned-process to die or for the event // indicating that the processes should be forcibly killed. DWORD event = WaitForMultipleObjects(5, h, FALSE, INFINITE); switch (event) { case WAIT_OBJECT_0 + 0: // SIGINT case WAIT_OBJECT_0 + 4: // CTRL-C #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID); OutputDebugStringW(buffer); #endif if ((event == (WAIT_OBJECT_0 + 0)) && isCygwin(h[1])) { // Need to issue a kill command wchar_t kill[1024]; swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId); if (!runCygwinCommand(kill)) { // fall back to console event GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } } else { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } SetEvent(waitEvent); break; case WAIT_OBJECT_0 + 1: // App terminated normally // Make it's exit code our exit code #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"), pi.dwProcessId); OutputDebugStringW(buffer); #endif GetExitCodeProcess(pi.hProcess, &dwExitCode); exitProc = TRUE; break; // Terminate and Kill behavior differ only for cygwin processes, where // we use the cygwin 'kill' command. We send a SIGKILL in one case, // SIGTERM in the other. For non-cygwin processes, both requests // are treated exactly the same case WAIT_OBJECT_0 + 2: // TERM case WAIT_OBJECT_0 + 3: // KILL { const wchar_t* signal = (event == WAIT_OBJECT_0 + 2) ? L"TERM" : L"KILL"; #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter received %s event (PID %i)\n"), signal, currentPID); OutputDebugStringW(buffer); #endif if (isCygwin(h[1])) { // Need to issue a kill command wchar_t kill[1024]; swprintf(kill, L"kill -%s %d", signal, pi.dwProcessId); if (!runCygwinCommand(kill)) { // fall back to console event GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } } else { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } SetEvent(waitEvent); if(NULL != hJob) { if(!TerminateJobObject(hJob, (DWORD)-1)) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Cannot terminate job\n")); DisplayErrorMessage(); #endif } } // Note that we keep trucking until the child process terminates (case WAIT_OBJECT_0 + 1) break; } default: // Unexpected code #ifdef DEBUG_MONITOR DisplayErrorMessage(); #endif exitProc = TRUE; break; } } } else { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine); OutputDebugStringW(buffer); DisplayErrorMessage(); #endif } if (NULL != szCmdLine) { free(szCmdLine); } CloseHandle(waitEvent); CloseHandle(h[0]); CloseHandle(h[1]); CloseHandle(h[2]); CloseHandle(h[3]); CloseHandle(h[4]); return(dwExitCode); }
int uv_spawn_jx(uv_loop_t* loop, uv_process_t* process, uv_process_options_t* options) { #ifdef WINONECORE error_console("Error: WindowsOneCore does not support spawning a process.\n"); return -1; // not supported #else int i; uv_err_t err = uv_ok_; WCHAR* path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } if (options->file == NULL || options->args == NULL) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); uv_process_init(loop, process); process->exit_cb = options->exit_cb; err = uv_utf8_to_utf16_alloc(options->file, &application); if (err.code != UV_OK) goto done; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err.code != UV_OK) goto done; if (options->env) { err = make_program_env(options->env, &env); if (err.code != UV_OK) goto done; } if (options->cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); if (err.code != UV_OK) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } cwd = (WCHAR*)malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } } /* Get PATH environment variable. */ { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = uv__new_sys_error(GetLastError()); goto done; } path = (WCHAR*)malloc(path_len * sizeof(WCHAR)); if (path == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = uv__new_sys_error(GetLastError()); goto done; } } application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = uv__new_artificial_error(UV_ENOENT); goto done; } err = uv__stdio_create(loop, options, &process->child_stdio_buffer); if (err.code != UV_OK) goto done; startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*)process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); if (options->flags & UV_PROCESS_WINDOWS_HIDE) { /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { startup.wShowWindow = SW_SHOWDEFAULT; } process_flags = CREATE_UNICODE_ENVIRONMENT; if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That * means that libuv might not let you create a fully deamonized process * when run under job control. However the type of job control that libuv * itself creates doesn't trickle down to subprocesses so they can still * daemonize. * * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the * CreateProcess call fail if we're under job control that doesn't allow * breakaway. */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* Spawn succeeded */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* If the process isn't spawned as detached, assign to the global job */ /* object so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { /* AssignProcessToJobObject might fail if this process is under job * control and the job doesn't have the * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version * that doesn't support nested jobs. * * When that happens we just swallow the error and continue without * establishing a kill-child-on-parent-exit relationship, otherwise * there would be no way for libuv applications run under job control * to spawn processes at all. */ DWORD err = GetLastError(); if (err != ERROR_ACCESS_DENIED) uv_fatal_error(err, "AssignProcessToJobObject"); } } /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options->stdio_count; i++) { const uv_stdio_container_t* fdopt = &options->stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*)fdopt->data.stream)->ipc) { ((uv_pipe_t*)fdopt->data.stream)->ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject( &process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); } else { /* CreateProcessW failed. */ err = uv__new_sys_error(GetLastError()); } done: JX_FREE(process, application); JX_FREE(process, application_path); JX_FREE(process, arguments); JX_FREE(process, cwd); JX_FREE(process, env); JX_FREE(process, path); process->spawn_error = err; if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* If an error happened, queue the exit req. */ if (err.code != UV_OK) { process->exit_cb_pending = 1; uv_insert_pending_req(loop, (uv_req_t*)&process->exit_req); } return 0; #endif }