Files
uniproc/src/uniproc_win64.c

227 lines
5.7 KiB
C

#if defined(_WIN32) || defined(_WIN64)
#include "uniproc.h"
#include <Windows.h>
#include <fcntl.h>
#include <io.h>
uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, const char** argv)
{
uniproc_process p;
// 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 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(const uniproc_process* p, int* return_codes, const 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++;
}
if (num_valid_handles == 0) return;
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);
}
int 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++;
}
if (num_valid_handles == 0) return true;
DWORD ret = WaitForMultipleObjects(num_valid_handles, h, 1, 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)); }
int 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++;
}
if (num_valid_handles == 0) return;
WaitForMultipleObjects(num_valid_handles, h, 0, 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