Compare commits

..

4 Commits

Author SHA1 Message Date
500fe17076 Removed un-needed function overload for setting userdata
Fixed bugs in win64 impl where it did not check if the process was a known invalid value
2025-03-06 15:54:50 +11:00
12cc5bd38e Merge branch 'main' of ssh://git.rileyk.au:19482/riley/uniproc 2025-03-06 15:35:59 +11:00
682773a934 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

AMEND: 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
2025-03-06 15:35:53 +11:00
7c437b8f30 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
2025-03-06 15:29:37 +11:00
4 changed files with 188 additions and 21 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@
/test.ilk /test.ilk
/test.pdb /test.pdb
/src/main.c /src/main.c
*.o

View File

@@ -4,6 +4,8 @@
#include <stdint.h> #include <stdint.h>
#include <Windows.h> #include <Windows.h>
typedef struct { typedef struct {
uint64_t userdata;
FILE* in; FILE* in;
FILE* out; FILE* out;
FILE* err; FILE* err;
@@ -14,5 +16,11 @@ typedef struct {
} uniproc_process; } uniproc_process;
uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, const char** argv); 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); 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, void const* userdata);
void* uniproc_get_userdata(uniproc_process* p);

View File

@@ -15,11 +15,20 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
int stderr_pipe[2]; int stderr_pipe[2];
if (pipe(stdin_pipe) == -1) if (pipe(stdin_pipe) == -1)
exit(EXIT_FAILURE); {
uniproc_nullify_processes(p, 1);
return p;
}
if (pipe(stdout_pipe) == -1) if (pipe(stdout_pipe) == -1)
exit(EXIT_FAILURE); {
uniproc_nullify_processes(p, 1);
return p;
}
if (pipe(stderr_pipe) == -1) if (pipe(stderr_pipe) == -1)
exit(EXIT_FAILURE); {
uniproc_nullify_processes(p, 1);
return p;
}
// Fork process // Fork process
uniproc_process p; 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(); pid_t pid = fork();
if (pid == -1) if (pid == -1)
exit(EXIT_FAILURE); {
uniproc_nullify_processes(p, 1);
return p;
}
// Child // Child
else if (pid == 0) else if (pid == 0)
{ {
// Redirect the child's std. files to the pipes created above // Redirect the child's std. files to the pipes created above
if (dup2(stdin_pipe[0], STDIN_FILENO) == -1) 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) 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) 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 // Close file handle references that are not needed
if (stdin_pipe[0] != -1) close(stdin_pipe[0]); 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 // And execute the command provided
if (execvp(cmd, argv) == -1) if (execvp(cmd, argv) == -1)
exit(EXIT_FAILURE); {
uniproc_nullify_processes(p, 1);
return p;
}
} }
// Parent // Parent
else else
@@ -77,19 +102,50 @@ void uniproc_await_processes(uniproc_process* p, int* return_codes, size_t num_p
int rc; int rc;
if (return_codes == NULL) if (return_codes == NULL)
for (size_t i = 0; i < num_processes; ++i) 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 else
for (size_t i = 0; i < num_processes; ++i) 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) void uniproc_close_process(uniproc_process* p)
{ {
if (uniproc_is_process_null(p)) return;
kill(p->_proc_hdl, SIGKILL); kill(p->_proc_hdl, SIGKILL);
fclose(p->in); fclose(p->in);
fclose(p->out); fclose(p->out);
fclose(p->err); fclose(p->err);
uniproc_nullify_processes(p, 1);
} }
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, void const* userdata)
{ p->userdata = (uint64_t)userdata; }
void* uniproc_get_userdata(uniproc_process* p)
{ return (void*)p->userdata; }
#endif #endif

View File

@@ -21,19 +21,61 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
// Actually create the pipes // Actually create the pipes
if (!CreatePipe(&out, &child_out, &pipe_attribs, 0)) 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)) 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)) 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 // Unset inherrit flags for the pipes
if (!SetHandleInformation(out, HANDLE_FLAG_INHERIT, 0)) 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)) 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)) 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 // Create child process
uniproc_process p; uniproc_process p;
@@ -82,7 +124,16 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
free(p_cmd); free(p_cmd);
if (!is_ok) 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.err = _fdopen(_open_osfhandle((intptr_t)err, _O_RDONLY), "r");
p.out = _fdopen(_open_osfhandle((intptr_t)out, _O_RDONLY), "r"); p.out = _fdopen(_open_osfhandle((intptr_t)out, _O_RDONLY), "r");
@@ -99,25 +150,76 @@ uniproc_process uniproc_create_process(const char* cmd, const size_t num_args, c
void uniproc_await_processes(uniproc_process* p, int* return_codes, size_t num_processes) 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)); HANDLE* h = (HANDLE*)malloc(num_processes*sizeof(HANDLE));
for (size_t i = 0; i < num_processes; ++i) for (size_t i = 0; i < num_processes; ++i)
{
if (uniproc_is_process_null(p + i)) continue;
h[i] = (HANDLE)p[i]._proc_hdl; h[i] = (HANDLE)p[i]._proc_hdl;
num_valid_handles++;
}
WaitForMultipleObjects(num_processes, h, 1, INFINITE); WaitForMultipleObjects(num_valid_handles, h, 1, INFINITE);
free(h); free(h);
if (return_codes == NULL) return; if (return_codes == NULL) return;
for (size_t i = 0; i < num_processes; ++i) 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)); GetExitCodeProcess((HANDLE)p[i]._proc_hdl, (LPDWORD)(return_codes + i));
} }
}
void uniproc_close_process(uniproc_process* p) void uniproc_close_process(uniproc_process* p)
{ {
if (uniproc_is_process_null(p)) return;
TerminateProcess((HANDLE)p->_proc_hdl, 2); TerminateProcess((HANDLE)p->_proc_hdl, 2);
CloseHandle((HANDLE)p->_proc_hdl); CloseHandle((HANDLE)p->_proc_hdl);
fclose(p->in); fclose(p->in);
fclose(p->out); fclose(p->out);
fclose(p->err); 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 #endif