From 682773a934698703e49f1794e25be3303af2f910 Mon Sep 17 00:00:00 2001 From: Riley King-Saunders Date: Thu, 6 Mar 2025 15:29:37 +1100 Subject: [PATCH] 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 --- .gitignore | 1 + include/uniproc.h | 11 +++++- src/uniproc_unix.c | 81 ++++++++++++++++++++++++++++++++------ src/uniproc_win64.c | 96 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 170 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index c72fe0f..f4afecb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /test.ilk /test.pdb /src/main.c +*.o diff --git a/include/uniproc.h b/include/uniproc.h index eb30910..c08a656 100644 --- a/include/uniproc.h +++ b/include/uniproc.h @@ -4,6 +4,8 @@ #include #include 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); \ No newline at end of file diff --git a/src/uniproc_unix.c b/src/uniproc_unix.c index aa7043b..68471b7 100644 --- a/src/uniproc_unix.c +++ b/src/uniproc_unix.c @@ -15,31 +15,52 @@ 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; p.in = stdin_pipe[1]; // Write handle p.out = stdout_pipe[0]; // Read handle p.err = stderr_pipe[0]; // Read handle - + 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,53 @@ 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); + 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, 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 \ No newline at end of file diff --git a/src/uniproc_win64.c b/src/uniproc_win64.c index 767a82a..e742145 100644 --- a/src/uniproc_win64.c +++ b/src/uniproc_win64.c @@ -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"); @@ -118,6 +169,37 @@ void uniproc_close_process(uniproc_process* p) 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)); + 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 \ No newline at end of file