Added a function to wait on any process completing
Added function to check if all processes are finished without blocking Added a function to set a uniproc_process object to a known invalid value Added a function to check if a process is a known invalid value Added userdata variable to struct as well as functions to set/get it Updated uniproc_close_process to set the process to a known invalid value All functions now ignore uniproc_process's with a known invalid value uniproc_create_process will now return a known invalid value if it fails to create a process
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@
|
||||
/test.ilk
|
||||
/test.pdb
|
||||
/src/main.c
|
||||
*.o
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdint.h>
|
||||
#include <Windows.h>
|
||||
typedef struct {
|
||||
|
||||
uint64_t userdata;
|
||||
FILE* in;
|
||||
FILE* out;
|
||||
FILE* err;
|
||||
@@ -14,5 +16,12 @@ typedef struct {
|
||||
} uniproc_process;
|
||||
|
||||
uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, const char** argv);
|
||||
void uniproc_await_processes(uniproc_process* p, int* return_codes, size_t num_processes);
|
||||
void uniproc_await_processes(const uniproc_process* p, int* return_codes, const size_t num_processes);
|
||||
void uniproc_close_process(uniproc_process* p);
|
||||
bool uniproc_are_processes_finished(const uniproc_process* p, const size_t num_processes);
|
||||
void uniproc_nullify_processes(uniproc_process* p, const size_t num_processes);
|
||||
bool uniproc_is_process_null(const uniproc_process* p);
|
||||
void uniproc_await_any_processes(const uniproc_process* p, const size_t num_processes);
|
||||
void uniproc_set_userdata(uniproc_process* p, const uint64_t userdata);
|
||||
void uniproc_set_userdata(uniproc_process* p, void const* userdata);
|
||||
void* uniproc_get_userdata(uniproc_process* p);
|
||||
@@ -15,11 +15,20 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
|
||||
int stderr_pipe[2];
|
||||
|
||||
if (pipe(stdin_pipe) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (pipe(stdout_pipe) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (pipe(stderr_pipe) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Fork process
|
||||
uniproc_process p;
|
||||
@@ -29,17 +38,29 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
// Child
|
||||
else if (pid == 0)
|
||||
{
|
||||
// Redirect the child's std. files to the pipes created above
|
||||
if (dup2(stdin_pipe[0], STDIN_FILENO) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (dup2(stdout_pipe[2], STDERR_FILENO) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Close file handle references that are not needed
|
||||
if (stdin_pipe[0] != -1) close(stdin_pipe[0]);
|
||||
@@ -51,7 +72,11 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
|
||||
|
||||
// And execute the command provided
|
||||
if (execvp(cmd, argv) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
||||
// Parent
|
||||
else
|
||||
@@ -77,19 +102,52 @@ void uniproc_await_processes(uniproc_process* p, int* return_codes, size_t num_p
|
||||
int rc;
|
||||
if (return_codes == NULL)
|
||||
for (size_t i = 0; i < num_processes; ++i)
|
||||
waitpid(p._proc_hdl, &rc, 0);
|
||||
if (!uniproc_is_process_null(p+i))
|
||||
waitpid(p[i]._proc_hdl, &rc, 0);
|
||||
else
|
||||
for (size_t i = 0; i < num_processes; ++i)
|
||||
waitpid(p._proc_hdl, return_codes+i, 0);
|
||||
if (!uniproc_is_process_null(p+i))
|
||||
waitpid(p[i]._proc_hdl, return_codes + i, 0);
|
||||
}
|
||||
|
||||
void uniproc_close_process(uniproc_process* p)
|
||||
{
|
||||
if (uniproc_is_process_null(p)) return;
|
||||
kill(p->_proc_hdl, SIGKILL);
|
||||
fclose(p->in);
|
||||
fclose(p->out);
|
||||
fclose(p->err);
|
||||
}
|
||||
|
||||
bool uniproc_are_processes_finished(const uniproc_process* p, const size_t num_processes)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
for (size_t i = 0; i < num_processes; ++i)
|
||||
res &&= uniproc_is_process_null(p + i) || waitpid(p[i]._proc_hdl, nullptr, WNOHANG | WIFEXITED | WIFSIGNALED | WCOREDUMP);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void uniproc_nullify_processes(uniproc_process* p, const size_t num_processes)
|
||||
{ memset(p, 0, sizeof(uniproc_process) * mum_processes); }
|
||||
|
||||
bool 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)
|
||||
{
|
||||
while (uniproc_are_processes_finished(p, num_processes))
|
||||
waitpid(0, nullptr, WIFEXITED | WIFSIGNALED | WCOREDUMP);
|
||||
}
|
||||
|
||||
void uniproc_set_userdata(uniproc_process* p, const uint64_t userdata)
|
||||
{ p->userdata = userdata; }
|
||||
|
||||
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
|
||||
@@ -21,19 +21,61 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
|
||||
|
||||
// Actually create the pipes
|
||||
if (!CreatePipe(&out, &child_out, &pipe_attribs, 0))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (!CreatePipe(&err, &child_err, &pipe_attribs, 0))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
CloseHandle(child_out);
|
||||
CloseHandle(out);
|
||||
uniproc_nullify_processes(p, 1);
|
||||
return p;
|
||||
}
|
||||
if (!CreatePipe(&child_in, &in, &pipe_attribs, 0))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
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))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
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))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
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))
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
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;
|
||||
@@ -82,7 +124,16 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
|
||||
free(p_cmd);
|
||||
|
||||
if (!is_ok)
|
||||
exit(EXIT_FAILURE);
|
||||
{
|
||||
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");
|
||||
@@ -120,4 +171,34 @@ void uniproc_close_process(uniproc_process* p)
|
||||
fclose(p->err);
|
||||
}
|
||||
|
||||
bool uniproc_are_processes_finished(const uniproc_process* p, const size_t num_processes)
|
||||
{
|
||||
HANDLE* h = (HANDLE*)malloc(num_processes*sizeof(HANDLE));
|
||||
DWORD ret = WaitForMultipleObjects(num_processes, h, true, 0);
|
||||
free(h);
|
||||
return ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + num_processes;
|
||||
}
|
||||
|
||||
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));
|
||||
WaitForMultipleObjects(num_processes, h, false, INFINITE);
|
||||
free(h);
|
||||
}
|
||||
|
||||
void uniproc_set_userdata(uniproc_process* p, const uint64_t userdata)
|
||||
{ p->userdata = userdata; }
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user