#if defined(_WIN32) || defined(_WIN64) #include "uniproc.h" #include #include #include uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, const char** argv) { // Create pipes HANDLE child_in; HANDLE in; HANDLE child_out; HANDLE out; HANDLE child_err; HANDLE err; SECURITY_ATTRIBUTES pipe_attribs; pipe_attribs.nLength = sizeof(SECURITY_ATTRIBUTES); pipe_attribs.bInheritHandle = 1; pipe_attribs.lpSecurityDescriptor = NULL; // Actually create the pipes if (!CreatePipe(&out, &child_out, &pipe_attribs, 0)) { uniproc_nullify_processes(p, 1); return p; } if (!CreatePipe(&err, &child_err, &pipe_attribs, 0)) { CloseHandle(child_out); CloseHandle(out); uniproc_nullify_processes(p, 1); return p; } if (!CreatePipe(&child_in, &in, &pipe_attribs, 0)) { CloseHandle(child_out); CloseHandle(out); CloseHandle(child_err); CloseHandle(err); uniproc_nullify_processes(p, 1); return p; } // Unset inherrit flags for the pipes if (!SetHandleInformation(out, HANDLE_FLAG_INHERIT, 0)) { CloseHandle(child_in); CloseHandle(in); CloseHandle(child_out); CloseHandle(out); CloseHandle(child_err); CloseHandle(err); uniproc_nullify_processes(p, 1); return p; } if (!SetHandleInformation(err, HANDLE_FLAG_INHERIT, 0)) { CloseHandle(child_in); CloseHandle(in); CloseHandle(child_out); CloseHandle(out); CloseHandle(child_err); CloseHandle(err); uniproc_nullify_processes(p, 1); return p; } if (!SetHandleInformation(in, HANDLE_FLAG_INHERIT, 0)) { CloseHandle(child_in); CloseHandle(in); CloseHandle(child_out); CloseHandle(out); CloseHandle(child_err); CloseHandle(err); uniproc_nullify_processes(p, 1); return p; } // Create child process uniproc_process p; // Create p_cmd by appending all argv's to cmd size_t x = strlen(cmd); size_t cmd_len = x + 1; for (size_t i = 0; i < num_args; ++i) cmd_len += strlen(argv[i]) + 1; char* p_cmd = malloc((cmd_len+1) * sizeof(char)); p_cmd[x] = ' '; memcpy(p_cmd, cmd, x * sizeof(char)); x += 1; // Account for space after cmd for (size_t i = 0; i < num_args; ++i) { size_t arglen = strlen(argv[i]); memcpy(p_cmd + x, argv[i], arglen); p_cmd[x + arglen] = ' '; x += arglen + 1; } p_cmd[cmd_len] = '\0'; PROCESS_INFORMATION p_info; STARTUPINFOA p_startup; memset(&p_info, 0, sizeof(PROCESS_INFORMATION)); memset(&p_startup, 0, sizeof(STARTUPINFOA)); p_startup.cb = sizeof(STARTUPINFOA); p_startup.dwFlags |= STARTF_USESTDHANDLES; p_startup.hStdInput = child_in; p_startup.hStdOutput = child_out; p_startup.hStdError = child_err; int is_ok = CreateProcessA( NULL,// Application name p_cmd, // Command to execute NULL,// Security attributes NULL,// Primary thread security 1, // Inherrit handles 0, // Creation flags NULL,// Environment (use parent's) NULL,// Current directory (use parent's) &p_startup, &p_info ); free(p_cmd); if (!is_ok) { CloseHandle(child_in); CloseHandle(in); CloseHandle(child_out); CloseHandle(out); CloseHandle(child_err); CloseHandle(err); uniproc_nullify_processes(p, 1); return p; } p.err = _fdopen(_open_osfhandle((intptr_t)err, _O_RDONLY), "r"); p.out = _fdopen(_open_osfhandle((intptr_t)out, _O_RDONLY), "r"); p.in = _fdopen(_open_osfhandle( (intptr_t)in, _O_WRONLY), "w"); p._proc_hdl = (uint32_t)p_info.hProcess; CloseHandle(child_in); CloseHandle(child_out); CloseHandle(child_err); CloseHandle(p_info.hThread); return p; } void uniproc_await_processes(uniproc_process* p, int* return_codes, size_t num_processes) { size_t num_valid_handles = 0; HANDLE* h = (HANDLE*)malloc(num_processes*sizeof(HANDLE)); for (size_t i = 0; i < num_processes; ++i) { if (uniproc_is_process_null(p + i)) continue; h[i] = (HANDLE)p[i]._proc_hdl; num_valid_handles++; } WaitForMultipleObjects(num_valid_handles, h, 1, INFINITE); free(h); if (return_codes == NULL) return; for (size_t i = 0; i < num_processes; ++i) { if (uniproc_is_process_null(p + i)) continue; GetExitCodeProcess((HANDLE)p[i]._proc_hdl, (LPDWORD)(return_codes + i)); } } void uniproc_close_process(uniproc_process* p) { if (uniproc_is_process_null(p)) return; TerminateProcess((HANDLE)p->_proc_hdl, 2); CloseHandle((HANDLE)p->_proc_hdl); fclose(p->in); fclose(p->out); fclose(p->err); uniproc_nullify_processes(p, 1); } bool uniproc_are_processes_finished(const uniproc_process* p, const size_t num_processes) { HANDLE* h = (HANDLE*)malloc(num_processes*sizeof(HANDLE)); size_t num_valid_handles = 0; for (size_t i = 0; i < num_processes; ++i) { if (uniproc_is_process_null(p + i)) continue; h[i] = (HANDLE)p[i]._proc_hdl; num_valid_handles++; } DWORD ret = WaitForMultipleObjects(num_valid_handles, h, true, 0); free(h); return ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + num_valid_handles; } void uniproc_nullify_processes(uniproc_process* p, const size_t num_processes) { memset(p, 0, num_processes * sizeof(uniproc_process)); } void uniproc_is_process_null(const uniproc_process* p) { return p->_proc_hdl == NULL; } void uniproc_await_any_processes(const uniproc_process* p, const size_t num_processes) { HANDLE* h = (HANDLE*)malloc(num_processes * sizeof(HANDLE)); size_t num_valid_handles = 0; for (size_t i = 0; i < num_processes; ++i) { if (uniproc_is_process_null(p + i)) continue; h[i] = (HANDLE)p[i]._proc_hdl; num_valid_handles++; } WaitForMultipleObjects(num_valid_handles, h, false, INFINITE); free(h); } void uniproc_set_userdata(uniproc_process * p, void const* userdata) { p->userdata = (uint64_t)userdata; } void* uniproc_get_userdata(uniproc_process* p) { return (void*)p->userdata; } #endif