diff --git a/subprocess.h b/subprocess.h index 47517aa..03a86c1 100644 --- a/subprocess.h +++ b/subprocess.h @@ -224,6 +224,7 @@ subprocess_weak int subprocess_alive(struct subprocess_s *const process); #endif #if !defined(_WIN32) +#include #include #include #include @@ -757,6 +758,7 @@ int subprocess_create_ex(const char *const commandLine[], int options, int stdinfd[2]; int stdoutfd[2]; int stderrfd[2]; + int fd, fd_flags; pid_t child; extern char **environ; char *const empty_environment[1] = {SUBPROCESS_NULL}; @@ -886,6 +888,13 @@ int subprocess_create_ex(const char *const commandLine[], int options, // Store the stdout read end out_process->stdout_file = fdopen(stdoutfd[0], "rb"); + // Should we use async behaviour ? + if(options & subprocess_option_enable_async){ + fd = fileno(out_process->stdout_file); + fd_flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK); + } + if (subprocess_option_combined_stdout_stderr == (options & subprocess_option_combined_stdout_stderr)) { out_process->stderr_file = out_process->stdout_file; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 09a1490..7d26515 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,6 +47,7 @@ add_executable(process_fail_stackoverflow process_fail_stackoverflow.c) add_executable(process_hung process_hung.c) add_executable(process_stdout_data process_stdout_data.c) add_executable(process_stdout_poll process_stdout_poll.c) +add_executable(process_stdout_poll_nodata process_stdout_poll_nodata.c) add_executable(process_stderr_poll process_stderr_poll.c) add_executable(process_stdout_large process_stdout_large.c) add_executable(process_call_return_argc process_call_return_argc.c) diff --git a/test/main.c b/test/main.c index af54540..a63c682 100644 --- a/test/main.c +++ b/test/main.c @@ -594,11 +594,11 @@ UTEST(subprocess, read_stdout_async_small) { ASSERT_EQ(0, subprocess_create(commandLine, subprocess_option_enable_async, &process)); - do { + while(subprocess_alive(&process)) { bytes_read = subprocess_read_stdout(&process, data + index, sizeof(data) - 1 - index); index += bytes_read; - } while (bytes_read != 0); + } ASSERT_EQ(13u, index); @@ -624,11 +624,11 @@ UTEST(subprocess, read_stdout_async) { ASSERT_EQ(0, subprocess_create(commandLine, subprocess_option_enable_async, &process)); - do { + while(subprocess_alive(&process)) { bytes_read = subprocess_read_stdout(&process, data + index, sizeof(data) - 1 - index); index += bytes_read; - } while (bytes_read != 0); + } ASSERT_EQ(212992u, index); @@ -643,6 +643,38 @@ UTEST(subprocess, read_stdout_async) { ASSERT_EQ(ret, 0); } +UTEST(subprocess, read_stdout_async_nodata) { + const char *const commandLine[] = {"./process_stdout_poll_nodata", 0}; + struct subprocess_s process; + int ret = -1; + static char data[14 + 1] = {0}; + unsigned index = 0; + unsigned bytes_read = 0; + + ASSERT_EQ(0, subprocess_create(commandLine, subprocess_option_enable_async, + &process)); + + while(subprocess_alive(&process)) { + bytes_read = subprocess_read_stdout(&process, data + index, + sizeof(data) - 1 - index); + index += bytes_read; + + // Send any character to the subprocess to tell it to pursuit + if (bytes_read == 0) { + fputc('s', subprocess_stdin(&process)); + fflush(subprocess_stdin(&process)); + } + } + + ASSERT_EQ(15u, bytes_read); + ASSERT_EQ(15u, index); + ASSERT_TRUE(0 == memcmp("Hello, world!", data, 14)); + + ASSERT_EQ(0, subprocess_join(&process, &ret)); + ASSERT_EQ(0, subprocess_destroy(&process)); + ASSERT_EQ(ret, 0); +} + UTEST(subprocess, poll_stdout_async) { const char *const commandLine[] = {"./process_stdout_poll", "16384", 0}; struct subprocess_s process; @@ -654,7 +686,7 @@ UTEST(subprocess, poll_stdout_async) { ASSERT_EQ(0, subprocess_create(commandLine, subprocess_option_enable_async, &process)); - do { + while(subprocess_alive(&process)) { bytes_read = subprocess_read_stdout(&process, data + index, sizeof(data) - 1 - index); @@ -667,7 +699,7 @@ UTEST(subprocess, poll_stdout_async) { } index += bytes_read; - } while (bytes_read != 0); + } ASSERT_EQ(212992u, index); diff --git a/test/process_stdout_poll_nodata.c b/test/process_stdout_poll_nodata.c new file mode 100644 index 0000000..8ce3d0f --- /dev/null +++ b/test/process_stdout_poll_nodata.c @@ -0,0 +1,37 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +#include +#include + +int main(int argc, const char *const argv[]) { + // Do nothing, wait for an event on stdin + while(fgetc(stdin) == EOF){} + + // Event received, write something on stdout + printf("Hello, world!"); + + return 0; +} \ No newline at end of file