rbuv 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +0 -1
  6. data/README.md +6 -1
  7. data/Rakefile +42 -0
  8. data/deps/libuv/.gitignore +34 -0
  9. data/deps/libuv/.mailmap +16 -0
  10. data/deps/libuv/AUTHORS +81 -0
  11. data/deps/libuv/ChangeLog +45 -0
  12. data/deps/libuv/LICENSE +41 -0
  13. data/deps/libuv/Makefile +53 -0
  14. data/deps/libuv/README.md +118 -0
  15. data/deps/libuv/build.mk +164 -0
  16. data/deps/libuv/checksparse.sh +230 -0
  17. data/deps/libuv/common.gypi +197 -0
  18. data/deps/libuv/config-mingw.mk +48 -0
  19. data/deps/libuv/config-unix.mk +167 -0
  20. data/deps/libuv/gyp_uv +98 -0
  21. data/deps/libuv/include/uv-private/ngx-queue.h +129 -0
  22. data/deps/libuv/include/uv-private/stdint-msvc2008.h +247 -0
  23. data/deps/libuv/include/uv-private/tree.h +768 -0
  24. data/deps/libuv/include/uv-private/uv-bsd.h +34 -0
  25. data/deps/libuv/include/uv-private/uv-darwin.h +61 -0
  26. data/deps/libuv/include/uv-private/uv-linux.h +34 -0
  27. data/deps/libuv/include/uv-private/uv-sunos.h +44 -0
  28. data/deps/libuv/include/uv-private/uv-unix.h +332 -0
  29. data/deps/libuv/include/uv-private/uv-win.h +585 -0
  30. data/deps/libuv/include/uv.h +1987 -0
  31. data/deps/libuv/src/fs-poll.c +248 -0
  32. data/deps/libuv/src/inet.c +298 -0
  33. data/deps/libuv/src/unix/aix.c +393 -0
  34. data/deps/libuv/src/unix/async.c +281 -0
  35. data/deps/libuv/src/unix/core.c +714 -0
  36. data/deps/libuv/src/unix/cygwin.c +93 -0
  37. data/deps/libuv/src/unix/darwin-proctitle.m +78 -0
  38. data/deps/libuv/src/unix/darwin.c +431 -0
  39. data/deps/libuv/src/unix/dl.c +83 -0
  40. data/deps/libuv/src/unix/error.c +109 -0
  41. data/deps/libuv/src/unix/freebsd.c +343 -0
  42. data/deps/libuv/src/unix/fs.c +869 -0
  43. data/deps/libuv/src/unix/fsevents.c +299 -0
  44. data/deps/libuv/src/unix/getaddrinfo.c +159 -0
  45. data/deps/libuv/src/unix/internal.h +259 -0
  46. data/deps/libuv/src/unix/kqueue.c +347 -0
  47. data/deps/libuv/src/unix/linux-core.c +724 -0
  48. data/deps/libuv/src/unix/linux-inotify.c +236 -0
  49. data/deps/libuv/src/unix/linux-syscalls.c +388 -0
  50. data/deps/libuv/src/unix/linux-syscalls.h +150 -0
  51. data/deps/libuv/src/unix/loop-watcher.c +64 -0
  52. data/deps/libuv/src/unix/loop.c +114 -0
  53. data/deps/libuv/src/unix/netbsd.c +353 -0
  54. data/deps/libuv/src/unix/openbsd.c +304 -0
  55. data/deps/libuv/src/unix/pipe.c +261 -0
  56. data/deps/libuv/src/unix/poll.c +108 -0
  57. data/deps/libuv/src/unix/process.c +501 -0
  58. data/deps/libuv/src/unix/proctitle.c +103 -0
  59. data/deps/libuv/src/unix/signal.c +455 -0
  60. data/deps/libuv/src/unix/stream.c +1380 -0
  61. data/deps/libuv/src/unix/sunos.c +647 -0
  62. data/deps/libuv/src/unix/tcp.c +357 -0
  63. data/deps/libuv/src/unix/thread.c +431 -0
  64. data/deps/libuv/src/unix/threadpool.c +286 -0
  65. data/deps/libuv/src/unix/timer.c +153 -0
  66. data/deps/libuv/src/unix/tty.c +179 -0
  67. data/deps/libuv/src/unix/udp.c +715 -0
  68. data/deps/libuv/src/uv-common.c +431 -0
  69. data/deps/libuv/src/uv-common.h +204 -0
  70. data/deps/libuv/src/version.c +60 -0
  71. data/deps/libuv/src/win/async.c +99 -0
  72. data/deps/libuv/src/win/atomicops-inl.h +56 -0
  73. data/deps/libuv/src/win/core.c +310 -0
  74. data/deps/libuv/src/win/dl.c +86 -0
  75. data/deps/libuv/src/win/error.c +164 -0
  76. data/deps/libuv/src/win/fs-event.c +506 -0
  77. data/deps/libuv/src/win/fs.c +1951 -0
  78. data/deps/libuv/src/win/getaddrinfo.c +365 -0
  79. data/deps/libuv/src/win/handle-inl.h +164 -0
  80. data/deps/libuv/src/win/handle.c +153 -0
  81. data/deps/libuv/src/win/internal.h +346 -0
  82. data/deps/libuv/src/win/loop-watcher.c +124 -0
  83. data/deps/libuv/src/win/pipe.c +1656 -0
  84. data/deps/libuv/src/win/poll.c +615 -0
  85. data/deps/libuv/src/win/process-stdio.c +503 -0
  86. data/deps/libuv/src/win/process.c +1048 -0
  87. data/deps/libuv/src/win/req-inl.h +224 -0
  88. data/deps/libuv/src/win/req.c +25 -0
  89. data/deps/libuv/src/win/signal.c +354 -0
  90. data/deps/libuv/src/win/stream-inl.h +67 -0
  91. data/deps/libuv/src/win/stream.c +198 -0
  92. data/deps/libuv/src/win/tcp.c +1422 -0
  93. data/deps/libuv/src/win/thread.c +666 -0
  94. data/deps/libuv/src/win/threadpool.c +82 -0
  95. data/deps/libuv/src/win/timer.c +230 -0
  96. data/deps/libuv/src/win/tty.c +1857 -0
  97. data/deps/libuv/src/win/udp.c +744 -0
  98. data/deps/libuv/src/win/util.c +946 -0
  99. data/deps/libuv/src/win/winapi.c +152 -0
  100. data/deps/libuv/src/win/winapi.h +4476 -0
  101. data/deps/libuv/src/win/winsock.c +560 -0
  102. data/deps/libuv/src/win/winsock.h +171 -0
  103. data/deps/libuv/test/benchmark-async-pummel.c +119 -0
  104. data/deps/libuv/test/benchmark-async.c +139 -0
  105. data/deps/libuv/test/benchmark-fs-stat.c +136 -0
  106. data/deps/libuv/test/benchmark-getaddrinfo.c +91 -0
  107. data/deps/libuv/test/benchmark-list.h +163 -0
  108. data/deps/libuv/test/benchmark-loop-count.c +90 -0
  109. data/deps/libuv/test/benchmark-million-async.c +112 -0
  110. data/deps/libuv/test/benchmark-million-timers.c +77 -0
  111. data/deps/libuv/test/benchmark-multi-accept.c +432 -0
  112. data/deps/libuv/test/benchmark-ping-pongs.c +212 -0
  113. data/deps/libuv/test/benchmark-pound.c +325 -0
  114. data/deps/libuv/test/benchmark-pump.c +459 -0
  115. data/deps/libuv/test/benchmark-sizes.c +45 -0
  116. data/deps/libuv/test/benchmark-spawn.c +163 -0
  117. data/deps/libuv/test/benchmark-tcp-write-batch.c +141 -0
  118. data/deps/libuv/test/benchmark-thread.c +64 -0
  119. data/deps/libuv/test/benchmark-udp-pummel.c +238 -0
  120. data/deps/libuv/test/blackhole-server.c +118 -0
  121. data/deps/libuv/test/dns-server.c +329 -0
  122. data/deps/libuv/test/echo-server.c +384 -0
  123. data/deps/libuv/test/fixtures/empty_file +0 -0
  124. data/deps/libuv/test/fixtures/load_error.node +1 -0
  125. data/deps/libuv/test/run-benchmarks.c +64 -0
  126. data/deps/libuv/test/run-tests.c +159 -0
  127. data/deps/libuv/test/runner-unix.c +328 -0
  128. data/deps/libuv/test/runner-unix.h +36 -0
  129. data/deps/libuv/test/runner-win.c +318 -0
  130. data/deps/libuv/test/runner-win.h +43 -0
  131. data/deps/libuv/test/runner.c +394 -0
  132. data/deps/libuv/test/runner.h +165 -0
  133. data/deps/libuv/test/task.h +122 -0
  134. data/deps/libuv/test/test-active.c +83 -0
  135. data/deps/libuv/test/test-async.c +136 -0
  136. data/deps/libuv/test/test-barrier.c +98 -0
  137. data/deps/libuv/test/test-callback-order.c +77 -0
  138. data/deps/libuv/test/test-callback-stack.c +204 -0
  139. data/deps/libuv/test/test-condvar.c +173 -0
  140. data/deps/libuv/test/test-connection-fail.c +150 -0
  141. data/deps/libuv/test/test-cwd-and-chdir.c +64 -0
  142. data/deps/libuv/test/test-delayed-accept.c +189 -0
  143. data/deps/libuv/test/test-dlerror.c +58 -0
  144. data/deps/libuv/test/test-embed.c +136 -0
  145. data/deps/libuv/test/test-error.c +59 -0
  146. data/deps/libuv/test/test-fail-always.c +29 -0
  147. data/deps/libuv/test/test-fs-event.c +504 -0
  148. data/deps/libuv/test/test-fs-poll.c +148 -0
  149. data/deps/libuv/test/test-fs.c +1899 -0
  150. data/deps/libuv/test/test-get-currentexe.c +63 -0
  151. data/deps/libuv/test/test-get-loadavg.c +36 -0
  152. data/deps/libuv/test/test-get-memory.c +38 -0
  153. data/deps/libuv/test/test-getaddrinfo.c +120 -0
  154. data/deps/libuv/test/test-getsockname.c +344 -0
  155. data/deps/libuv/test/test-hrtime.c +54 -0
  156. data/deps/libuv/test/test-idle.c +82 -0
  157. data/deps/libuv/test/test-ipc-send-recv.c +218 -0
  158. data/deps/libuv/test/test-ipc.c +625 -0
  159. data/deps/libuv/test/test-list.h +492 -0
  160. data/deps/libuv/test/test-loop-handles.c +337 -0
  161. data/deps/libuv/test/test-loop-stop.c +73 -0
  162. data/deps/libuv/test/test-multiple-listen.c +103 -0
  163. data/deps/libuv/test/test-mutexes.c +63 -0
  164. data/deps/libuv/test/test-pass-always.c +28 -0
  165. data/deps/libuv/test/test-ping-pong.c +250 -0
  166. data/deps/libuv/test/test-pipe-bind-error.c +144 -0
  167. data/deps/libuv/test/test-pipe-connect-error.c +98 -0
  168. data/deps/libuv/test/test-platform-output.c +87 -0
  169. data/deps/libuv/test/test-poll-close.c +73 -0
  170. data/deps/libuv/test/test-poll.c +575 -0
  171. data/deps/libuv/test/test-process-title.c +49 -0
  172. data/deps/libuv/test/test-ref.c +415 -0
  173. data/deps/libuv/test/test-run-nowait.c +46 -0
  174. data/deps/libuv/test/test-run-once.c +49 -0
  175. data/deps/libuv/test/test-semaphore.c +111 -0
  176. data/deps/libuv/test/test-shutdown-close.c +105 -0
  177. data/deps/libuv/test/test-shutdown-eof.c +184 -0
  178. data/deps/libuv/test/test-signal-multiple-loops.c +270 -0
  179. data/deps/libuv/test/test-signal.c +152 -0
  180. data/deps/libuv/test/test-spawn.c +938 -0
  181. data/deps/libuv/test/test-stdio-over-pipes.c +250 -0
  182. data/deps/libuv/test/test-tcp-bind-error.c +198 -0
  183. data/deps/libuv/test/test-tcp-bind6-error.c +159 -0
  184. data/deps/libuv/test/test-tcp-close-while-connecting.c +81 -0
  185. data/deps/libuv/test/test-tcp-close.c +130 -0
  186. data/deps/libuv/test/test-tcp-connect-error-after-write.c +96 -0
  187. data/deps/libuv/test/test-tcp-connect-error.c +71 -0
  188. data/deps/libuv/test/test-tcp-connect-timeout.c +86 -0
  189. data/deps/libuv/test/test-tcp-connect6-error.c +69 -0
  190. data/deps/libuv/test/test-tcp-flags.c +52 -0
  191. data/deps/libuv/test/test-tcp-open.c +175 -0
  192. data/deps/libuv/test/test-tcp-read-stop.c +73 -0
  193. data/deps/libuv/test/test-tcp-shutdown-after-write.c +132 -0
  194. data/deps/libuv/test/test-tcp-unexpected-read.c +114 -0
  195. data/deps/libuv/test/test-tcp-write-to-half-open-connection.c +136 -0
  196. data/deps/libuv/test/test-tcp-writealot.c +171 -0
  197. data/deps/libuv/test/test-thread.c +183 -0
  198. data/deps/libuv/test/test-threadpool-cancel.c +311 -0
  199. data/deps/libuv/test/test-threadpool.c +77 -0
  200. data/deps/libuv/test/test-timer-again.c +142 -0
  201. data/deps/libuv/test/test-timer.c +266 -0
  202. data/deps/libuv/test/test-tty.c +111 -0
  203. data/deps/libuv/test/test-udp-dgram-too-big.c +87 -0
  204. data/deps/libuv/test/test-udp-ipv6.c +158 -0
  205. data/deps/libuv/test/test-udp-multicast-join.c +140 -0
  206. data/deps/libuv/test/test-udp-multicast-ttl.c +87 -0
  207. data/deps/libuv/test/test-udp-open.c +154 -0
  208. data/deps/libuv/test/test-udp-options.c +87 -0
  209. data/deps/libuv/test/test-udp-send-and-recv.c +210 -0
  210. data/deps/libuv/test/test-util.c +97 -0
  211. data/deps/libuv/test/test-walk-handles.c +78 -0
  212. data/deps/libuv/uv.gyp +431 -0
  213. data/deps/libuv/vcbuild.bat +128 -0
  214. data/ext/rbuv/debug.h +27 -0
  215. data/ext/rbuv/error.c +7 -0
  216. data/ext/rbuv/error.h +10 -0
  217. data/ext/rbuv/extconf.rb +35 -0
  218. data/ext/rbuv/handle.c +40 -0
  219. data/ext/rbuv/handle.h +14 -0
  220. data/ext/rbuv/libuv.mk +12 -0
  221. data/ext/rbuv/loop.c +50 -0
  222. data/ext/rbuv/loop.h +13 -0
  223. data/ext/rbuv/rbuv.c +15 -0
  224. data/ext/rbuv/rbuv.h +27 -0
  225. data/ext/rbuv/timer.c +133 -0
  226. data/ext/rbuv/timer.h +13 -0
  227. data/lib/rbuv/timer.rb +7 -0
  228. data/lib/rbuv/version.rb +1 -1
  229. data/lib/rbuv.rb +24 -2
  230. data/rbuv.gemspec +5 -1
  231. data/spec/spec_helper.rb +22 -0
  232. data/spec/timer_spec.rb +144 -0
  233. metadata +278 -9
@@ -0,0 +1,1380 @@
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
+
22
+ #include "uv.h"
23
+ #include "internal.h"
24
+
25
+ #include <stdio.h>
26
+ #include <stdlib.h>
27
+ #include <string.h>
28
+ #include <assert.h>
29
+ #include <errno.h>
30
+
31
+ #include <sys/types.h>
32
+ #include <sys/socket.h>
33
+ #include <sys/uio.h>
34
+ #include <sys/un.h>
35
+ #include <unistd.h>
36
+
37
+ #if defined(__APPLE__)
38
+ # include <sys/event.h>
39
+ # include <sys/time.h>
40
+ # include <sys/select.h>
41
+
42
+ /* Forward declaration */
43
+ typedef struct uv__stream_select_s uv__stream_select_t;
44
+
45
+ struct uv__stream_select_s {
46
+ uv_stream_t* stream;
47
+ uv_thread_t thread;
48
+ uv_sem_t sem;
49
+ uv_mutex_t mutex;
50
+ uv_async_t async;
51
+ int events;
52
+ int fake_fd;
53
+ int int_fd;
54
+ int fd;
55
+ };
56
+ #endif /* defined(__APPLE__) */
57
+
58
+ static void uv__stream_connect(uv_stream_t*);
59
+ static void uv__write(uv_stream_t* stream);
60
+ static void uv__read(uv_stream_t* stream);
61
+ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
62
+
63
+
64
+ /* Used by the accept() EMFILE party trick. */
65
+ static int uv__open_cloexec(const char* path, int flags) {
66
+ int fd;
67
+
68
+ #if defined(__linux__)
69
+ fd = open(path, flags | UV__O_CLOEXEC);
70
+ if (fd != -1)
71
+ return fd;
72
+
73
+ if (errno != EINVAL)
74
+ return -1;
75
+
76
+ /* O_CLOEXEC not supported. */
77
+ #endif
78
+
79
+ fd = open(path, flags);
80
+ if (fd != -1)
81
+ uv__cloexec(fd, 1);
82
+
83
+ return fd;
84
+ }
85
+
86
+
87
+ static size_t uv__buf_count(uv_buf_t bufs[], int bufcnt) {
88
+ size_t total = 0;
89
+ int i;
90
+
91
+ for (i = 0; i < bufcnt; i++) {
92
+ total += bufs[i].len;
93
+ }
94
+
95
+ return total;
96
+ }
97
+
98
+
99
+ void uv__stream_init(uv_loop_t* loop,
100
+ uv_stream_t* stream,
101
+ uv_handle_type type) {
102
+ uv__handle_init(loop, (uv_handle_t*)stream, type);
103
+ stream->read_cb = NULL;
104
+ stream->read2_cb = NULL;
105
+ stream->alloc_cb = NULL;
106
+ stream->close_cb = NULL;
107
+ stream->connection_cb = NULL;
108
+ stream->connect_req = NULL;
109
+ stream->shutdown_req = NULL;
110
+ stream->accepted_fd = -1;
111
+ stream->delayed_error = 0;
112
+ ngx_queue_init(&stream->write_queue);
113
+ ngx_queue_init(&stream->write_completed_queue);
114
+ stream->write_queue_size = 0;
115
+
116
+ if (loop->emfile_fd == -1)
117
+ loop->emfile_fd = uv__open_cloexec("/", O_RDONLY);
118
+
119
+ #if defined(__APPLE__)
120
+ stream->select = NULL;
121
+ #endif /* defined(__APPLE_) */
122
+
123
+ uv__io_init(&stream->io_watcher, uv__stream_io, -1);
124
+ }
125
+
126
+
127
+ #if defined(__APPLE__)
128
+ static void uv__stream_osx_select(void* arg) {
129
+ uv_stream_t* stream;
130
+ uv__stream_select_t* s;
131
+ char buf[1024];
132
+ fd_set sread;
133
+ fd_set swrite;
134
+ int events;
135
+ int fd;
136
+ int r;
137
+ int max_fd;
138
+
139
+ stream = arg;
140
+ s = stream->select;
141
+ fd = stream->io_watcher.fd;
142
+
143
+ if (fd > s->int_fd)
144
+ max_fd = fd;
145
+ else
146
+ max_fd = s->int_fd;
147
+
148
+ while (1) {
149
+ /* Terminate on semaphore */
150
+ if (uv_sem_trywait(&s->sem) == 0)
151
+ break;
152
+
153
+ /* Watch fd using select(2) */
154
+ FD_ZERO(&sread);
155
+ FD_ZERO(&swrite);
156
+
157
+ if (uv_is_readable(stream))
158
+ FD_SET(fd, &sread);
159
+ if (uv_is_writable(stream))
160
+ FD_SET(fd, &swrite);
161
+ FD_SET(s->int_fd, &sread);
162
+
163
+ /* Wait indefinitely for fd events */
164
+ r = select(max_fd + 1, &sread, &swrite, NULL, NULL);
165
+ if (r == -1) {
166
+ if (errno == EINTR)
167
+ continue;
168
+
169
+ /* XXX: Possible?! */
170
+ abort();
171
+ }
172
+
173
+ /* Ignore timeouts */
174
+ if (r == 0)
175
+ continue;
176
+
177
+ /* Empty socketpair's buffer in case of interruption */
178
+ if (FD_ISSET(s->int_fd, &sread))
179
+ while (1) {
180
+ r = read(s->int_fd, buf, sizeof(buf));
181
+
182
+ if (r == sizeof(buf))
183
+ continue;
184
+
185
+ if (r != -1)
186
+ break;
187
+
188
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
189
+ break;
190
+
191
+ if (errno == EINTR)
192
+ continue;
193
+
194
+ abort();
195
+ }
196
+
197
+ /* Handle events */
198
+ events = 0;
199
+ if (FD_ISSET(fd, &sread))
200
+ events |= UV__POLLIN;
201
+ if (FD_ISSET(fd, &swrite))
202
+ events |= UV__POLLOUT;
203
+
204
+ uv_mutex_lock(&s->mutex);
205
+ s->events |= events;
206
+ uv_mutex_unlock(&s->mutex);
207
+
208
+ if (events != 0)
209
+ uv_async_send(&s->async);
210
+ }
211
+ }
212
+
213
+
214
+ static void uv__stream_osx_interrupt_select(uv_stream_t* stream) {
215
+ /* Notify select() thread about state change */
216
+ uv__stream_select_t* s;
217
+ int r;
218
+
219
+ s = stream->select;
220
+
221
+ /* Interrupt select() loop
222
+ * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will
223
+ * emit read event on other side
224
+ */
225
+ do
226
+ r = write(s->fake_fd, "x", 1);
227
+ while (r == -1 && errno == EINTR);
228
+
229
+ assert(r == 1);
230
+ }
231
+
232
+
233
+ static void uv__stream_osx_select_cb(uv_async_t* handle, int status) {
234
+ uv__stream_select_t* s;
235
+ uv_stream_t* stream;
236
+ int events;
237
+
238
+ s = container_of(handle, uv__stream_select_t, async);
239
+ stream = s->stream;
240
+
241
+ /* Get and reset stream's events */
242
+ uv_mutex_lock(&s->mutex);
243
+ events = s->events;
244
+ s->events = 0;
245
+ uv_mutex_unlock(&s->mutex);
246
+
247
+ assert(events != 0);
248
+ assert(events == (events & (UV__POLLIN | UV__POLLOUT)));
249
+
250
+ /* Invoke callback on event-loop */
251
+ if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN))
252
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN);
253
+
254
+ if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT))
255
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT);
256
+ }
257
+
258
+
259
+ static void uv__stream_osx_cb_close(uv_handle_t* async) {
260
+ uv__stream_select_t* s;
261
+
262
+ s = container_of(async, uv__stream_select_t, async);
263
+ free(s);
264
+ }
265
+
266
+
267
+ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
268
+ /*
269
+ * kqueue doesn't work with some files from /dev mount on osx.
270
+ * select(2) in separate thread for those fds
271
+ */
272
+
273
+ struct kevent filter[1];
274
+ struct kevent events[1];
275
+ struct timespec timeout;
276
+ uv__stream_select_t* s;
277
+ int fds[2];
278
+ int ret;
279
+ int kq;
280
+
281
+ kq = kqueue();
282
+ if (kq == -1) {
283
+ fprintf(stderr, "(libuv) Failed to create kqueue (%d)\n", errno);
284
+ return uv__set_sys_error(stream->loop, errno);
285
+ }
286
+
287
+ EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
288
+
289
+ /* Use small timeout, because we only want to capture EINVALs */
290
+ timeout.tv_sec = 0;
291
+ timeout.tv_nsec = 1;
292
+
293
+ ret = kevent(kq, filter, 1, events, 1, &timeout);
294
+ SAVE_ERRNO(close(kq));
295
+
296
+ if (ret == -1)
297
+ return uv__set_sys_error(stream->loop, errno);
298
+
299
+ if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL)
300
+ return 0;
301
+
302
+ /* At this point we definitely know that this fd won't work with kqueue */
303
+ s = malloc(sizeof(*s));
304
+ if (s == NULL)
305
+ return uv__set_artificial_error(stream->loop, UV_ENOMEM);
306
+
307
+ s->fd = *fd;
308
+
309
+ if (uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb)) {
310
+ SAVE_ERRNO(free(s));
311
+ return uv__set_sys_error(stream->loop, errno);
312
+ }
313
+
314
+ s->async.flags |= UV__HANDLE_INTERNAL;
315
+ uv__handle_unref(&s->async);
316
+
317
+ if (uv_sem_init(&s->sem, 0))
318
+ goto fatal1;
319
+
320
+ if (uv_mutex_init(&s->mutex))
321
+ goto fatal2;
322
+
323
+ /* Create fds for io watcher and to interrupt the select() loop. */
324
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
325
+ goto fatal3;
326
+
327
+ s->fake_fd = fds[0];
328
+ s->int_fd = fds[1];
329
+
330
+ if (uv_thread_create(&s->thread, uv__stream_osx_select, stream))
331
+ goto fatal4;
332
+
333
+ s->stream = stream;
334
+ stream->select = s;
335
+ *fd = s->fake_fd;
336
+
337
+ return 0;
338
+
339
+ fatal4:
340
+ close(s->fake_fd);
341
+ close(s->int_fd);
342
+ s->fake_fd = -1;
343
+ s->int_fd = -1;
344
+ fatal3:
345
+ uv_mutex_destroy(&s->mutex);
346
+ fatal2:
347
+ uv_sem_destroy(&s->sem);
348
+ fatal1:
349
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
350
+ return uv__set_sys_error(stream->loop, errno);
351
+ }
352
+ #endif /* defined(__APPLE__) */
353
+
354
+
355
+ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
356
+ assert(fd >= 0);
357
+ stream->flags |= flags;
358
+
359
+ if (stream->type == UV_TCP) {
360
+ if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
361
+ return uv__set_sys_error(stream->loop, errno);
362
+
363
+ /* TODO Use delay the user passed in. */
364
+ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
365
+ return uv__set_sys_error(stream->loop, errno);
366
+ }
367
+
368
+ stream->io_watcher.fd = fd;
369
+
370
+ return 0;
371
+ }
372
+
373
+
374
+ void uv__stream_destroy(uv_stream_t* stream) {
375
+ uv_write_t* req;
376
+ ngx_queue_t* q;
377
+
378
+ assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT));
379
+ assert(stream->flags & UV_CLOSED);
380
+
381
+ if (stream->connect_req) {
382
+ uv__req_unregister(stream->loop, stream->connect_req);
383
+ uv__set_artificial_error(stream->loop, UV_ECANCELED);
384
+ stream->connect_req->cb(stream->connect_req, -1);
385
+ stream->connect_req = NULL;
386
+ }
387
+
388
+ while (!ngx_queue_empty(&stream->write_queue)) {
389
+ q = ngx_queue_head(&stream->write_queue);
390
+ ngx_queue_remove(q);
391
+
392
+ req = ngx_queue_data(q, uv_write_t, queue);
393
+ uv__req_unregister(stream->loop, req);
394
+
395
+ if (req->bufs != req->bufsml)
396
+ free(req->bufs);
397
+
398
+ if (req->cb) {
399
+ uv__set_artificial_error(req->handle->loop, UV_ECANCELED);
400
+ req->cb(req, -1);
401
+ }
402
+ }
403
+
404
+ while (!ngx_queue_empty(&stream->write_completed_queue)) {
405
+ q = ngx_queue_head(&stream->write_completed_queue);
406
+ ngx_queue_remove(q);
407
+
408
+ req = ngx_queue_data(q, uv_write_t, queue);
409
+ uv__req_unregister(stream->loop, req);
410
+
411
+ if (req->cb) {
412
+ uv__set_sys_error(stream->loop, req->error);
413
+ req->cb(req, req->error ? -1 : 0);
414
+ }
415
+ }
416
+
417
+ if (stream->shutdown_req) {
418
+ uv__req_unregister(stream->loop, stream->shutdown_req);
419
+ uv__set_artificial_error(stream->loop, UV_ECANCELED);
420
+ stream->shutdown_req->cb(stream->shutdown_req, -1);
421
+ stream->shutdown_req = NULL;
422
+ }
423
+ }
424
+
425
+
426
+ /* Implements a best effort approach to mitigating accept() EMFILE errors.
427
+ * We have a spare file descriptor stashed away that we close to get below
428
+ * the EMFILE limit. Next, we accept all pending connections and close them
429
+ * immediately to signal the clients that we're overloaded - and we are, but
430
+ * we still keep on trucking.
431
+ *
432
+ * There is one caveat: it's not reliable in a multi-threaded environment.
433
+ * The file descriptor limit is per process. Our party trick fails if another
434
+ * thread opens a file or creates a socket in the time window between us
435
+ * calling close() and accept().
436
+ */
437
+ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
438
+ int fd;
439
+ int r;
440
+
441
+ if (loop->emfile_fd == -1)
442
+ return -1;
443
+
444
+ close(loop->emfile_fd);
445
+
446
+ for (;;) {
447
+ fd = uv__accept(accept_fd);
448
+
449
+ if (fd != -1) {
450
+ close(fd);
451
+ continue;
452
+ }
453
+
454
+ if (errno == EINTR)
455
+ continue;
456
+
457
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
458
+ r = 0;
459
+ else
460
+ r = -1;
461
+
462
+ loop->emfile_fd = uv__open_cloexec("/", O_RDONLY);
463
+
464
+ return r;
465
+ }
466
+ }
467
+
468
+
469
+ #if defined(UV_HAVE_KQUEUE)
470
+ # define UV_DEC_BACKLOG(w) w->rcount--;
471
+ #else
472
+ # define UV_DEC_BACKLOG(w) /* no-op */
473
+ #endif /* defined(UV_HAVE_KQUEUE) */
474
+
475
+
476
+ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
477
+ static int use_emfile_trick = -1;
478
+ uv_stream_t* stream;
479
+ int fd;
480
+ int r;
481
+
482
+ stream = container_of(w, uv_stream_t, io_watcher);
483
+ assert(events == UV__POLLIN);
484
+ assert(stream->accepted_fd == -1);
485
+ assert(!(stream->flags & UV_CLOSING));
486
+
487
+ if (stream->accepted_fd == -1)
488
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
489
+
490
+ /* connection_cb can close the server socket while we're
491
+ * in the loop so check it on each iteration.
492
+ */
493
+ while (uv__stream_fd(stream) != -1) {
494
+ assert(stream->accepted_fd == -1);
495
+ #if defined(UV_HAVE_KQUEUE)
496
+ if (w->rcount <= 0)
497
+ return;
498
+ #endif /* defined(UV_HAVE_KQUEUE) */
499
+ fd = uv__accept(uv__stream_fd(stream));
500
+
501
+ if (fd == -1) {
502
+ switch (errno) {
503
+ #if EWOULDBLOCK != EAGAIN
504
+ case EWOULDBLOCK:
505
+ #endif
506
+ case EAGAIN:
507
+ return; /* Not an error. */
508
+
509
+ case ECONNABORTED:
510
+ UV_DEC_BACKLOG(w)
511
+ continue; /* Ignore. */
512
+
513
+ case EMFILE:
514
+ case ENFILE:
515
+ if (use_emfile_trick == -1) {
516
+ const char* val = getenv("UV_ACCEPT_EMFILE_TRICK");
517
+ use_emfile_trick = (val == NULL || atoi(val) != 0);
518
+ }
519
+
520
+ if (use_emfile_trick) {
521
+ SAVE_ERRNO(r = uv__emfile_trick(loop, uv__stream_fd(stream)));
522
+ if (r == 0) {
523
+ UV_DEC_BACKLOG(w)
524
+ continue;
525
+ }
526
+ }
527
+
528
+ /* Fall through. */
529
+
530
+ default:
531
+ uv__set_sys_error(loop, errno);
532
+ stream->connection_cb(stream, -1);
533
+ continue;
534
+ }
535
+ }
536
+
537
+ UV_DEC_BACKLOG(w)
538
+
539
+ stream->accepted_fd = fd;
540
+ stream->connection_cb(stream, 0);
541
+
542
+ if (stream->accepted_fd != -1) {
543
+ /* The user hasn't yet accepted called uv_accept() */
544
+ uv__io_stop(loop, &stream->io_watcher, UV__POLLIN);
545
+ return;
546
+ }
547
+
548
+ if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
549
+ /* Give other processes a chance to accept connections. */
550
+ struct timespec timeout = { 0, 1 };
551
+ nanosleep(&timeout, NULL);
552
+ }
553
+ }
554
+ }
555
+
556
+
557
+ #undef UV_DEC_BACKLOG
558
+
559
+
560
+ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
561
+ uv_stream_t* streamServer;
562
+ uv_stream_t* streamClient;
563
+ int saved_errno;
564
+ int status;
565
+
566
+ /* TODO document this */
567
+ assert(server->loop == client->loop);
568
+
569
+ saved_errno = errno;
570
+ status = -1;
571
+
572
+ streamServer = (uv_stream_t*)server;
573
+ streamClient = (uv_stream_t*)client;
574
+
575
+ if (streamServer->accepted_fd < 0) {
576
+ uv__set_sys_error(server->loop, EAGAIN);
577
+ goto out;
578
+ }
579
+
580
+ switch (streamClient->type) {
581
+ case UV_NAMED_PIPE:
582
+ case UV_TCP:
583
+ if (uv__stream_open(streamClient, streamServer->accepted_fd,
584
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
585
+ /* TODO handle error */
586
+ close(streamServer->accepted_fd);
587
+ streamServer->accepted_fd = -1;
588
+ goto out;
589
+ }
590
+ break;
591
+
592
+ case UV_UDP:
593
+ if (uv_udp_open((uv_udp_t*) client, streamServer->accepted_fd)) {
594
+ close(streamServer->accepted_fd);
595
+ streamServer->accepted_fd = -1;
596
+ goto out;
597
+ }
598
+ break;
599
+
600
+ default:
601
+ assert(0);
602
+ }
603
+
604
+ uv__io_start(streamServer->loop, &streamServer->io_watcher, UV__POLLIN);
605
+ streamServer->accepted_fd = -1;
606
+ status = 0;
607
+
608
+ out:
609
+ errno = saved_errno;
610
+ return status;
611
+ }
612
+
613
+
614
+ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
615
+ int r;
616
+
617
+ switch (stream->type) {
618
+ case UV_TCP:
619
+ r = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
620
+ break;
621
+
622
+ case UV_NAMED_PIPE:
623
+ r = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
624
+ break;
625
+
626
+ default:
627
+ assert(0);
628
+ return -1;
629
+ }
630
+
631
+ if (r == 0)
632
+ uv__handle_start(stream);
633
+
634
+ return r;
635
+ }
636
+
637
+
638
+ static void uv__drain(uv_stream_t* stream) {
639
+ uv_shutdown_t* req;
640
+
641
+ assert(ngx_queue_empty(&stream->write_queue));
642
+ assert(stream->write_queue_size == 0);
643
+
644
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
645
+
646
+ /* Shutdown? */
647
+ if ((stream->flags & UV_STREAM_SHUTTING) &&
648
+ !(stream->flags & UV_CLOSING) &&
649
+ !(stream->flags & UV_STREAM_SHUT)) {
650
+ assert(stream->shutdown_req);
651
+
652
+ req = stream->shutdown_req;
653
+ stream->shutdown_req = NULL;
654
+ uv__req_unregister(stream->loop, req);
655
+
656
+ if (shutdown(uv__stream_fd(stream), SHUT_WR)) {
657
+ /* Error. Report it. User should call uv_close(). */
658
+ uv__set_sys_error(stream->loop, errno);
659
+ if (req->cb) {
660
+ req->cb(req, -1);
661
+ }
662
+ } else {
663
+ uv__set_sys_error(stream->loop, 0);
664
+ ((uv_handle_t*) stream)->flags |= UV_STREAM_SHUT;
665
+ if (req->cb) {
666
+ req->cb(req, 0);
667
+ }
668
+ }
669
+ }
670
+ }
671
+
672
+
673
+ static size_t uv__write_req_size(uv_write_t* req) {
674
+ size_t size;
675
+
676
+ size = uv__buf_count(req->bufs + req->write_index,
677
+ req->bufcnt - req->write_index);
678
+ assert(req->handle->write_queue_size >= size);
679
+
680
+ return size;
681
+ }
682
+
683
+
684
+ static void uv__write_req_finish(uv_write_t* req) {
685
+ uv_stream_t* stream = req->handle;
686
+
687
+ /* Pop the req off tcp->write_queue. */
688
+ ngx_queue_remove(&req->queue);
689
+ if (req->bufs != req->bufsml) {
690
+ free(req->bufs);
691
+ }
692
+ req->bufs = NULL;
693
+
694
+ /* Add it to the write_completed_queue where it will have its
695
+ * callback called in the near future.
696
+ */
697
+ ngx_queue_insert_tail(&stream->write_completed_queue, &req->queue);
698
+ uv__io_feed(stream->loop, &stream->io_watcher);
699
+ }
700
+
701
+
702
+ static int uv__handle_fd(uv_handle_t* handle) {
703
+ switch (handle->type) {
704
+ case UV_NAMED_PIPE:
705
+ case UV_TCP:
706
+ return ((uv_stream_t*) handle)->io_watcher.fd;
707
+
708
+ case UV_UDP:
709
+ return ((uv_udp_t*) handle)->io_watcher.fd;
710
+
711
+ default:
712
+ return -1;
713
+ }
714
+ }
715
+
716
+
717
+ static void uv__write(uv_stream_t* stream) {
718
+ struct iovec* iov;
719
+ ngx_queue_t* q;
720
+ uv_write_t* req;
721
+ int iovcnt;
722
+ ssize_t n;
723
+
724
+ start:
725
+
726
+ assert(uv__stream_fd(stream) >= 0);
727
+
728
+ if (ngx_queue_empty(&stream->write_queue)) {
729
+ assert(stream->write_queue_size == 0);
730
+ return;
731
+ }
732
+
733
+ q = ngx_queue_head(&stream->write_queue);
734
+ req = ngx_queue_data(q, uv_write_t, queue);
735
+ assert(req->handle == stream);
736
+
737
+ /*
738
+ * Cast to iovec. We had to have our own uv_buf_t instead of iovec
739
+ * because Windows's WSABUF is not an iovec.
740
+ */
741
+ assert(sizeof(uv_buf_t) == sizeof(struct iovec));
742
+ iov = (struct iovec*) &(req->bufs[req->write_index]);
743
+ iovcnt = req->bufcnt - req->write_index;
744
+
745
+ /*
746
+ * Now do the actual writev. Note that we've been updating the pointers
747
+ * inside the iov each time we write. So there is no need to offset it.
748
+ */
749
+
750
+ if (req->send_handle) {
751
+ struct msghdr msg;
752
+ char scratch[64];
753
+ struct cmsghdr *cmsg;
754
+ int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
755
+
756
+ assert(fd_to_send >= 0);
757
+
758
+ msg.msg_name = NULL;
759
+ msg.msg_namelen = 0;
760
+ msg.msg_iov = iov;
761
+ msg.msg_iovlen = iovcnt;
762
+ msg.msg_flags = 0;
763
+
764
+ msg.msg_control = (void*) scratch;
765
+ msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));
766
+
767
+ cmsg = CMSG_FIRSTHDR(&msg);
768
+ cmsg->cmsg_level = SOL_SOCKET;
769
+ cmsg->cmsg_type = SCM_RIGHTS;
770
+ cmsg->cmsg_len = msg.msg_controllen;
771
+
772
+ /* silence aliasing warning */
773
+ {
774
+ void* pv = CMSG_DATA(cmsg);
775
+ int* pi = pv;
776
+ *pi = fd_to_send;
777
+ }
778
+
779
+ do {
780
+ n = sendmsg(uv__stream_fd(stream), &msg, 0);
781
+ }
782
+ while (n == -1 && errno == EINTR);
783
+ } else {
784
+ do {
785
+ if (iovcnt == 1) {
786
+ n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
787
+ } else {
788
+ n = writev(uv__stream_fd(stream), iov, iovcnt);
789
+ }
790
+ }
791
+ while (n == -1 && errno == EINTR);
792
+ }
793
+
794
+ if (n < 0) {
795
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
796
+ /* Error */
797
+ req->error = errno;
798
+ stream->write_queue_size -= uv__write_req_size(req);
799
+ uv__write_req_finish(req);
800
+ return;
801
+ } else if (stream->flags & UV_STREAM_BLOCKING) {
802
+ /* If this is a blocking stream, try again. */
803
+ goto start;
804
+ }
805
+ } else {
806
+ /* Successful write */
807
+
808
+ while (n >= 0) {
809
+ uv_buf_t* buf = &(req->bufs[req->write_index]);
810
+ size_t len = buf->len;
811
+
812
+ assert(req->write_index < req->bufcnt);
813
+
814
+ if ((size_t)n < len) {
815
+ buf->base += n;
816
+ buf->len -= n;
817
+ stream->write_queue_size -= n;
818
+ n = 0;
819
+
820
+ /* There is more to write. */
821
+ if (stream->flags & UV_STREAM_BLOCKING) {
822
+ /*
823
+ * If we're blocking then we should not be enabling the write
824
+ * watcher - instead we need to try again.
825
+ */
826
+ goto start;
827
+ } else {
828
+ /* Break loop and ensure the watcher is pending. */
829
+ break;
830
+ }
831
+
832
+ } else {
833
+ /* Finished writing the buf at index req->write_index. */
834
+ req->write_index++;
835
+
836
+ assert((size_t)n >= len);
837
+ n -= len;
838
+
839
+ assert(stream->write_queue_size >= len);
840
+ stream->write_queue_size -= len;
841
+
842
+ if (req->write_index == req->bufcnt) {
843
+ /* Then we're done! */
844
+ assert(n == 0);
845
+ uv__write_req_finish(req);
846
+ /* TODO: start trying to write the next request. */
847
+ return;
848
+ }
849
+ }
850
+ }
851
+ }
852
+
853
+ /* Either we've counted n down to zero or we've got EAGAIN. */
854
+ assert(n == 0 || n == -1);
855
+
856
+ /* Only non-blocking streams should use the write_watcher. */
857
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
858
+
859
+ /* We're not done. */
860
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
861
+ }
862
+
863
+
864
+ static void uv__write_callbacks(uv_stream_t* stream) {
865
+ uv_write_t* req;
866
+ ngx_queue_t* q;
867
+
868
+ while (!ngx_queue_empty(&stream->write_completed_queue)) {
869
+ /* Pop a req off write_completed_queue. */
870
+ q = ngx_queue_head(&stream->write_completed_queue);
871
+ req = ngx_queue_data(q, uv_write_t, queue);
872
+ ngx_queue_remove(q);
873
+ uv__req_unregister(stream->loop, req);
874
+
875
+ /* NOTE: call callback AFTER freeing the request data. */
876
+ if (req->cb) {
877
+ uv__set_sys_error(stream->loop, req->error);
878
+ req->cb(req, req->error ? -1 : 0);
879
+ }
880
+ }
881
+
882
+ assert(ngx_queue_empty(&stream->write_completed_queue));
883
+
884
+ /* Write queue drained. */
885
+ if (ngx_queue_empty(&stream->write_queue))
886
+ uv__drain(stream);
887
+ }
888
+
889
+
890
+ static uv_handle_type uv__handle_type(int fd) {
891
+ struct sockaddr_storage ss;
892
+ socklen_t len;
893
+ int type;
894
+
895
+ memset(&ss, 0, sizeof(ss));
896
+ len = sizeof(ss);
897
+
898
+ if (getsockname(fd, (struct sockaddr*)&ss, &len))
899
+ return UV_UNKNOWN_HANDLE;
900
+
901
+ len = sizeof type;
902
+
903
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
904
+ return UV_UNKNOWN_HANDLE;
905
+
906
+ if (type == SOCK_STREAM) {
907
+ switch (ss.ss_family) {
908
+ case AF_UNIX:
909
+ return UV_NAMED_PIPE;
910
+ case AF_INET:
911
+ case AF_INET6:
912
+ return UV_TCP;
913
+ }
914
+ }
915
+
916
+ if (type == SOCK_DGRAM &&
917
+ (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
918
+ return UV_UDP;
919
+
920
+ return UV_UNKNOWN_HANDLE;
921
+ }
922
+
923
+
924
+ static void uv__read(uv_stream_t* stream) {
925
+ uv_buf_t buf;
926
+ ssize_t nread;
927
+ struct msghdr msg;
928
+ struct cmsghdr* cmsg;
929
+ char cmsg_space[64];
930
+ int count;
931
+
932
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
933
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
934
+ */
935
+ count = 32;
936
+
937
+ /* XXX: Maybe instead of having UV_STREAM_READING we just test if
938
+ * tcp->read_cb is NULL or not?
939
+ */
940
+ while ((stream->read_cb || stream->read2_cb)
941
+ && (stream->flags & UV_STREAM_READING)
942
+ && (count-- > 0)) {
943
+ assert(stream->alloc_cb);
944
+ buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);
945
+
946
+ assert(buf.len > 0);
947
+ assert(buf.base);
948
+ assert(uv__stream_fd(stream) >= 0);
949
+
950
+ if (stream->read_cb) {
951
+ do {
952
+ nread = read(uv__stream_fd(stream), buf.base, buf.len);
953
+ }
954
+ while (nread < 0 && errno == EINTR);
955
+ } else {
956
+ assert(stream->read2_cb);
957
+ /* read2_cb uses recvmsg */
958
+ msg.msg_flags = 0;
959
+ msg.msg_iov = (struct iovec*) &buf;
960
+ msg.msg_iovlen = 1;
961
+ msg.msg_name = NULL;
962
+ msg.msg_namelen = 0;
963
+ /* Set up to receive a descriptor even if one isn't in the message */
964
+ msg.msg_controllen = 64;
965
+ msg.msg_control = (void *) cmsg_space;
966
+
967
+ do {
968
+ nread = recvmsg(uv__stream_fd(stream), &msg, 0);
969
+ }
970
+ while (nread < 0 && errno == EINTR);
971
+ }
972
+
973
+ #define INVOKE_READ_CB(stream, status, buf, type) \
974
+ do { \
975
+ if ((stream)->read_cb != NULL) \
976
+ (stream)->read_cb((stream), (status), (buf)); \
977
+ else \
978
+ (stream)->read2_cb((uv_pipe_t*) (stream), (status), (buf), (type)); \
979
+ } \
980
+ while (0)
981
+
982
+ if (nread < 0) {
983
+ /* Error */
984
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
985
+ /* Wait for the next one. */
986
+ if (stream->flags & UV_STREAM_READING) {
987
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
988
+ }
989
+ uv__set_sys_error(stream->loop, EAGAIN);
990
+ INVOKE_READ_CB(stream, 0, buf, UV_UNKNOWN_HANDLE);
991
+ } else {
992
+ /* Error. User should call uv_close(). */
993
+ uv__set_sys_error(stream->loop, errno);
994
+ INVOKE_READ_CB(stream, -1, buf, UV_UNKNOWN_HANDLE);
995
+ assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) &&
996
+ "stream->read_cb(status=-1) did not call uv_close()");
997
+ }
998
+ return;
999
+ } else if (nread == 0) {
1000
+ /* EOF */
1001
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
1002
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
1003
+ uv__handle_stop(stream);
1004
+ uv__set_artificial_error(stream->loop, UV_EOF);
1005
+ INVOKE_READ_CB(stream, -1, buf, UV_UNKNOWN_HANDLE);
1006
+ return;
1007
+ } else {
1008
+ /* Successful read */
1009
+ ssize_t buflen = buf.len;
1010
+
1011
+ if (stream->read_cb) {
1012
+ stream->read_cb(stream, nread, buf);
1013
+ } else {
1014
+ assert(stream->read2_cb);
1015
+
1016
+ /*
1017
+ * XXX: Some implementations can send multiple file descriptors in a
1018
+ * single message. We should be using CMSG_NXTHDR() to walk the
1019
+ * chain to get at them all. This would require changing the API to
1020
+ * hand these back up the caller, is a pain.
1021
+ */
1022
+
1023
+ for (cmsg = CMSG_FIRSTHDR(&msg);
1024
+ msg.msg_controllen > 0 && cmsg != NULL;
1025
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1026
+
1027
+ if (cmsg->cmsg_type == SCM_RIGHTS) {
1028
+ if (stream->accepted_fd != -1) {
1029
+ fprintf(stderr, "(libuv) ignoring extra FD received\n");
1030
+ }
1031
+
1032
+ /* silence aliasing warning */
1033
+ {
1034
+ void* pv = CMSG_DATA(cmsg);
1035
+ int* pi = pv;
1036
+ stream->accepted_fd = *pi;
1037
+ }
1038
+
1039
+ } else {
1040
+ fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
1041
+ cmsg->cmsg_type);
1042
+ }
1043
+ }
1044
+
1045
+
1046
+ if (stream->accepted_fd >= 0) {
1047
+ stream->read2_cb((uv_pipe_t*)stream, nread, buf,
1048
+ uv__handle_type(stream->accepted_fd));
1049
+ } else {
1050
+ stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_UNKNOWN_HANDLE);
1051
+ }
1052
+ }
1053
+
1054
+ /* Return if we didn't fill the buffer, there is no more data to read. */
1055
+ if (nread < buflen) {
1056
+ return;
1057
+ }
1058
+ }
1059
+ }
1060
+ }
1061
+
1062
+
1063
+ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
1064
+ assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
1065
+ "uv_shutdown (unix) only supports uv_handle_t right now");
1066
+ assert(uv__stream_fd(stream) >= 0);
1067
+
1068
+ if (!(stream->flags & UV_STREAM_WRITABLE) ||
1069
+ stream->flags & UV_STREAM_SHUT ||
1070
+ stream->flags & UV_CLOSED ||
1071
+ stream->flags & UV_CLOSING) {
1072
+ uv__set_artificial_error(stream->loop, UV_ENOTCONN);
1073
+ return -1;
1074
+ }
1075
+
1076
+ /* Initialize request */
1077
+ uv__req_init(stream->loop, req, UV_SHUTDOWN);
1078
+ req->handle = stream;
1079
+ req->cb = cb;
1080
+ stream->shutdown_req = req;
1081
+ stream->flags |= UV_STREAM_SHUTTING;
1082
+
1083
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
1084
+
1085
+ return 0;
1086
+ }
1087
+
1088
+
1089
+ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
1090
+ uv_stream_t* stream;
1091
+
1092
+ stream = container_of(w, uv_stream_t, io_watcher);
1093
+
1094
+ assert(stream->type == UV_TCP ||
1095
+ stream->type == UV_NAMED_PIPE ||
1096
+ stream->type == UV_TTY);
1097
+ assert(!(stream->flags & UV_CLOSING));
1098
+
1099
+ if (stream->connect_req) {
1100
+ uv__stream_connect(stream);
1101
+ return;
1102
+ }
1103
+
1104
+ if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) {
1105
+ assert(uv__stream_fd(stream) >= 0);
1106
+
1107
+ uv__read(stream);
1108
+
1109
+ if (uv__stream_fd(stream) == -1)
1110
+ return; /* read_cb closed stream. */
1111
+ }
1112
+
1113
+ if (events & UV__POLLOUT) {
1114
+ assert(uv__stream_fd(stream) >= 0);
1115
+ uv__write(stream);
1116
+ uv__write_callbacks(stream);
1117
+ }
1118
+ }
1119
+
1120
+
1121
+ /**
1122
+ * We get called here from directly following a call to connect(2).
1123
+ * In order to determine if we've errored out or succeeded must call
1124
+ * getsockopt.
1125
+ */
1126
+ static void uv__stream_connect(uv_stream_t* stream) {
1127
+ int error;
1128
+ uv_connect_t* req = stream->connect_req;
1129
+ socklen_t errorsize = sizeof(int);
1130
+
1131
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE);
1132
+ assert(req);
1133
+
1134
+ if (stream->delayed_error) {
1135
+ /* To smooth over the differences between unixes errors that
1136
+ * were reported synchronously on the first connect can be delayed
1137
+ * until the next tick--which is now.
1138
+ */
1139
+ error = stream->delayed_error;
1140
+ stream->delayed_error = 0;
1141
+ } else {
1142
+ /* Normal situation: we need to get the socket error from the kernel. */
1143
+ assert(uv__stream_fd(stream) >= 0);
1144
+ getsockopt(uv__stream_fd(stream),
1145
+ SOL_SOCKET,
1146
+ SO_ERROR,
1147
+ &error,
1148
+ &errorsize);
1149
+ }
1150
+
1151
+ if (error == EINPROGRESS)
1152
+ return;
1153
+
1154
+ stream->connect_req = NULL;
1155
+ uv__req_unregister(stream->loop, req);
1156
+
1157
+ if (req->cb) {
1158
+ uv__set_sys_error(stream->loop, error);
1159
+ req->cb(req, error ? -1 : 0);
1160
+ }
1161
+ }
1162
+
1163
+
1164
+ int uv_write2(uv_write_t* req,
1165
+ uv_stream_t* stream,
1166
+ uv_buf_t bufs[],
1167
+ int bufcnt,
1168
+ uv_stream_t* send_handle,
1169
+ uv_write_cb cb) {
1170
+ int empty_queue;
1171
+
1172
+ assert(bufcnt > 0);
1173
+ assert((stream->type == UV_TCP ||
1174
+ stream->type == UV_NAMED_PIPE ||
1175
+ stream->type == UV_TTY) &&
1176
+ "uv_write (unix) does not yet support other types of streams");
1177
+
1178
+ if (uv__stream_fd(stream) < 0)
1179
+ return uv__set_artificial_error(stream->loop, UV_EBADF);
1180
+
1181
+ if (send_handle) {
1182
+ if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
1183
+ return uv__set_artificial_error(stream->loop, UV_EINVAL);
1184
+
1185
+ /* XXX We abuse uv_write2() to send over UDP handles to child processes.
1186
+ * Don't call uv__stream_fd() on those handles, it's a macro that on OS X
1187
+ * evaluates to a function that operates on a uv_stream_t with a couple of
1188
+ * OS X specific fields. On other Unices it does (handle)->io_watcher.fd,
1189
+ * which works but only by accident.
1190
+ */
1191
+ if (uv__handle_fd((uv_handle_t*) send_handle) < 0)
1192
+ return uv__set_artificial_error(stream->loop, UV_EBADF);
1193
+ }
1194
+
1195
+ empty_queue = (stream->write_queue_size == 0);
1196
+
1197
+ /* Initialize the req */
1198
+ uv__req_init(stream->loop, req, UV_WRITE);
1199
+ req->cb = cb;
1200
+ req->handle = stream;
1201
+ req->error = 0;
1202
+ req->send_handle = send_handle;
1203
+ ngx_queue_init(&req->queue);
1204
+
1205
+ if (bufcnt <= (int) ARRAY_SIZE(req->bufsml))
1206
+ req->bufs = req->bufsml;
1207
+ else
1208
+ req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);
1209
+
1210
+ memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t));
1211
+ req->bufcnt = bufcnt;
1212
+ req->write_index = 0;
1213
+ stream->write_queue_size += uv__buf_count(bufs, bufcnt);
1214
+
1215
+ /* Append the request to write_queue. */
1216
+ ngx_queue_insert_tail(&stream->write_queue, &req->queue);
1217
+
1218
+ /* If the queue was empty when this function began, we should attempt to
1219
+ * do the write immediately. Otherwise start the write_watcher and wait
1220
+ * for the fd to become writable.
1221
+ */
1222
+ if (stream->connect_req) {
1223
+ /* Still connecting, do nothing. */
1224
+ }
1225
+ else if (empty_queue) {
1226
+ uv__write(stream);
1227
+ }
1228
+ else {
1229
+ /*
1230
+ * blocking streams should never have anything in the queue.
1231
+ * if this assert fires then somehow the blocking stream isn't being
1232
+ * sufficiently flushed in uv__write.
1233
+ */
1234
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
1235
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
1236
+ }
1237
+
1238
+ return 0;
1239
+ }
1240
+
1241
+
1242
+ /* The buffers to be written must remain valid until the callback is called.
1243
+ * This is not required for the uv_buf_t array.
1244
+ */
1245
+ int uv_write(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
1246
+ uv_write_cb cb) {
1247
+ return uv_write2(req, stream, bufs, bufcnt, NULL, cb);
1248
+ }
1249
+
1250
+
1251
+ static int uv__read_start_common(uv_stream_t* stream,
1252
+ uv_alloc_cb alloc_cb,
1253
+ uv_read_cb read_cb,
1254
+ uv_read2_cb read2_cb) {
1255
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
1256
+ stream->type == UV_TTY);
1257
+
1258
+ if (stream->flags & UV_CLOSING)
1259
+ return uv__set_sys_error(stream->loop, EINVAL);
1260
+
1261
+ /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
1262
+ * expresses the desired state of the user.
1263
+ */
1264
+ stream->flags |= UV_STREAM_READING;
1265
+
1266
+ #if defined(__APPLE__)
1267
+ /* Notify select() thread about state change */
1268
+ if (stream->select != NULL)
1269
+ uv__stream_osx_interrupt_select(stream);
1270
+ #endif /* defined(__APPLE__) */
1271
+
1272
+ /* TODO: try to do the read inline? */
1273
+ /* TODO: keep track of tcp state. If we've gotten a EOF then we should
1274
+ * not start the IO watcher.
1275
+ */
1276
+ assert(uv__stream_fd(stream) >= 0);
1277
+ assert(alloc_cb);
1278
+
1279
+ stream->read_cb = read_cb;
1280
+ stream->read2_cb = read2_cb;
1281
+ stream->alloc_cb = alloc_cb;
1282
+
1283
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
1284
+ uv__handle_start(stream);
1285
+
1286
+ return 0;
1287
+ }
1288
+
1289
+
1290
+ int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
1291
+ uv_read_cb read_cb) {
1292
+ return uv__read_start_common(stream, alloc_cb, read_cb, NULL);
1293
+ }
1294
+
1295
+
1296
+ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
1297
+ uv_read2_cb read_cb) {
1298
+ return uv__read_start_common(stream, alloc_cb, NULL, read_cb);
1299
+ }
1300
+
1301
+
1302
+ int uv_read_stop(uv_stream_t* stream) {
1303
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
1304
+ uv__handle_stop(stream);
1305
+ stream->flags &= ~UV_STREAM_READING;
1306
+
1307
+ #if defined(__APPLE__)
1308
+ /* Notify select() thread about state change */
1309
+ if (stream->select != NULL)
1310
+ uv__stream_osx_interrupt_select(stream);
1311
+ #endif /* defined(__APPLE__) */
1312
+
1313
+ stream->read_cb = NULL;
1314
+ stream->read2_cb = NULL;
1315
+ stream->alloc_cb = NULL;
1316
+ return 0;
1317
+ }
1318
+
1319
+
1320
+ int uv_is_readable(const uv_stream_t* stream) {
1321
+ return stream->flags & UV_STREAM_READABLE;
1322
+ }
1323
+
1324
+
1325
+ int uv_is_writable(const uv_stream_t* stream) {
1326
+ return stream->flags & UV_STREAM_WRITABLE;
1327
+ }
1328
+
1329
+
1330
+ #if defined(__APPLE__)
1331
+ int uv___stream_fd(uv_stream_t* handle) {
1332
+ uv__stream_select_t* s;
1333
+
1334
+ assert(handle->type == UV_TCP ||
1335
+ handle->type == UV_TTY ||
1336
+ handle->type == UV_NAMED_PIPE);
1337
+
1338
+ s = handle->select;
1339
+ if (s != NULL)
1340
+ return s->fd;
1341
+
1342
+ return handle->io_watcher.fd;
1343
+ }
1344
+ #endif /* defined(__APPLE__) */
1345
+
1346
+
1347
+ void uv__stream_close(uv_stream_t* handle) {
1348
+ #if defined(__APPLE__)
1349
+ /* Terminate select loop first */
1350
+ if (handle->select != NULL) {
1351
+ uv__stream_select_t* s;
1352
+
1353
+ s = handle->select;
1354
+
1355
+ uv_sem_post(&s->sem);
1356
+ uv__stream_osx_interrupt_select(handle);
1357
+ uv_thread_join(&s->thread);
1358
+ uv_sem_destroy(&s->sem);
1359
+ uv_mutex_destroy(&s->mutex);
1360
+ close(s->fake_fd);
1361
+ close(s->int_fd);
1362
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
1363
+
1364
+ handle->select = NULL;
1365
+ }
1366
+ #endif /* defined(__APPLE__) */
1367
+
1368
+ uv_read_stop(handle);
1369
+ uv__io_close(handle->loop, &handle->io_watcher);
1370
+
1371
+ close(handle->io_watcher.fd);
1372
+ handle->io_watcher.fd = -1;
1373
+
1374
+ if (handle->accepted_fd >= 0) {
1375
+ close(handle->accepted_fd);
1376
+ handle->accepted_fd = -1;
1377
+ }
1378
+
1379
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
1380
+ }