asyncengine 0.0.1.testing1 → 0.0.2.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. data/README.markdown +3 -0
  2. data/Rakefile +38 -0
  3. data/asyncengine.gemspec +8 -4
  4. data/ext/asyncengine/ae_call_from_other_thread.c +106 -0
  5. data/ext/asyncengine/ae_call_from_other_thread.h +12 -0
  6. data/ext/asyncengine/ae_handle_common.c +193 -48
  7. data/ext/asyncengine/ae_handle_common.h +40 -13
  8. data/ext/asyncengine/ae_ip_utils.c +246 -0
  9. data/ext/asyncengine/ae_ip_utils.h +25 -0
  10. data/ext/asyncengine/ae_next_tick.c +81 -21
  11. data/ext/asyncengine/ae_next_tick.h +4 -2
  12. data/ext/asyncengine/ae_resolver.c +156 -0
  13. data/ext/asyncengine/ae_resolver.h +10 -0
  14. data/ext/asyncengine/ae_tcp.c +908 -0
  15. data/ext/asyncengine/ae_tcp.h +20 -0
  16. data/ext/asyncengine/ae_timer.c +355 -81
  17. data/ext/asyncengine/ae_timer.h +11 -4
  18. data/ext/asyncengine/ae_udp.c +579 -13
  19. data/ext/asyncengine/ae_udp.h +15 -2
  20. data/ext/asyncengine/ae_utils.c +192 -0
  21. data/ext/asyncengine/ae_utils.h +16 -0
  22. data/ext/asyncengine/asyncengine_ruby.c +469 -26
  23. data/ext/asyncengine/asyncengine_ruby.h +49 -11
  24. data/ext/asyncengine/debug.h +68 -0
  25. data/ext/asyncengine/extconf.rb +26 -2
  26. data/ext/asyncengine/ip_parser.c +5954 -0
  27. data/ext/asyncengine/ip_parser.h +16 -0
  28. data/ext/asyncengine/libuv/AUTHORS +16 -0
  29. data/ext/asyncengine/libuv/common.gypi +4 -4
  30. data/ext/asyncengine/libuv/config-mingw.mk +6 -6
  31. data/ext/asyncengine/libuv/config-unix.mk +13 -13
  32. data/ext/asyncengine/libuv/gyp_uv +5 -1
  33. data/ext/asyncengine/libuv/ibc_tests/exec_test.sh +8 -0
  34. data/ext/asyncengine/libuv/ibc_tests/uv_shutdown_write_issue.c +171 -0
  35. data/ext/asyncengine/libuv/ibc_tests/uv_tcp_close_while_connecting.c +102 -0
  36. data/ext/asyncengine/libuv/include/uv-private/ngx-queue.h +3 -1
  37. data/ext/asyncengine/libuv/include/uv-private/uv-unix.h +103 -50
  38. data/ext/asyncengine/libuv/include/uv-private/uv-win.h +76 -24
  39. data/ext/asyncengine/libuv/include/uv.h +353 -88
  40. data/ext/asyncengine/libuv/src/ares/ares__close_sockets.o +0 -0
  41. data/ext/asyncengine/libuv/src/ares/ares__get_hostent.o +0 -0
  42. data/ext/asyncengine/libuv/src/ares/ares__read_line.o +0 -0
  43. data/ext/asyncengine/libuv/src/ares/ares__timeval.o +0 -0
  44. data/ext/asyncengine/libuv/src/ares/ares_cancel.o +0 -0
  45. data/ext/asyncengine/libuv/src/ares/ares_data.o +0 -0
  46. data/ext/asyncengine/libuv/src/ares/ares_destroy.o +0 -0
  47. data/ext/asyncengine/libuv/src/ares/ares_expand_name.o +0 -0
  48. data/ext/asyncengine/libuv/src/ares/ares_expand_string.o +0 -0
  49. data/ext/asyncengine/libuv/src/ares/ares_fds.o +0 -0
  50. data/ext/asyncengine/libuv/src/ares/ares_free_hostent.o +0 -0
  51. data/ext/asyncengine/libuv/src/ares/ares_free_string.o +0 -0
  52. data/ext/asyncengine/libuv/src/ares/ares_gethostbyaddr.o +0 -0
  53. data/ext/asyncengine/libuv/src/ares/ares_gethostbyname.o +0 -0
  54. data/ext/asyncengine/libuv/src/ares/ares_getnameinfo.o +0 -0
  55. data/ext/asyncengine/libuv/src/ares/ares_getopt.o +0 -0
  56. data/ext/asyncengine/libuv/src/ares/ares_getsock.o +0 -0
  57. data/ext/asyncengine/libuv/src/ares/ares_init.o +0 -0
  58. data/ext/asyncengine/libuv/src/ares/ares_library_init.o +0 -0
  59. data/ext/asyncengine/libuv/src/ares/ares_llist.o +0 -0
  60. data/ext/asyncengine/libuv/src/ares/ares_mkquery.o +0 -0
  61. data/ext/asyncengine/libuv/src/ares/ares_nowarn.o +0 -0
  62. data/ext/asyncengine/libuv/src/ares/ares_options.o +0 -0
  63. data/ext/asyncengine/libuv/src/ares/ares_parse_a_reply.o +0 -0
  64. data/ext/asyncengine/libuv/src/ares/ares_parse_aaaa_reply.o +0 -0
  65. data/ext/asyncengine/libuv/src/ares/ares_parse_mx_reply.o +0 -0
  66. data/ext/asyncengine/libuv/src/ares/ares_parse_ns_reply.o +0 -0
  67. data/ext/asyncengine/libuv/src/ares/ares_parse_ptr_reply.o +0 -0
  68. data/ext/asyncengine/libuv/src/ares/ares_parse_srv_reply.o +0 -0
  69. data/ext/asyncengine/libuv/src/ares/ares_parse_txt_reply.o +0 -0
  70. data/ext/asyncengine/libuv/src/ares/ares_process.o +0 -0
  71. data/ext/asyncengine/libuv/src/ares/ares_query.o +0 -0
  72. data/ext/asyncengine/libuv/src/ares/ares_search.o +0 -0
  73. data/ext/asyncengine/libuv/src/ares/ares_send.o +0 -0
  74. data/ext/asyncengine/libuv/src/ares/ares_strcasecmp.o +0 -0
  75. data/ext/asyncengine/libuv/src/ares/ares_strdup.o +0 -0
  76. data/ext/asyncengine/libuv/src/ares/ares_strerror.o +0 -0
  77. data/ext/asyncengine/libuv/src/ares/ares_timeout.o +0 -0
  78. data/ext/asyncengine/libuv/src/ares/ares_version.o +0 -0
  79. data/ext/asyncengine/libuv/src/ares/ares_writev.o +0 -0
  80. data/ext/asyncengine/libuv/src/ares/bitncmp.o +0 -0
  81. data/ext/asyncengine/libuv/src/ares/inet_net_pton.o +0 -0
  82. data/ext/asyncengine/libuv/src/ares/inet_ntop.o +0 -0
  83. data/ext/asyncengine/libuv/src/cares.c +225 -0
  84. data/ext/asyncengine/libuv/src/cares.o +0 -0
  85. data/ext/asyncengine/libuv/src/fs-poll.c +237 -0
  86. data/ext/asyncengine/libuv/src/fs-poll.o +0 -0
  87. data/ext/asyncengine/libuv/src/unix/async.c +78 -17
  88. data/ext/asyncengine/libuv/src/unix/async.o +0 -0
  89. data/ext/asyncengine/libuv/src/unix/core.c +305 -213
  90. data/ext/asyncengine/libuv/src/unix/core.o +0 -0
  91. data/ext/asyncengine/libuv/src/unix/cygwin.c +1 -1
  92. data/ext/asyncengine/libuv/src/unix/darwin.c +2 -1
  93. data/ext/asyncengine/libuv/src/unix/dl.c +36 -44
  94. data/ext/asyncengine/libuv/src/unix/dl.o +0 -0
  95. data/ext/asyncengine/libuv/src/unix/eio/eio.o +0 -0
  96. data/ext/asyncengine/libuv/src/unix/error.c +6 -0
  97. data/ext/asyncengine/libuv/src/unix/error.o +0 -0
  98. data/ext/asyncengine/libuv/src/unix/ev/ev.c +8 -4
  99. data/ext/asyncengine/libuv/src/unix/ev/ev.o +0 -0
  100. data/ext/asyncengine/libuv/src/unix/freebsd.c +1 -1
  101. data/ext/asyncengine/libuv/src/unix/fs.c +25 -33
  102. data/ext/asyncengine/libuv/src/unix/fs.o +0 -0
  103. data/ext/asyncengine/libuv/src/unix/internal.h +50 -31
  104. data/ext/asyncengine/libuv/src/unix/kqueue.c +2 -7
  105. data/ext/asyncengine/libuv/src/unix/linux/core.o +0 -0
  106. data/ext/asyncengine/libuv/src/unix/linux/inotify.c +12 -14
  107. data/ext/asyncengine/libuv/src/unix/linux/inotify.o +0 -0
  108. data/ext/asyncengine/libuv/src/unix/linux/{core.c → linux-core.c} +1 -1
  109. data/ext/asyncengine/libuv/src/unix/linux/linux-core.o +0 -0
  110. data/ext/asyncengine/libuv/src/unix/linux/syscalls.c +147 -1
  111. data/ext/asyncengine/libuv/src/unix/linux/syscalls.h +39 -2
  112. data/ext/asyncengine/libuv/src/unix/linux/syscalls.o +0 -0
  113. data/ext/asyncengine/libuv/src/unix/loop-watcher.c +63 -0
  114. data/ext/asyncengine/libuv/src/unix/loop-watcher.o +0 -0
  115. data/ext/asyncengine/libuv/src/unix/loop.c +29 -6
  116. data/ext/asyncengine/libuv/src/unix/loop.o +0 -0
  117. data/ext/asyncengine/libuv/src/unix/netbsd.c +1 -1
  118. data/ext/asyncengine/libuv/src/unix/openbsd.c +1 -1
  119. data/ext/asyncengine/libuv/src/unix/pipe.c +31 -36
  120. data/ext/asyncengine/libuv/src/unix/pipe.o +0 -0
  121. data/ext/asyncengine/libuv/src/unix/poll.c +116 -0
  122. data/ext/asyncengine/libuv/src/unix/poll.o +0 -0
  123. data/ext/asyncengine/libuv/src/unix/process.c +193 -115
  124. data/ext/asyncengine/libuv/src/unix/process.o +0 -0
  125. data/ext/asyncengine/libuv/src/unix/stream.c +146 -153
  126. data/ext/asyncengine/libuv/src/unix/stream.o +0 -0
  127. data/ext/asyncengine/libuv/src/unix/sunos.c +45 -36
  128. data/ext/asyncengine/libuv/src/unix/tcp.c +6 -5
  129. data/ext/asyncengine/libuv/src/unix/tcp.o +0 -0
  130. data/ext/asyncengine/libuv/src/unix/thread.c +82 -25
  131. data/ext/asyncengine/libuv/src/unix/thread.o +0 -0
  132. data/ext/asyncengine/libuv/src/unix/timer.c +69 -58
  133. data/ext/asyncengine/libuv/src/unix/timer.o +0 -0
  134. data/ext/asyncengine/libuv/src/unix/tty.c +3 -3
  135. data/ext/asyncengine/libuv/src/unix/tty.o +0 -0
  136. data/ext/asyncengine/libuv/src/unix/udp.c +57 -66
  137. data/ext/asyncengine/libuv/src/unix/udp.o +0 -0
  138. data/ext/asyncengine/libuv/src/unix/uv-eio.c +33 -50
  139. data/ext/asyncengine/libuv/src/unix/uv-eio.o +0 -0
  140. data/ext/asyncengine/libuv/src/uv-common.c +68 -38
  141. data/ext/asyncengine/libuv/src/uv-common.h +104 -20
  142. data/ext/asyncengine/libuv/src/uv-common.o +0 -0
  143. data/ext/asyncengine/libuv/src/win/async.c +20 -17
  144. data/ext/asyncengine/libuv/src/win/core.c +44 -31
  145. data/ext/asyncengine/libuv/src/win/dl.c +40 -36
  146. data/ext/asyncengine/libuv/src/win/error.c +21 -1
  147. data/ext/asyncengine/libuv/src/win/fs-event.c +19 -21
  148. data/ext/asyncengine/libuv/src/win/fs.c +541 -189
  149. data/ext/asyncengine/libuv/src/win/getaddrinfo.c +56 -63
  150. data/ext/asyncengine/libuv/src/win/handle-inl.h +145 -0
  151. data/ext/asyncengine/libuv/src/win/handle.c +26 -101
  152. data/ext/asyncengine/libuv/src/win/internal.h +92 -107
  153. data/ext/asyncengine/libuv/src/win/loop-watcher.c +6 -14
  154. data/ext/asyncengine/libuv/src/win/pipe.c +78 -64
  155. data/ext/asyncengine/libuv/src/win/poll.c +618 -0
  156. data/ext/asyncengine/libuv/src/win/process-stdio.c +479 -0
  157. data/ext/asyncengine/libuv/src/win/process.c +147 -274
  158. data/ext/asyncengine/libuv/src/win/req-inl.h +225 -0
  159. data/ext/asyncengine/libuv/src/win/req.c +0 -149
  160. data/ext/asyncengine/libuv/src/{unix/check.c → win/stream-inl.h} +31 -42
  161. data/ext/asyncengine/libuv/src/win/stream.c +9 -43
  162. data/ext/asyncengine/libuv/src/win/tcp.c +200 -82
  163. data/ext/asyncengine/libuv/src/win/thread.c +42 -2
  164. data/ext/asyncengine/libuv/src/win/threadpool.c +3 -2
  165. data/ext/asyncengine/libuv/src/win/timer.c +13 -63
  166. data/ext/asyncengine/libuv/src/win/tty.c +26 -20
  167. data/ext/asyncengine/libuv/src/win/udp.c +26 -17
  168. data/ext/asyncengine/libuv/src/win/util.c +312 -167
  169. data/ext/asyncengine/libuv/src/win/winapi.c +16 -1
  170. data/ext/asyncengine/libuv/src/win/winapi.h +33 -9
  171. data/ext/asyncengine/libuv/src/win/winsock.c +88 -1
  172. data/ext/asyncengine/libuv/src/win/winsock.h +36 -3
  173. data/ext/asyncengine/libuv/test/benchmark-ares.c +16 -17
  174. data/ext/asyncengine/libuv/test/benchmark-fs-stat.c +164 -0
  175. data/ext/asyncengine/libuv/test/benchmark-list.h +9 -0
  176. data/ext/asyncengine/libuv/{src/unix/prepare.c → test/benchmark-loop-count.c} +42 -33
  177. data/ext/asyncengine/libuv/test/benchmark-million-timers.c +65 -0
  178. data/ext/asyncengine/libuv/test/benchmark-pound.c +1 -1
  179. data/ext/asyncengine/libuv/test/benchmark-sizes.c +2 -0
  180. data/ext/asyncengine/libuv/test/benchmark-spawn.c +7 -1
  181. data/ext/asyncengine/libuv/test/benchmark-udp-packet-storm.c +1 -1
  182. data/ext/asyncengine/libuv/test/echo-server.c +8 -0
  183. data/ext/asyncengine/libuv/test/run-tests.c +30 -0
  184. data/ext/asyncengine/libuv/test/runner-unix.c +6 -26
  185. data/ext/asyncengine/libuv/test/runner-win.c +5 -63
  186. data/ext/asyncengine/libuv/test/runner.c +10 -1
  187. data/ext/asyncengine/libuv/test/task.h +0 -8
  188. data/ext/asyncengine/libuv/test/test-async.c +43 -141
  189. data/ext/asyncengine/libuv/test/test-callback-order.c +76 -0
  190. data/ext/asyncengine/libuv/test/test-counters-init.c +2 -3
  191. data/ext/asyncengine/libuv/test/test-dlerror.c +17 -8
  192. data/ext/asyncengine/libuv/test/test-fs-event.c +31 -39
  193. data/ext/asyncengine/libuv/test/test-fs-poll.c +146 -0
  194. data/ext/asyncengine/libuv/test/test-fs.c +114 -2
  195. data/ext/asyncengine/libuv/test/test-gethostbyname.c +8 -8
  196. data/ext/asyncengine/libuv/test/test-hrtime.c +18 -15
  197. data/ext/asyncengine/libuv/test/test-ipc.c +8 -2
  198. data/ext/asyncengine/libuv/test/test-list.h +59 -9
  199. data/ext/asyncengine/libuv/test/test-loop-handles.c +2 -25
  200. data/ext/asyncengine/libuv/{src/unix/idle.c → test/test-poll-close.c} +37 -39
  201. data/ext/asyncengine/libuv/test/test-poll.c +573 -0
  202. data/ext/asyncengine/libuv/test/test-ref.c +79 -63
  203. data/ext/asyncengine/libuv/test/test-run-once.c +15 -11
  204. data/ext/asyncengine/libuv/test/test-semaphore.c +111 -0
  205. data/ext/asyncengine/libuv/test/test-spawn.c +368 -20
  206. data/ext/asyncengine/libuv/test/test-stdio-over-pipes.c +25 -35
  207. data/ext/asyncengine/libuv/test/test-tcp-close-while-connecting.c +80 -0
  208. data/ext/asyncengine/libuv/test/test-tcp-close.c +1 -1
  209. data/ext/asyncengine/libuv/test/test-tcp-connect-error-after-write.c +95 -0
  210. data/ext/asyncengine/libuv/test/test-tcp-connect-timeout.c +85 -0
  211. data/ext/asyncengine/libuv/test/test-tcp-shutdown-after-write.c +131 -0
  212. data/ext/asyncengine/libuv/test/test-tcp-write-error.c +2 -2
  213. data/ext/asyncengine/libuv/test/test-tcp-writealot.c +29 -54
  214. data/ext/asyncengine/libuv/test/test-timer-again.c +1 -1
  215. data/ext/asyncengine/libuv/test/test-timer.c +23 -1
  216. data/ext/asyncengine/libuv/test/test-udp-options.c +1 -1
  217. data/ext/asyncengine/libuv/test/{test-eio-overflow.c → test-walk-handles.c} +31 -44
  218. data/ext/asyncengine/libuv/uv.gyp +26 -9
  219. data/ext/asyncengine/rb_utilities.c +54 -0
  220. data/ext/asyncengine/rb_utilities.h +63 -0
  221. data/lib/asyncengine.rb +45 -38
  222. data/lib/asyncengine/asyncengine_ext.so +0 -0
  223. data/lib/asyncengine/debug.rb +37 -0
  224. data/lib/asyncengine/handle.rb +9 -0
  225. data/lib/asyncengine/tcp.rb +28 -0
  226. data/lib/asyncengine/timer.rb +18 -28
  227. data/lib/asyncengine/udp.rb +29 -0
  228. data/lib/asyncengine/utils.rb +32 -0
  229. data/lib/asyncengine/uv_error.rb +17 -0
  230. data/lib/asyncengine/version.rb +9 -1
  231. data/test/ae_test_helper.rb +62 -0
  232. data/test/test_basic.rb +169 -0
  233. data/test/test_call_from_other_thread.rb +55 -0
  234. data/test/test_error.rb +92 -0
  235. data/test/test_ip_utils.rb +44 -0
  236. data/test/test_next_tick.rb +37 -0
  237. data/test/test_resolver.rb +51 -0
  238. data/test/test_threads.rb +69 -0
  239. data/test/test_timer.rb +95 -0
  240. data/test/test_udp.rb +216 -0
  241. data/test/test_utils.rb +49 -0
  242. metadata +84 -57
  243. data/ext/asyncengine/libuv/mkmf.log +0 -24
  244. data/ext/asyncengine/libuv/src/unix/cares.c +0 -194
  245. data/ext/asyncengine/libuv/src/unix/cares.o +0 -0
  246. data/ext/asyncengine/libuv/src/unix/check.o +0 -0
  247. data/ext/asyncengine/libuv/src/unix/idle.o +0 -0
  248. data/ext/asyncengine/libuv/src/unix/prepare.o +0 -0
  249. data/ext/asyncengine/libuv/src/win/cares.c +0 -290
  250. data/lib/asyncengine/errors.rb +0 -5
  251. data/lib/asyncengine/next_tick.rb +0 -24
@@ -19,18 +19,21 @@
19
19
  * IN THE SOFTWARE.
20
20
  */
21
21
 
22
- #include "uv.h"
23
- #include "../uv-common.h"
24
- #include "internal.h"
25
-
26
- #include <stdio.h>
27
22
  #include <assert.h>
23
+ #include <io.h>
24
+ #include <stdio.h>
28
25
  #include <stdlib.h>
29
26
  #include <signal.h>
30
- #include <windows.h>
27
+
28
+ #include "uv.h"
29
+ #include "internal.h"
30
+ #include "handle-inl.h"
31
+ #include "req-inl.h"
32
+
31
33
 
32
34
  #define SIGKILL 9
33
35
 
36
+
34
37
  typedef struct env_var {
35
38
  const char* narrow;
36
39
  const wchar_t* wide;
@@ -41,6 +44,7 @@ typedef struct env_var {
41
44
 
42
45
  #define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
43
46
 
47
+
44
48
  #define UTF8_TO_UTF16(s, t) \
45
49
  size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t); \
46
50
  t = (wchar_t*)malloc(size); \
@@ -55,18 +59,14 @@ typedef struct env_var {
55
59
 
56
60
 
57
61
  static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
58
- handle->type = UV_PROCESS;
59
- handle->loop = loop;
60
- handle->flags = 0;
62
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
61
63
  handle->exit_cb = NULL;
62
64
  handle->pid = 0;
63
65
  handle->exit_signal = 0;
64
66
  handle->wait_handle = INVALID_HANDLE_VALUE;
65
67
  handle->process_handle = INVALID_HANDLE_VALUE;
66
68
  handle->close_handle = INVALID_HANDLE_VALUE;
67
- handle->child_stdio[0] = INVALID_HANDLE_VALUE;
68
- handle->child_stdio[1] = INVALID_HANDLE_VALUE;
69
- handle->child_stdio[2] = INVALID_HANDLE_VALUE;
69
+ handle->child_stdio_buffer = NULL;
70
70
 
71
71
  uv_req_init(loop, (uv_req_t*)&handle->exit_req);
72
72
  handle->exit_req.type = UV_PROCESS_EXIT;
@@ -77,8 +77,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
77
77
 
78
78
  loop->counters.handle_init++;
79
79
  loop->counters.process_init++;
80
-
81
- uv_ref(loop);
82
80
  }
83
81
 
84
82
 
@@ -639,30 +637,32 @@ static DWORD WINAPI spawn_failure(void* data) {
639
637
  char unknown[] = "unknown error\n";
640
638
  uv_process_t* process = (uv_process_t*) data;
641
639
  uv_loop_t* loop = process->loop;
642
- HANDLE child_stderr = process->child_stdio[2];
640
+ HANDLE child_stderr = uv__stdio_handle(process->child_stdio_buffer, 2);
643
641
  char* buf = NULL;
644
642
  DWORD count, written;
645
643
 
646
- WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
647
-
648
- count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
649
- FORMAT_MESSAGE_FROM_SYSTEM |
650
- FORMAT_MESSAGE_IGNORE_INSERTS,
651
- NULL,
652
- process->spawn_errno,
653
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
654
- (LPSTR) &buf,
655
- 0,
656
- NULL);
657
-
658
- if (buf != NULL && count > 0) {
659
- WriteFile(child_stderr, buf, count, &written, NULL);
660
- LocalFree(buf);
661
- } else {
662
- WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
663
- }
644
+ if (child_stderr != INVALID_HANDLE_VALUE) {
645
+ WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
646
+
647
+ count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
648
+ FORMAT_MESSAGE_FROM_SYSTEM |
649
+ FORMAT_MESSAGE_IGNORE_INSERTS,
650
+ NULL,
651
+ process->spawn_errno,
652
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
653
+ (LPSTR) &buf,
654
+ 0,
655
+ NULL);
656
+
657
+ if (buf != NULL && count > 0) {
658
+ WriteFile(child_stderr, buf, count, &written, NULL);
659
+ LocalFree(buf);
660
+ } else {
661
+ WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
662
+ }
664
663
 
665
- FlushFileBuffers(child_stderr);
664
+ FlushFileBuffers(child_stderr);
665
+ }
666
666
 
667
667
  /* Post completed */
668
668
  POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
@@ -671,48 +671,32 @@ static DWORD WINAPI spawn_failure(void* data) {
671
671
  }
672
672
 
673
673
 
674
- static void close_child_stdio(uv_process_t* process) {
675
- int i;
676
- HANDLE handle;
677
-
678
- for (i = 0; i < ARRAY_SIZE(process->child_stdio); i++) {
679
- handle = process->child_stdio[i];
680
- if (handle != NULL && handle != INVALID_HANDLE_VALUE) {
681
- CloseHandle(handle);
682
- process->child_stdio[i] = INVALID_HANDLE_VALUE;
683
- }
684
- }
685
- }
686
-
687
-
688
674
  /* Called on main thread after a child process has exited. */
689
675
  void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
690
676
  DWORD exit_code;
691
677
 
678
+ /* FIXME: race condition. */
679
+ if (handle->flags & UV_HANDLE_CLOSING) {
680
+ return;
681
+ }
682
+
692
683
  /* Unregister from process notification. */
693
684
  if (handle->wait_handle != INVALID_HANDLE_VALUE) {
694
685
  UnregisterWait(handle->wait_handle);
695
686
  handle->wait_handle = INVALID_HANDLE_VALUE;
696
687
  }
697
688
 
698
- if (handle->process_handle != INVALID_HANDLE_VALUE) {
699
- /* Get the exit code. */
700
- if (!GetExitCodeProcess(handle->process_handle, &exit_code)) {
701
- exit_code = 127;
702
- }
703
-
704
- /* Clean-up the process handle. */
705
- CloseHandle(handle->process_handle);
706
- handle->process_handle = INVALID_HANDLE_VALUE;
707
- } else {
708
- /* We probably left the child stdio handles open to report the error */
709
- /* asynchronously, so close them now. */
710
- close_child_stdio(handle);
711
-
712
- /* The process never even started in the first place. */
689
+ if (handle->process_handle == INVALID_HANDLE_VALUE ||
690
+ !GetExitCodeProcess(handle->process_handle, &exit_code)) {
691
+ /* The process never even started in the first place, or we were unable */
692
+ /* to obtain the exit code. */
713
693
  exit_code = 127;
714
694
  }
715
695
 
696
+ /* Set the handle to inactive: no callbacks will be made after the exit */
697
+ /* callback.*/
698
+ uv__handle_stop(handle);
699
+
716
700
  /* Fire the exit callback. */
717
701
  if (handle->exit_cb) {
718
702
  handle->exit_cb(handle, exit_code, handle->exit_signal);
@@ -726,21 +710,9 @@ void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) {
726
710
  }
727
711
 
728
712
 
729
- void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
730
- if (handle->flags & UV_HANDLE_CLOSING) {
731
- assert(!(handle->flags & UV_HANDLE_CLOSED));
732
- handle->flags |= UV_HANDLE_CLOSED;
733
-
734
- if (handle->close_cb) {
735
- handle->close_cb((uv_handle_t*)handle);
736
- }
737
-
738
- uv_unref(loop);
739
- }
740
- }
741
-
742
-
743
713
  void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
714
+ uv__handle_start(handle);
715
+
744
716
  if (handle->wait_handle != INVALID_HANDLE_VALUE) {
745
717
  handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
746
718
  UnregisterWaitEx(handle->wait_handle, handle->close_handle);
@@ -755,134 +727,52 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
755
727
  }
756
728
 
757
729
 
758
- static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
759
- HANDLE* child_pipe, DWORD server_access, DWORD child_access,
760
- int overlapped) {
761
- int err;
762
- SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
763
- char pipe_name[64];
764
- DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
765
-
766
- if (server_pipe->type != UV_NAMED_PIPE) {
767
- uv__set_artificial_error(loop, UV_EINVAL);
768
- err = -1;
769
- goto done;
770
- }
771
-
772
- /* Create server pipe handle. */
773
- err = uv_stdio_pipe_server(loop,
774
- server_pipe,
775
- server_access,
776
- pipe_name,
777
- sizeof(pipe_name));
778
- if (err) {
779
- goto done;
780
- }
781
-
782
- /* Create child pipe handle. */
783
- *child_pipe = CreateFileA(pipe_name,
784
- child_access,
785
- 0,
786
- &sa,
787
- OPEN_EXISTING,
788
- overlapped ? FILE_FLAG_OVERLAPPED : 0,
789
- NULL);
790
-
791
- if (*child_pipe == INVALID_HANDLE_VALUE) {
792
- uv__set_sys_error(loop, GetLastError());
793
- err = -1;
794
- goto done;
795
- }
796
-
797
- if (!SetNamedPipeHandleState(*child_pipe, &mode, NULL, NULL)) {
798
- uv__set_sys_error(loop, GetLastError());
799
- err = -1;
800
- goto done;
801
- }
802
-
803
- /* Do a blocking ConnectNamedPipe. This should not block because
804
- * we have both ends of the pipe created.
805
- */
806
- if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
807
- if (GetLastError() != ERROR_PIPE_CONNECTED) {
808
- uv__set_sys_error(loop, GetLastError());
809
- err = -1;
810
- goto done;
811
- }
812
- }
813
-
814
- err = 0;
730
+ void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
731
+ if (handle->flags & UV_HANDLE_CLOSING) {
732
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
733
+ uv__handle_stop(handle);
815
734
 
816
- done:
817
- if (err) {
818
- if (server_pipe->handle != INVALID_HANDLE_VALUE) {
819
- close_pipe(server_pipe, NULL, NULL);
820
- }
735
+ /* Clean-up the process handle. */
736
+ CloseHandle(handle->process_handle);
821
737
 
822
- if (*child_pipe != INVALID_HANDLE_VALUE) {
823
- CloseHandle(*child_pipe);
824
- *child_pipe = INVALID_HANDLE_VALUE;
738
+ /* Clean up the child stdio ends that may have been left open. */
739
+ if (handle->child_stdio_buffer != NULL) {
740
+ uv__stdio_destroy(handle->child_stdio_buffer);
825
741
  }
826
- }
827
-
828
- return err;
829
- }
830
-
831
-
832
- static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
833
- HANDLE handle;
834
- HANDLE current_process = GetCurrentProcess();
835
-
836
- handle = GetStdHandle(id);
837
-
838
- if (handle == NULL) {
839
- *dup = NULL;
840
- return 0;
841
- } else if (handle == INVALID_HANDLE_VALUE) {
842
- *dup = INVALID_HANDLE_VALUE;
843
- uv__set_sys_error(loop, GetLastError());
844
- return -1;
845
- }
846
742
 
847
- if (!DuplicateHandle(current_process,
848
- handle,
849
- current_process,
850
- dup,
851
- 0,
852
- TRUE,
853
- DUPLICATE_SAME_ACCESS)) {
854
- *dup = INVALID_HANDLE_VALUE;
855
- uv__set_sys_error(loop, GetLastError());
856
- return -1;
743
+ uv__handle_close(handle);
857
744
  }
858
-
859
- return 0;
860
745
  }
861
746
 
862
747
 
863
748
  int uv_spawn(uv_loop_t* loop, uv_process_t* process,
864
749
  uv_process_options_t options) {
865
- int err = 0, keep_child_stdio_open = 0;
750
+ int i, size, err = 0, keep_child_stdio_open = 0;
866
751
  wchar_t* path = NULL;
867
- int size;
868
752
  BOOL result;
869
753
  wchar_t* application_path = NULL, *application = NULL, *arguments = NULL,
870
- *env = NULL, *cwd = NULL;
871
- HANDLE* child_stdio = process->child_stdio;
754
+ *env = NULL, *cwd = NULL;
872
755
  STARTUPINFOW startup;
873
756
  PROCESS_INFORMATION info;
757
+ DWORD process_flags;
874
758
 
875
- if (!options.file) {
876
- uv__set_artificial_error(loop, UV_EINVAL);
759
+ if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
760
+ uv__set_artificial_error(loop, UV_ENOTSUP);
877
761
  return -1;
878
762
  }
879
763
 
764
+ assert(options.file != NULL);
765
+ assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
766
+ UV_PROCESS_DETACHED |
767
+ UV_PROCESS_SETGID |
768
+ UV_PROCESS_SETUID)));
769
+
880
770
  uv_process_init(loop, process);
881
771
 
882
772
  process->exit_cb = options.exit_cb;
883
773
  UTF8_TO_UTF16(options.file, application);
884
774
  arguments = options.args ? make_program_args(options.args,
885
- options.windows_verbatim_arguments) : NULL;
775
+ options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL;
886
776
  env = options.env ? make_program_env(options.env) : NULL;
887
777
 
888
778
  if (options.cwd) {
@@ -892,8 +782,11 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
892
782
  if (size) {
893
783
  cwd = (wchar_t*)malloc(size);
894
784
  if (!cwd) {
895
- uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
785
+ uv__set_artificial_error(loop, UV_ENOMEM);
786
+ err = -1;
787
+ goto done;
896
788
  }
789
+
897
790
  GetCurrentDirectoryW(size, cwd);
898
791
  } else {
899
792
  uv__set_sys_error(loop, GetLastError());
@@ -921,59 +814,10 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
921
814
  application_path = application;
922
815
  }
923
816
 
924
- /* Create stdio pipes. */
925
- if (options.stdin_stream) {
926
- if (options.stdin_stream->ipc) {
927
- err = uv_create_stdio_pipe_pair(
928
- loop,
929
- options.stdin_stream,
930
- &child_stdio[0],
931
- PIPE_ACCESS_DUPLEX,
932
- GENERIC_READ | FILE_WRITE_ATTRIBUTES | GENERIC_WRITE,
933
- 1);
934
- } else {
935
- err = uv_create_stdio_pipe_pair(
936
- loop,
937
- options.stdin_stream,
938
- &child_stdio[0],
939
- PIPE_ACCESS_OUTBOUND,
940
- GENERIC_READ | FILE_WRITE_ATTRIBUTES,
941
- 0);
942
- }
943
- } else {
944
- err = duplicate_std_handle(loop, STD_INPUT_HANDLE, &child_stdio[0]);
945
- }
946
- if (err) {
947
- goto done;
948
- }
949
-
950
- if (options.stdout_stream) {
951
- err = uv_create_stdio_pipe_pair(
952
- loop, options.stdout_stream,
953
- &child_stdio[1],
954
- PIPE_ACCESS_INBOUND,
955
- GENERIC_WRITE,
956
- 0);
957
- } else {
958
- err = duplicate_std_handle(loop, STD_OUTPUT_HANDLE, &child_stdio[1]);
959
- }
960
- if (err) {
961
- goto done;
962
- }
963
817
 
964
- if (options.stderr_stream) {
965
- err = uv_create_stdio_pipe_pair(
966
- loop,
967
- options.stderr_stream,
968
- &child_stdio[2],
969
- PIPE_ACCESS_INBOUND,
970
- GENERIC_WRITE,
971
- 0);
972
- } else {
973
- err = duplicate_std_handle(loop, STD_ERROR_HANDLE, &child_stdio[2]);
974
- }
975
- if (err) {
976
- goto done;
818
+ if (uv__stdio_create(loop, &options, &process->child_stdio_buffer) < 0) {
819
+ err = -1;
820
+ goto done;
977
821
  }
978
822
 
979
823
  startup.cb = sizeof(startup);
@@ -981,18 +825,23 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
981
825
  startup.lpDesktop = NULL;
982
826
  startup.lpTitle = NULL;
983
827
  startup.dwFlags = STARTF_USESTDHANDLES;
984
- startup.cbReserved2 = 0;
985
- startup.lpReserved2 = NULL;
986
- startup.hStdInput = child_stdio[0];
987
- startup.hStdOutput = child_stdio[1];
988
- startup.hStdError = child_stdio[2];
828
+ startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
829
+ startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
830
+ startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
831
+ startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
832
+ startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
833
+
834
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
835
+ if (options.flags & UV_PROCESS_DETACHED) {
836
+ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
837
+ }
989
838
 
990
839
  if (CreateProcessW(application_path,
991
840
  arguments,
992
841
  NULL,
993
842
  NULL,
994
843
  1,
995
- CREATE_UNICODE_ENVIRONMENT,
844
+ process_flags,
996
845
  env,
997
846
  cwd,
998
847
  &startup,
@@ -1001,9 +850,14 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
1001
850
  process->process_handle = info.hProcess;
1002
851
  process->pid = info.dwProcessId;
1003
852
 
1004
- if (options.stdin_stream &&
1005
- options.stdin_stream->ipc) {
1006
- options.stdin_stream->ipc_pid = info.dwProcessId;
853
+ /* Set IPC pid to all IPC pipes. */
854
+ for (i = 0; i < options.stdio_count; i++) {
855
+ const uv_stdio_container_t* fdopt = &options.stdio[i];
856
+ if (fdopt->flags & UV_CREATE_PIPE &&
857
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
858
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
859
+ ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId;
860
+ }
1007
861
  }
1008
862
 
1009
863
  /* Setup notifications for when the child process exits. */
@@ -1038,22 +892,27 @@ done:
1038
892
  free(env);
1039
893
  free(path);
1040
894
 
1041
- /* Under normal circumstances we should close the stdio handles now - */
1042
- /* the child now has its own duplicates, or something went horribly wrong. */
895
+ /* Under normal circumstances we should close the stdio handles now - the */
896
+ /* the child now has its own duplicates, or something went horribly wrong */
1043
897
  /* The only exception is when CreateProcess has failed, then we actually */
1044
898
  /* need to keep the stdio handles to report the error asynchronously. */
1045
- if (!keep_child_stdio_open) {
1046
- close_child_stdio(process);
899
+ if (process->child_stdio_buffer == NULL) {
900
+ /* Something went wrong before child stdio was initialized. */
901
+ } else if (!keep_child_stdio_open) {
902
+ uv__stdio_destroy(process->child_stdio_buffer);
903
+ process->child_stdio_buffer = NULL;
1047
904
  } else {
1048
905
  /* We're keeping the handles open, the thread pool is going to have */
1049
906
  /* it's way with them. But at least make them non-inheritable. */
1050
- int i;
1051
- for (i = 0; i < ARRAY_SIZE(process->child_stdio); i++) {
1052
- SetHandleInformation(child_stdio[i], HANDLE_FLAG_INHERIT, 0);
1053
- }
907
+ uv__stdio_noinherit(process->child_stdio_buffer);
1054
908
  }
1055
909
 
1056
- if (err) {
910
+ if (err == 0) {
911
+ /* Spawn was succesful. The handle will be active until the exit */
912
+ /* is made or the handle is closed, whichever happens first. */
913
+ uv__handle_start(process);
914
+ } else {
915
+ /* Spawn was not successful. Clean up. */
1057
916
  if (process->wait_handle != INVALID_HANDLE_VALUE) {
1058
917
  UnregisterWait(process->wait_handle);
1059
918
  process->wait_handle = INVALID_HANDLE_VALUE;
@@ -1070,32 +929,46 @@ done:
1070
929
 
1071
930
 
1072
931
  static uv_err_t uv__kill(HANDLE process_handle, int signum) {
1073
- DWORD status;
1074
- uv_err_t err;
932
+ switch (signum) {
933
+ case SIGTERM:
934
+ case SIGKILL:
935
+ case SIGINT: {
936
+ /* Unconditionally terminate the process. On Windows, killed processes */
937
+ /* normally return 1. */
938
+ DWORD error, status;
939
+
940
+ if (TerminateProcess(process_handle, 1))
941
+ return uv_ok_;
942
+
943
+ /* If the process already exited before TerminateProcess was called, */
944
+ /* TerminateProcess will fail with ERROR_ACESS_DENIED. */
945
+ error = GetLastError();
946
+ if (error == ERROR_ACCESS_DENIED &&
947
+ GetExitCodeProcess(process_handle, &status) &&
948
+ status != STILL_ACTIVE) {
949
+ return uv__new_artificial_error(UV_ESRCH);
950
+ }
1075
951
 
1076
- if (signum == SIGTERM || signum == SIGKILL || signum == SIGINT) {
1077
- /* Kill the process. On Windows, killed processes normally return 1. */
1078
- if (TerminateProcess(process_handle, 1)) {
1079
- err = uv_ok_;
1080
- } else {
1081
- err = uv__new_sys_error(GetLastError());
952
+ return uv__new_sys_error(error);
1082
953
  }
1083
- } else if (signum == 0) {
1084
- /* Health check: is the process still alive? */
1085
- if (GetExitCodeProcess(process_handle, &status)) {
1086
- if (status == STILL_ACTIVE) {
1087
- err = uv_ok_;
1088
- } else {
1089
- err = uv__new_artificial_error(UV_ESRCH);
1090
- }
1091
- } else {
1092
- err = uv__new_sys_error(GetLastError());
954
+
955
+ case 0: {
956
+ /* Health check: is the process still alive? */
957
+ DWORD status;
958
+
959
+ if (!GetExitCodeProcess(process_handle, &status))
960
+ return uv__new_sys_error(GetLastError());
961
+
962
+ if (status != STILL_ACTIVE)
963
+ return uv__new_artificial_error(UV_ESRCH);
964
+
965
+ return uv_ok_;
1093
966
  }
1094
- } else {
1095
- err = uv__new_artificial_error(UV_ENOSYS);
1096
- }
1097
967
 
1098
- return err;
968
+ default:
969
+ /* Unsupported signal. */
970
+ return uv__new_artificial_error(UV_ENOSYS);
971
+ }
1099
972
  }
1100
973
 
1101
974