test-stdio-over-pipes.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "uv.h"
  22. #include "task.h"
  23. #include <stdlib.h>
  24. #include <string.h>
  25. static char exepath[1024];
  26. static size_t exepath_size = 1024;
  27. static char* args[3];
  28. static uv_process_options_t options;
  29. static int close_cb_called;
  30. static int exit_cb_called;
  31. static int on_read_cb_called;
  32. static int after_write_cb_called;
  33. static uv_pipe_t in;
  34. static uv_pipe_t out;
  35. static uv_loop_t* loop;
  36. #define OUTPUT_SIZE 1024
  37. static char output[OUTPUT_SIZE];
  38. static int output_used;
  39. static void close_cb(uv_handle_t* handle) {
  40. close_cb_called++;
  41. }
  42. static void exit_cb(uv_process_t* process,
  43. int64_t exit_status,
  44. int term_signal) {
  45. printf("exit_cb\n");
  46. exit_cb_called++;
  47. ASSERT(exit_status == 0);
  48. ASSERT(term_signal == 0);
  49. uv_close((uv_handle_t*)process, close_cb);
  50. uv_close((uv_handle_t*)&in, close_cb);
  51. uv_close((uv_handle_t*)&out, close_cb);
  52. }
  53. static void init_process_options(char* test, uv_exit_cb exit_cb) {
  54. int r = uv_exepath(exepath, &exepath_size);
  55. ASSERT(r == 0);
  56. exepath[exepath_size] = '\0';
  57. args[0] = exepath;
  58. args[1] = test;
  59. args[2] = NULL;
  60. options.file = exepath;
  61. options.args = args;
  62. options.exit_cb = exit_cb;
  63. }
  64. static void on_alloc(uv_handle_t* handle,
  65. size_t suggested_size,
  66. uv_buf_t* buf) {
  67. buf->base = output + output_used;
  68. buf->len = OUTPUT_SIZE - output_used;
  69. }
  70. static void after_write(uv_write_t* req, int status) {
  71. if (status) {
  72. fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
  73. ASSERT(0);
  74. }
  75. /* Free the read/write buffer and the request */
  76. free(req);
  77. after_write_cb_called++;
  78. }
  79. static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) {
  80. uv_write_t* req;
  81. uv_buf_t wrbuf;
  82. int r;
  83. ASSERT(nread > 0 || nread == UV_EOF);
  84. if (nread > 0) {
  85. output_used += nread;
  86. if (output_used % 12 == 0) {
  87. ASSERT(memcmp("hello world\n", output, 12) == 0);
  88. wrbuf = uv_buf_init(output, 12);
  89. req = malloc(sizeof(*req));
  90. r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write);
  91. ASSERT(r == 0);
  92. }
  93. }
  94. on_read_cb_called++;
  95. }
  96. static void test_stdio_over_pipes(int overlapped) {
  97. int r;
  98. uv_process_t process;
  99. uv_stdio_container_t stdio[3];
  100. loop = uv_default_loop();
  101. init_process_options("stdio_over_pipes_helper", exit_cb);
  102. uv_pipe_init(loop, &out, 0);
  103. uv_pipe_init(loop, &in, 0);
  104. options.stdio = stdio;
  105. options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE |
  106. (overlapped ? UV_OVERLAPPED_PIPE : 0);
  107. options.stdio[0].data.stream = (uv_stream_t*) &in;
  108. options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE |
  109. (overlapped ? UV_OVERLAPPED_PIPE : 0);
  110. options.stdio[1].data.stream = (uv_stream_t*) &out;
  111. options.stdio[2].flags = UV_INHERIT_FD;
  112. options.stdio[2].data.fd = 2;
  113. options.stdio_count = 3;
  114. r = uv_spawn(loop, &process, &options);
  115. ASSERT(r == 0);
  116. r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
  117. ASSERT(r == 0);
  118. r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  119. ASSERT(r == 0);
  120. ASSERT(on_read_cb_called > 1);
  121. ASSERT(after_write_cb_called == 2);
  122. ASSERT(exit_cb_called == 1);
  123. ASSERT(close_cb_called == 3);
  124. ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0);
  125. ASSERT(output_used == 24);
  126. MAKE_VALGRIND_HAPPY();
  127. }
  128. TEST_IMPL(stdio_over_pipes) {
  129. test_stdio_over_pipes(0);
  130. return 0;
  131. }
  132. TEST_IMPL(stdio_emulate_iocp) {
  133. test_stdio_over_pipes(1);
  134. return 0;
  135. }
  136. /* Everything here runs in a child process. */
  137. static int on_pipe_read_called;
  138. static int after_write_called;
  139. static uv_pipe_t stdin_pipe1;
  140. static uv_pipe_t stdout_pipe1;
  141. static uv_pipe_t stdin_pipe2;
  142. static uv_pipe_t stdout_pipe2;
  143. static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
  144. ASSERT(nread > 0);
  145. ASSERT(memcmp("hello world\n", buf->base, nread) == 0);
  146. on_pipe_read_called++;
  147. free(buf->base);
  148. uv_read_stop(pipe);
  149. }
  150. static void after_pipe_write(uv_write_t* req, int status) {
  151. ASSERT(status == 0);
  152. after_write_called++;
  153. }
  154. static void on_read_alloc(uv_handle_t* handle,
  155. size_t suggested_size,
  156. uv_buf_t* buf) {
  157. buf->base = malloc(suggested_size);
  158. buf->len = suggested_size;
  159. }
  160. int stdio_over_pipes_helper(void) {
  161. /* Write several buffers to test that the write order is preserved. */
  162. char* buffers[] = {
  163. "he",
  164. "ll",
  165. "o ",
  166. "wo",
  167. "rl",
  168. "d",
  169. "\n"
  170. };
  171. uv_write_t write_req[ARRAY_SIZE(buffers)];
  172. uv_buf_t buf[ARRAY_SIZE(buffers)];
  173. unsigned int i;
  174. int j;
  175. int r;
  176. uv_loop_t* loop = uv_default_loop();
  177. ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
  178. ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
  179. r = uv_pipe_init(loop, &stdin_pipe1, 0);
  180. ASSERT(r == 0);
  181. r = uv_pipe_init(loop, &stdout_pipe1, 0);
  182. ASSERT(r == 0);
  183. r = uv_pipe_init(loop, &stdin_pipe2, 0);
  184. ASSERT(r == 0);
  185. r = uv_pipe_init(loop, &stdout_pipe2, 0);
  186. ASSERT(r == 0);
  187. uv_pipe_open(&stdin_pipe1, 0);
  188. uv_pipe_open(&stdout_pipe1, 1);
  189. uv_pipe_open(&stdin_pipe2, 0);
  190. uv_pipe_open(&stdout_pipe2, 1);
  191. for (j = 0; j < 2; j++) {
  192. /* Unref both stdio handles to make sure that all writes complete. */
  193. uv_unref((uv_handle_t*) &stdin_pipe1);
  194. uv_unref((uv_handle_t*) &stdout_pipe1);
  195. uv_unref((uv_handle_t*) &stdin_pipe2);
  196. uv_unref((uv_handle_t*) &stdout_pipe2);
  197. for (i = 0; i < ARRAY_SIZE(buffers); i++) {
  198. buf[i] = uv_buf_init((char*) buffers[i], strlen(buffers[i]));
  199. }
  200. for (i = 0; i < ARRAY_SIZE(buffers); i++) {
  201. r = uv_write(&write_req[i],
  202. (uv_stream_t*) (j == 0 ? &stdout_pipe1 : &stdout_pipe2),
  203. &buf[i],
  204. 1,
  205. after_pipe_write);
  206. ASSERT(r == 0);
  207. }
  208. notify_parent_process();
  209. uv_run(loop, UV_RUN_DEFAULT);
  210. ASSERT(after_write_called == 7 * (j + 1));
  211. ASSERT(on_pipe_read_called == j);
  212. ASSERT(close_cb_called == 0);
  213. uv_ref((uv_handle_t*) &stdout_pipe1);
  214. uv_ref((uv_handle_t*) &stdin_pipe1);
  215. uv_ref((uv_handle_t*) &stdout_pipe2);
  216. uv_ref((uv_handle_t*) &stdin_pipe2);
  217. r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2),
  218. on_read_alloc,
  219. on_pipe_read);
  220. ASSERT(r == 0);
  221. uv_run(loop, UV_RUN_DEFAULT);
  222. ASSERT(after_write_called == 7 * (j + 1));
  223. ASSERT(on_pipe_read_called == j + 1);
  224. ASSERT(close_cb_called == 0);
  225. }
  226. uv_close((uv_handle_t*)&stdin_pipe1, close_cb);
  227. uv_close((uv_handle_t*)&stdout_pipe1, close_cb);
  228. uv_close((uv_handle_t*)&stdin_pipe2, close_cb);
  229. uv_close((uv_handle_t*)&stdout_pipe2, close_cb);
  230. uv_run(loop, UV_RUN_DEFAULT);
  231. ASSERT(after_write_called == 14);
  232. ASSERT(on_pipe_read_called == 2);
  233. ASSERT(close_cb_called == 4);
  234. MAKE_VALGRIND_HAPPY();
  235. return 0;
  236. }