Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : #include "platform.h"
4 : :
5 : : #include <stdio.h>
6 : : #include <stddef.h>
7 : : #include <stdint.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : :
11 : : #ifdef _OS_WINDOWS_
12 : : #include <ws2tcpip.h>
13 : : #include <malloc.h>
14 : : #else
15 : : #include "errno.h"
16 : : #include <unistd.h>
17 : : #include <sys/socket.h>
18 : : #endif
19 : :
20 : : #include "julia.h"
21 : : #include "julia_internal.h"
22 : : #include "support/ios.h"
23 : : #include "uv.h"
24 : :
25 : : #include "julia_assert.h"
26 : :
27 : : #ifdef __cplusplus
28 : : #include <cstring>
29 : : extern "C" {
30 : : #endif
31 : :
32 : : static uv_async_t signal_async;
33 : :
34 : 29830 : static void jl_signal_async_cb(uv_async_t *hdl)
35 : : {
36 : : // This should abort the current loop and the julia code it returns to
37 : : // or the safepoint in the callers of `uv_run` should throw the exception.
38 : : (void)hdl;
39 : 29830 : uv_stop(jl_io_loop);
40 : 29830 : }
41 : :
42 : 30214 : void jl_wake_libuv(void)
43 : : {
44 : 30214 : uv_async_send(&signal_async);
45 : 30214 : }
46 : :
47 : : jl_mutex_t jl_uv_mutex;
48 : :
49 : 573 : void jl_init_uv(void)
50 : : {
51 : 573 : uv_async_init(jl_io_loop, &signal_async, jl_signal_async_cb);
52 : 573 : JL_MUTEX_INIT(&jl_uv_mutex); // a file-scope initializer can be used instead
53 : 573 : }
54 : :
55 : : _Atomic(int) jl_uv_n_waiters = 0;
56 : :
57 : 7353060 : void JL_UV_LOCK(void)
58 : : {
59 [ + + ]: 7353060 : if (jl_mutex_trylock(&jl_uv_mutex)) {
60 : : }
61 : : else {
62 : 29626 : jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, 1);
63 : 29626 : jl_fence(); // [^store_buffering_2]
64 : 29626 : jl_wake_libuv();
65 : 29626 : JL_LOCK(&jl_uv_mutex);
66 : 29626 : jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, -1);
67 : : }
68 : 7353060 : }
69 : :
70 : 6539980 : JL_DLLEXPORT void jl_iolock_begin(void)
71 : : {
72 : 6539980 : JL_UV_LOCK();
73 : 6539980 : }
74 : :
75 : 6539760 : JL_DLLEXPORT void jl_iolock_end(void)
76 : : {
77 : 6539760 : JL_UV_UNLOCK();
78 : 6539760 : }
79 : :
80 : :
81 : 90705 : static void jl_uv_call_close_callback(jl_value_t *val)
82 : : {
83 : : jl_value_t **args;
84 : 90705 : JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now
85 : 90705 : args[0] = jl_get_global(jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module),
86 : : jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close
87 : 90705 : args[1] = val;
88 [ - + ]: 90705 : assert(args[0]);
89 : 90705 : jl_apply(args, 2); // TODO: wrap in try-catch?
90 : 90705 : JL_GC_POP();
91 : 90705 : }
92 : :
93 : 95883 : static void jl_uv_closeHandle(uv_handle_t *handle)
94 : : {
95 : : // if the user killed a stdio handle,
96 : : // revert back to direct stdio FILE* writes
97 : : // so that errors can still be reported
98 [ + + ]: 95883 : if (handle == (uv_handle_t*)JL_STDIN)
99 : 297 : JL_STDIN = (JL_STREAM*)STDIN_FILENO;
100 [ + + ]: 95883 : if (handle == (uv_handle_t*)JL_STDOUT)
101 : 1 : JL_STDOUT = (JL_STREAM*)STDOUT_FILENO;
102 [ + + ]: 95883 : if (handle == (uv_handle_t*)JL_STDERR)
103 : 1 : JL_STDERR = (JL_STREAM*)STDERR_FILENO;
104 : : // also let the client app do its own cleanup
105 [ + - + + ]: 95883 : if (handle->type != UV_FILE && handle->data) {
106 : 90705 : jl_task_t *ct = jl_current_task;
107 : 90705 : size_t last_age = ct->world_age;
108 : 90705 : ct->world_age = jl_atomic_load_acquire(&jl_world_counter);
109 : 90705 : jl_uv_call_close_callback((jl_value_t*)handle->data);
110 : 90705 : ct->world_age = last_age;
111 : 90705 : return;
112 : : }
113 [ + + ]: 5178 : if (handle == (uv_handle_t*)&signal_async)
114 : 571 : return;
115 : 4607 : free(handle);
116 : : }
117 : :
118 : 5990 : static void jl_uv_flush_close_callback(uv_write_t *req, int status)
119 : : {
120 : 5990 : uv_stream_t *stream = req->handle;
121 : 5990 : req->handle = NULL;
122 : : // ignore attempts to close the stream while attempting a graceful shutdown
123 : : #ifdef _OS_WINDOWS_
124 : : if (stream->stream.conn.shutdown_req)
125 : : #else
126 [ - + ]: 5990 : if (stream->shutdown_req)
127 : : #endif
128 : : {
129 : 0 : free(req);
130 : 0 : return;
131 : : }
132 [ - + ]: 5990 : if (uv_is_closing((uv_handle_t*)stream)) { // avoid double-close on the stream
133 : 0 : free(req);
134 : 0 : return;
135 : : }
136 [ + - + + : 5990 : if (status == 0 && uv_is_writable(stream) && stream->write_queue_size != 0) {
+ + ]
137 : : // new data was written, wait for it to flush too
138 : : uv_buf_t buf;
139 : 1 : buf.base = (char*)(req + 1);
140 : 1 : buf.len = 0;
141 : 1 : req->data = NULL;
142 [ + - ]: 1 : if (uv_write(req, stream, &buf, 1, (uv_write_cb)jl_uv_flush_close_callback) == 0)
143 : 1 : return; // success
144 : : }
145 : 5989 : free(req);
146 [ + + ]: 5989 : if (stream->type == UV_TTY)
147 : 454 : uv_tty_set_mode((uv_tty_t*)stream, UV_TTY_MODE_NORMAL);
148 : 5989 : uv_close((uv_handle_t*)stream, &jl_uv_closeHandle);
149 : : }
150 : :
151 : 0 : static void uv_flush_callback(uv_write_t *req, int status)
152 : : {
153 : 0 : *(int*)(req->data) = 1;
154 : 0 : uv_stop(req->handle->loop);
155 : 0 : free(req);
156 : 0 : }
157 : :
158 : : // Turn a normal write into a blocking write (primarily for use from C and gdb).
159 : : // Warning: This calls uv_run, so it can have unbounded side-effects.
160 : : // Be care where you call it from! - the libuv loop is also not reentrant.
161 : 179 : JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream)
162 : : {
163 [ + - + - ]: 179 : if (stream == (void*)STDIN_FILENO ||
164 [ - + ]: 179 : stream == (void*)STDOUT_FILENO ||
165 : : stream == (void*)STDERR_FILENO)
166 : 0 : return;
167 [ + + ]: 179 : if (stream->type != UV_TTY &&
168 [ + - ]: 8 : stream->type != UV_TCP &&
169 [ + + ]: 8 : stream->type != UV_NAMED_PIPE)
170 : 2 : return;
171 : 177 : JL_UV_LOCK();
172 [ + - - + ]: 177 : while (uv_is_writable(stream) && stream->write_queue_size != 0) {
173 : 0 : int fired = 0;
174 : : uv_buf_t buf;
175 : 0 : buf.base = (char*)(&buf + 1);
176 : 0 : buf.len = 0;
177 : 0 : uv_write_t *write_req = (uv_write_t*)malloc_s(sizeof(uv_write_t));
178 : 0 : write_req->data = (void*)&fired;
179 [ # # ]: 0 : if (uv_write(write_req, stream, &buf, 1, uv_flush_callback) != 0) {
180 : 0 : JL_UV_UNLOCK();
181 : 0 : return;
182 : : }
183 [ # # ]: 0 : while (!fired) {
184 : 0 : uv_run(uv_default_loop(), UV_RUN_DEFAULT);
185 : : }
186 : : }
187 : 177 : JL_UV_UNLOCK();
188 : : }
189 : :
190 : : // getters and setters
191 : : // TODO: check if whoever calls these is thread-safe
192 : 2 : JL_DLLEXPORT int jl_uv_process_pid(uv_process_t *p) { return p->pid; }
193 : 1647 : JL_DLLEXPORT void *jl_uv_process_data(uv_process_t *p) { return p->data; }
194 : 69 : JL_DLLEXPORT void *jl_uv_buf_base(const uv_buf_t *buf) { return buf->base; }
195 : 142762 : JL_DLLEXPORT size_t jl_uv_buf_len(const uv_buf_t *buf) { return buf->len; }
196 : 142580 : JL_DLLEXPORT void jl_uv_buf_set_base(uv_buf_t *buf, char *b) { buf->base = b; }
197 : 142580 : JL_DLLEXPORT void jl_uv_buf_set_len(uv_buf_t *buf, size_t n) { buf->len = n; }
198 : 1023 : JL_DLLEXPORT void *jl_uv_connect_handle(uv_connect_t *connect) { return connect->handle; }
199 : 512 : JL_DLLEXPORT uv_os_fd_t jl_uv_file_handle(jl_uv_file_t *f) { return f->file; }
200 : 543370 : JL_DLLEXPORT void *jl_uv_req_data(uv_req_t *req) { return req->data; }
201 : 815486 : JL_DLLEXPORT void jl_uv_req_set_data(uv_req_t *req, void *data) { req->data = data; }
202 : 376022 : JL_DLLEXPORT void *jl_uv_handle_data(uv_handle_t *handle) { return handle->data; }
203 : 0 : JL_DLLEXPORT void *jl_uv_write_handle(uv_write_t *req) { return req->handle; }
204 : :
205 : : extern _Atomic(unsigned) _threadedregion;
206 : :
207 : 2102580 : JL_DLLEXPORT int jl_process_events(void)
208 : : {
209 : 2102580 : jl_task_t *ct = jl_current_task;
210 : 2102580 : uv_loop_t *loop = jl_io_loop;
211 : 2102580 : jl_gc_safepoint_(ct->ptls);
212 [ + + + + : 2102580 : if (loop && (jl_atomic_load_relaxed(&_threadedregion) || jl_atomic_load_relaxed(&ct->tid) == 0)) {
+ + ]
213 [ + # + + ]: 1589580 : if (jl_atomic_load_relaxed(&jl_uv_n_waiters) == 0 && jl_mutex_trylock(&jl_uv_mutex)) {
214 : : JL_PROBE_RT_START_PROCESS_EVENTS(ct);
215 : 1482600 : loop->stop_flag = 0;
216 : 1482600 : int r = uv_run(loop, UV_RUN_NOWAIT);
217 : : JL_PROBE_RT_FINISH_PROCESS_EVENTS(ct);
218 : 1485220 : JL_UV_UNLOCK();
219 : 1485220 : return r;
220 : : }
221 : 107047 : jl_gc_safepoint_(ct->ptls);
222 : : }
223 : 620050 : return 0;
224 : : }
225 : :
226 : 2 : static void jl_proc_exit_cleanup_cb(uv_process_t *process, int64_t exit_status, int term_signal)
227 : : {
228 : 2 : uv_close((uv_handle_t*)process, (uv_close_cb)&free);
229 : 2 : }
230 : :
231 : 95837 : JL_DLLEXPORT void jl_close_uv(uv_handle_t *handle)
232 : : {
233 : 95837 : JL_UV_LOCK();
234 [ + + + + ]: 95837 : if (handle->type == UV_PROCESS && ((uv_process_t*)handle)->pid != 0) {
235 : : // take ownership of this handle,
236 : : // so we can waitpid for the resource to exit and avoid leaving zombies
237 [ - + ]: 27 : assert(handle->data == NULL); // make sure Julia has forgotten about it already
238 : 27 : ((uv_process_t*)handle)->exit_cb = jl_proc_exit_cleanup_cb;
239 : 27 : uv_unref(handle);
240 : : }
241 [ - + ]: 95810 : else if (handle->type == UV_FILE) {
242 : : uv_fs_t req;
243 : 0 : jl_uv_file_t *fd = (jl_uv_file_t*)handle;
244 [ # # ]: 0 : if ((ssize_t)fd->file != -1) {
245 : 0 : uv_fs_close(handle->loop, &req, fd->file, NULL);
246 : 0 : fd->file = (uv_os_fd_t)(ssize_t)-1;
247 : : }
248 : 0 : jl_uv_closeHandle(handle); // synchronous (ok since the callback is known to not interact with any global state)
249 : : }
250 [ + + ]: 95810 : else if (!uv_is_closing(handle)) { // avoid double-closing the stream
251 [ + + + + : 101770 : if (handle->type == UV_NAMED_PIPE || handle->type == UV_TCP || handle->type == UV_TTY) {
+ + ]
252 : : // flush the stream write-queue first
253 : 5989 : uv_write_t *req = (uv_write_t*)malloc_s(sizeof(uv_write_t));
254 : 5989 : req->handle = (uv_stream_t*)handle;
255 : 5989 : jl_uv_flush_close_callback(req, 0);
256 : : }
257 : : else {
258 : 89792 : uv_close(handle, &jl_uv_closeHandle);
259 : : }
260 : : }
261 : 95837 : JL_UV_UNLOCK();
262 : 95837 : }
263 : :
264 : 102 : JL_DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle)
265 : : {
266 [ + - ]: 102 : if (!uv_is_closing(handle)) { // avoid double-closing the stream
267 : 102 : JL_UV_LOCK();
268 [ + - ]: 102 : if (!uv_is_closing(handle)) { // double-check
269 : 102 : uv_close(handle, &jl_uv_closeHandle);
270 : : }
271 : 102 : JL_UV_UNLOCK();
272 : : }
273 : 102 : }
274 : :
275 : 95306 : JL_DLLEXPORT void jl_uv_associate_julia_struct(uv_handle_t *handle,
276 : : jl_value_t *data)
277 : : {
278 : 95306 : handle->data = data;
279 : 95306 : }
280 : :
281 : 10695 : JL_DLLEXPORT void jl_uv_disassociate_julia_struct(uv_handle_t *handle)
282 : : {
283 : 10695 : handle->data = NULL;
284 : 10695 : }
285 : :
286 : : #define UV_HANDLE_CLOSED 0x02
287 : :
288 : 1675 : JL_DLLEXPORT int jl_spawn(char *name, char **argv,
289 : : uv_loop_t *loop, uv_process_t *proc,
290 : : uv_stdio_container_t *stdio, int nstdio,
291 : : uint32_t flags, char **env, char *cwd, char* cpumask,
292 : : size_t cpumask_size, uv_exit_cb cb)
293 : : {
294 : 1675 : uv_process_options_t opts = {0};
295 : 1675 : opts.stdio = stdio;
296 : 1675 : opts.file = name;
297 : 1675 : opts.env = env;
298 : 1675 : opts.flags = flags;
299 : : // unused fields:
300 : : //opts.uid = 0;
301 : : //opts.gid = 0;
302 : 1675 : opts.cpumask = cpumask;
303 : 1675 : opts.cpumask_size = cpumask_size;
304 : 1675 : opts.cwd = cwd;
305 : 1675 : opts.args = argv;
306 : 1675 : opts.stdio_count = nstdio;
307 [ + + ]: 6512 : while (nstdio--) {
308 : 4837 : int flags = opts.stdio[nstdio].flags;
309 [ + + + + : 4837 : if (!(flags == UV_INHERIT_FD || flags == UV_INHERIT_STREAM || flags == UV_IGNORE)) {
- + ]
310 : 0 : proc->type = UV_PROCESS;
311 : 0 : proc->loop = loop;
312 : 0 : proc->flags = UV_HANDLE_CLOSED;
313 : 0 : return UV_EINVAL;
314 : : }
315 : : }
316 : 1675 : opts.exit_cb = cb;
317 : 1675 : JL_UV_LOCK();
318 : 1675 : int r = uv_spawn(loop, proc, &opts);
319 : 1675 : JL_UV_UNLOCK();
320 : 1675 : return r;
321 : : }
322 : :
323 : : #ifdef _OS_WINDOWS_
324 : : #include <time.h>
325 : : JL_DLLEXPORT struct tm *localtime_r(const time_t *t, struct tm *tm)
326 : : {
327 : : struct tm *tmp = localtime(t); //localtime is reentrant on windows
328 : : if (tmp)
329 : : *tm = *tmp;
330 : : return tmp;
331 : : }
332 : : #endif
333 : :
334 : 766092 : JL_DLLEXPORT uv_loop_t *jl_global_event_loop(void)
335 : : {
336 : 766092 : return jl_io_loop;
337 : : }
338 : :
339 : 16571 : JL_DLLEXPORT int jl_fs_unlink(char *path)
340 : : {
341 : : uv_fs_t req;
342 : 16571 : JL_SIGATOMIC_BEGIN();
343 : 16571 : int ret = uv_fs_unlink(unused_uv_loop_arg, &req, path, NULL);
344 : 16571 : uv_fs_req_cleanup(&req);
345 [ + - ]: 16571 : JL_SIGATOMIC_END();
346 : 16571 : return ret;
347 : : }
348 : :
349 : 126 : JL_DLLEXPORT int jl_fs_rename(const char *src_path, const char *dst_path)
350 : : {
351 : : uv_fs_t req;
352 : 126 : JL_SIGATOMIC_BEGIN();
353 : 126 : int ret = uv_fs_rename(unused_uv_loop_arg, &req, src_path, dst_path, NULL);
354 : 126 : uv_fs_req_cleanup(&req);
355 [ + - ]: 126 : JL_SIGATOMIC_END();
356 : 126 : return ret;
357 : : }
358 : :
359 : 3907 : JL_DLLEXPORT int jl_fs_sendfile(uv_os_fd_t src_fd, uv_os_fd_t dst_fd,
360 : : int64_t in_offset, size_t len)
361 : : {
362 : : uv_fs_t req;
363 : 3907 : JL_SIGATOMIC_BEGIN();
364 : 3907 : int ret = uv_fs_sendfile(unused_uv_loop_arg, &req, dst_fd, src_fd,
365 : : in_offset, len, NULL);
366 : 3907 : uv_fs_req_cleanup(&req);
367 [ + - ]: 3907 : JL_SIGATOMIC_END();
368 : 3907 : return ret;
369 : : }
370 : :
371 : 3 : JL_DLLEXPORT int jl_fs_hardlink(char *path, char *new_path)
372 : : {
373 : : uv_fs_t req;
374 : 3 : int ret = uv_fs_link(unused_uv_loop_arg, &req, path, new_path, NULL);
375 : 3 : uv_fs_req_cleanup(&req);
376 : 3 : return ret;
377 : : }
378 : :
379 : 2173 : JL_DLLEXPORT int jl_fs_symlink(char *path, char *new_path, int flags)
380 : : {
381 : : uv_fs_t req;
382 : 2173 : int ret = uv_fs_symlink(unused_uv_loop_arg, &req, path, new_path, flags, NULL);
383 : 2173 : uv_fs_req_cleanup(&req);
384 : 2173 : return ret;
385 : : }
386 : :
387 : 9125 : JL_DLLEXPORT int jl_fs_chmod(char *path, int mode)
388 : : {
389 : : uv_fs_t req;
390 : 9125 : int ret = uv_fs_chmod(unused_uv_loop_arg, &req, path, mode, NULL);
391 : 9125 : uv_fs_req_cleanup(&req);
392 : 9125 : return ret;
393 : : }
394 : :
395 : 2 : JL_DLLEXPORT int jl_fs_chown(char *path, int uid, int gid)
396 : : {
397 : : uv_fs_t req;
398 : 2 : int ret = uv_fs_chown(unused_uv_loop_arg, &req, path, uid, gid, NULL);
399 : 2 : uv_fs_req_cleanup(&req);
400 : 2 : return ret;
401 : : }
402 : :
403 : 111 : JL_DLLEXPORT int jl_fs_access(char *path, int mode)
404 : : {
405 : : uv_fs_t req;
406 : 111 : int ret = uv_fs_access(unused_uv_loop_arg, &req, path, mode, NULL);
407 : 111 : uv_fs_req_cleanup(&req);
408 : 111 : return ret;
409 : : }
410 : :
411 : 304 : JL_DLLEXPORT int jl_fs_write(uv_os_fd_t handle, const char *data, size_t len,
412 : : int64_t offset) JL_NOTSAFEPOINT
413 : : {
414 : 304 : jl_task_t *ct = jl_get_current_task();
415 : : // TODO: fix this cheating
416 [ + - + + : 304 : if (jl_get_safe_restore() || ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0)
- + ]
417 : : #ifdef _OS_WINDOWS_
418 : : return WriteFile(handle, data, len, NULL, NULL);
419 : : #else
420 : 77 : return write(handle, data, len);
421 : : #endif
422 : : uv_fs_t req;
423 : : uv_buf_t buf[1];
424 : 227 : buf[0].base = (char*)data;
425 : 227 : buf[0].len = len;
426 [ - + ]: 227 : if (!jl_io_loop)
427 : 0 : jl_io_loop = uv_default_loop();
428 : 227 : int ret = uv_fs_write(unused_uv_loop_arg, &req, handle, buf, 1, offset, NULL);
429 : 227 : uv_fs_req_cleanup(&req);
430 : 227 : return ret;
431 : : }
432 : :
433 : 121 : JL_DLLEXPORT int jl_fs_read(uv_os_fd_t handle, char *data, size_t len)
434 : : {
435 : : uv_fs_t req;
436 : : uv_buf_t buf[1];
437 : 121 : buf[0].base = data;
438 : 121 : buf[0].len = len;
439 : 121 : int ret = uv_fs_read(unused_uv_loop_arg, &req, handle, buf, 1, -1, NULL);
440 : 121 : uv_fs_req_cleanup(&req);
441 : 121 : return ret;
442 : : }
443 : :
444 : 8718230 : JL_DLLEXPORT int jl_fs_read_byte(uv_os_fd_t handle)
445 : : {
446 : : uv_fs_t req;
447 : : unsigned char c;
448 : : uv_buf_t buf[1];
449 : 8718230 : buf[0].base = (char*)&c;
450 : 8718230 : buf[0].len = 1;
451 : 8718230 : int ret = uv_fs_read(unused_uv_loop_arg, &req, handle, buf, 1, -1, NULL);
452 : 8718230 : uv_fs_req_cleanup(&req);
453 [ - + + - ]: 8718230 : switch (ret) {
454 : 0 : case -1: return ret;
455 : 2 : case 0: jl_eof_error();
456 : 8718230 : case 1: return (int)c;
457 : 0 : default:
458 : 0 : assert(0 && "jl_fs_read_byte: Invalid return value from uv_fs_read");
459 : : return -1;
460 : : }
461 : : }
462 : :
463 : 8811 : JL_DLLEXPORT int jl_fs_close(uv_os_fd_t handle)
464 : : {
465 : : uv_fs_t req;
466 : 8811 : int ret = uv_fs_close(unused_uv_loop_arg, &req, handle, NULL);
467 : 8811 : uv_fs_req_cleanup(&req);
468 : 8811 : return ret;
469 : : }
470 : :
471 : 271609 : JL_DLLEXPORT int jl_uv_write(uv_stream_t *stream, const char *data, size_t n,
472 : : uv_write_t *uvw, uv_write_cb writecb)
473 : : {
474 : : uv_buf_t buf[1];
475 : 271609 : buf[0].base = (char*)data;
476 : 271609 : buf[0].len = n;
477 : 271609 : JL_UV_LOCK();
478 : 271609 : JL_SIGATOMIC_BEGIN();
479 : 271609 : int err = uv_write(uvw, stream, buf, 1, writecb);
480 : 271609 : JL_UV_UNLOCK();
481 [ - + ]: 271609 : JL_SIGATOMIC_END();
482 : 271609 : return err;
483 : : }
484 : :
485 : 903 : static void jl_uv_writecb(uv_write_t *req, int status) JL_NOTSAFEPOINT
486 : : {
487 : 903 : free(req);
488 [ - + ]: 903 : if (status < 0) {
489 : 0 : jl_safe_printf("jl_uv_writecb() ERROR: %s %s\n",
490 : : uv_strerror(status), uv_err_name(status));
491 : : }
492 : 903 : }
493 : :
494 : 60046 : JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n)
495 : : {
496 [ - + ]: 60046 : assert(stream);
497 : : static_assert(offsetof(uv_stream_t,type) == offsetof(ios_t,bm) &&
498 : : sizeof(((uv_stream_t*)0)->type) == sizeof(((ios_t*)0)->bm),
499 : : "UV and ios layout mismatch");
500 : :
501 : 60046 : uv_os_fd_t fd = (uv_os_fd_t)(ssize_t)-1;
502 : :
503 : : // Fallback for output during early initialisation...
504 [ + + ]: 60046 : if (stream == (void*)STDOUT_FILENO) {
505 : 27 : fd = UV_STDOUT_FD;
506 : : }
507 [ + + ]: 60019 : else if (stream == (void*)STDERR_FILENO) {
508 : 141 : fd = UV_STDERR_FD;
509 : : }
510 [ + + ]: 59878 : else if (stream->type == UV_FILE) {
511 : 6 : fd = ((jl_uv_file_t*)stream)->file;
512 : : }
513 : :
514 : : // TODO: Hack to make CoreIO thread-safer
515 : 60046 : jl_task_t *ct = jl_get_current_task();
516 [ + + - + ]: 60046 : if (ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0) {
517 [ + + ]: 77 : if (stream == JL_STDOUT) {
518 : 5 : fd = UV_STDOUT_FD;
519 : : }
520 [ + - ]: 72 : else if (stream == JL_STDERR) {
521 : 72 : fd = UV_STDERR_FD;
522 : : }
523 : : }
524 : :
525 [ + + ]: 60046 : if ((ssize_t)fd != -1) {
526 : : // Write to file descriptor...
527 : 174 : jl_fs_write(fd, str, n, -1);
528 : : }
529 [ + + ]: 59872 : else if (stream->type > UV_HANDLE_TYPE_MAX) {
530 : : // Write to ios.c stream...
531 : : // This is needed because caller jl_static_show() in builtins.c can be
532 : : // called from fl_print in flisp/print.c (via cvalue_printdata()),
533 : : // and cvalue_printdata() passes ios_t* to jl_static_show().
534 : 58969 : ios_write((ios_t*)stream, str, n);
535 : : }
536 : : else {
537 : : // Write to libuv stream...
538 : 903 : uv_write_t *req = (uv_write_t*)malloc_s(sizeof(uv_write_t) + n);
539 : 903 : char *data = (char*)(req + 1);
540 : 903 : memcpy(data, str, n);
541 : : uv_buf_t buf[1];
542 : 903 : buf[0].base = data;
543 : 903 : buf[0].len = n;
544 : 903 : req->data = NULL;
545 : 903 : JL_UV_LOCK();
546 : 903 : JL_SIGATOMIC_BEGIN();
547 : 903 : int status = uv_write(req, stream, buf, 1, (uv_write_cb)jl_uv_writecb);
548 : 903 : JL_UV_UNLOCK();
549 [ + + ]: 903 : JL_SIGATOMIC_END();
550 [ - + ]: 903 : if (status < 0) {
551 : 0 : jl_uv_writecb(req, status);
552 : : }
553 : : }
554 : 60046 : }
555 : :
556 : 230 : JL_DLLEXPORT void jl_uv_putb(uv_stream_t *stream, uint8_t b)
557 : : {
558 : 230 : jl_uv_puts(stream, (char*)&b, 1);
559 : 230 : }
560 : :
561 : 2 : JL_DLLEXPORT void jl_uv_putc(uv_stream_t *stream, uint32_t c)
562 : : {
563 : : char s[4];
564 : 2 : int n = 1;
565 : 2 : s[0] = c >> 24;
566 [ + - ]: 2 : if ((s[1] = c >> 16)) {
567 : 2 : n++;
568 [ - + ]: 2 : if ((s[2] = c >> 8)) {
569 : 0 : n++;
570 [ # # ]: 0 : if ((s[3] = c)) {
571 : 0 : n++;
572 : : }
573 : : }
574 : : }
575 : 2 : jl_uv_puts(stream, s, n);
576 : 2 : }
577 : :
578 : : extern int vasprintf(char **str, const char *fmt, va_list ap);
579 : :
580 : 59485 : JL_DLLEXPORT int jl_vprintf(uv_stream_t *s, const char *format, va_list args)
581 : : {
582 : 59485 : char *str = NULL;
583 : : int c;
584 : : va_list al;
585 : : #if defined(_OS_WINDOWS_) && !defined(_COMPILER_GCC_)
586 : : al = args;
587 : : #else
588 : 59485 : va_copy(al, args);
589 : : #endif
590 : :
591 : 59485 : c = vasprintf(&str, format, al);
592 : :
593 [ + - ]: 59485 : if (c >= 0) {
594 : 59485 : jl_uv_puts(s, str, c);
595 : 59485 : free(str);
596 : : }
597 : 59485 : va_end(al);
598 : 59485 : return c;
599 : : }
600 : :
601 : 59459 : JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...)
602 : : {
603 : : va_list args;
604 : : int c;
605 : :
606 : 59459 : va_start(args, format);
607 : 59459 : c = jl_vprintf(s, format, args);
608 : 59459 : va_end(args);
609 : 59459 : return c;
610 : : }
611 : :
612 : 664 : JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...)
613 : : {
614 : : static char buf[1000];
615 : 664 : buf[0] = '\0';
616 : 664 : int last_errno = errno;
617 : : #ifdef _OS_WINDOWS_
618 : : DWORD last_error = GetLastError();
619 : : #endif
620 : :
621 : : va_list args;
622 : 664 : va_start(args, fmt);
623 : : // Not async signal safe on some platforms?
624 : 664 : vsnprintf(buf, sizeof(buf), fmt, args);
625 : 664 : va_end(args);
626 : :
627 : 664 : buf[999] = '\0';
628 : 664 : if (write(STDERR_FILENO, buf, strlen(buf)) < 0) {
629 : : // nothing we can do; ignore the failure
630 : : }
631 : : #ifdef _OS_WINDOWS_
632 : : SetLastError(last_error);
633 : : #endif
634 : 664 : errno = last_errno;
635 : 664 : }
636 : :
637 : 278 : JL_DLLEXPORT void jl_exit(int exitcode)
638 : : {
639 : 278 : uv_tty_reset_mode();
640 : 278 : jl_atexit_hook(exitcode);
641 : 214 : exit(exitcode);
642 : : }
643 : :
644 : : typedef union {
645 : : struct sockaddr in;
646 : : struct sockaddr_in v4;
647 : : struct sockaddr_in6 v6;
648 : : } uv_sockaddr_in;
649 : :
650 : 1341 : static void jl_sockaddr_fill(uv_sockaddr_in *addr, uint16_t port, void *host, int ipv6)
651 : : {
652 : 1341 : memset(addr, 0, sizeof(*addr));
653 [ + + ]: 1341 : if (ipv6) {
654 : 20 : addr->v6.sin6_family = AF_INET6;
655 : 20 : memcpy(&addr->v6.sin6_addr, host, 16);
656 : 20 : addr->v6.sin6_port = port;
657 : : }
658 : : else {
659 : 1321 : addr->v4.sin_family = AF_INET;
660 : 1321 : addr->v4.sin_addr.s_addr = *(uint32_t*)host;
661 : 1321 : addr->v4.sin_port = port;
662 : : }
663 : 1341 : }
664 : :
665 : : //NOTE: These function expects port/host to be in network byte-order (Big Endian)
666 : 674 : JL_DLLEXPORT int jl_tcp_bind(uv_tcp_t *handle, uint16_t port, void *host,
667 : : unsigned int flags, int ipv6)
668 : : {
669 : : uv_sockaddr_in addr;
670 : 674 : jl_sockaddr_fill(&addr, port, host, ipv6);
671 : 674 : return uv_tcp_bind(handle, (struct sockaddr*)&addr, flags);
672 : : }
673 : :
674 : 192 : JL_DLLEXPORT int jl_tcp_getsockname(uv_tcp_t *handle, uint16_t *port,
675 : : void *host, uint32_t *family)
676 : : {
677 : : int namelen;
678 : : struct sockaddr_storage addr;
679 : 192 : memset(&addr, 0, sizeof(struct sockaddr_storage));
680 : 192 : namelen = sizeof addr;
681 : 192 : int res = uv_tcp_getsockname(handle, (struct sockaddr*)&addr, &namelen);
682 [ + + ]: 192 : if (res)
683 : 2 : return res;
684 : 190 : *family = addr.ss_family;
685 [ + + ]: 190 : if (addr.ss_family == AF_INET) {
686 : 187 : struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr;
687 : 187 : *port = addr4->sin_port;
688 : 187 : memcpy(host, &(addr4->sin_addr), 4);
689 : : }
690 [ + - ]: 3 : else if (addr.ss_family == AF_INET6) {
691 : 3 : struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&addr;
692 : 3 : *port = addr6->sin6_port;
693 : 3 : memcpy(host, &(addr6->sin6_addr), 16);
694 : : }
695 : 190 : return res;
696 : : }
697 : :
698 : 19 : JL_DLLEXPORT int jl_tcp_getpeername(uv_tcp_t *handle, uint16_t *port,
699 : : void *host, uint32_t *family)
700 : : {
701 : : int namelen;
702 : : struct sockaddr_storage addr;
703 : 19 : memset(&addr, 0, sizeof(struct sockaddr_storage));
704 : 19 : namelen = sizeof addr;
705 : 19 : int res = uv_tcp_getpeername(handle, (struct sockaddr*)&addr, &namelen);
706 [ + + ]: 19 : if (res)
707 : 1 : return res;
708 : 18 : *family = addr.ss_family;
709 [ + + ]: 18 : if (addr.ss_family == AF_INET) {
710 : 16 : struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr;
711 : 16 : *port = addr4->sin_port;
712 : 16 : memcpy(host, &(addr4->sin_addr), 4);
713 : : }
714 [ + - ]: 2 : else if (addr.ss_family == AF_INET6) {
715 : 2 : struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&addr;
716 : 2 : *port = addr6->sin6_port;
717 : 2 : memcpy(host, &(addr6->sin6_addr), 16);
718 : : }
719 : 18 : return res;
720 : : }
721 : :
722 : 10 : JL_DLLEXPORT int jl_udp_bind(uv_udp_t *handle, uint16_t port, void *host,
723 : : uint32_t flags, int ipv6)
724 : : {
725 : : uv_sockaddr_in addr;
726 : 10 : jl_sockaddr_fill(&addr, port, host, ipv6);
727 : 10 : return uv_udp_bind(handle, (struct sockaddr*)&addr, flags);
728 : : }
729 : :
730 : 40 : JL_DLLEXPORT int jl_udp_send(uv_udp_send_t *req, uv_udp_t *handle, uint16_t port, void *host,
731 : : char *data, uint32_t size, uv_udp_send_cb cb, int ipv6)
732 : : {
733 : : uv_sockaddr_in addr;
734 : 40 : jl_sockaddr_fill(&addr, port, host, ipv6);
735 : : uv_buf_t buf[1];
736 : 40 : buf[0].base = data;
737 : 40 : buf[0].len = size;
738 : 40 : int r = uv_udp_send(req, handle, buf, 1, (struct sockaddr*)&addr, cb);
739 : 40 : return r;
740 : : }
741 : :
742 : 1 : JL_DLLEXPORT int jl_uv_sizeof_interface_address(void)
743 : : {
744 : 1 : return sizeof(uv_interface_address_t);
745 : : }
746 : :
747 : 26 : JL_DLLEXPORT int jl_uv_interface_addresses(uv_interface_address_t **ifAddrStruct,
748 : : int *count)
749 : : {
750 : 26 : return uv_interface_addresses(ifAddrStruct, count);
751 : : }
752 : :
753 : 104 : JL_DLLEXPORT int jl_uv_interface_address_is_internal(uv_interface_address_t *addr)
754 : : {
755 : 104 : return addr->is_internal;
756 : : }
757 : :
758 : 56 : JL_DLLEXPORT struct sockaddr_in *jl_uv_interface_address_sockaddr(uv_interface_address_t *ifa)
759 : : {
760 : 56 : return &ifa->address.address4;
761 : : }
762 : :
763 : 10 : JL_DLLEXPORT int jl_getaddrinfo(uv_loop_t *loop, uv_getaddrinfo_t *req,
764 : : const char *host, const char *service, uv_getaddrinfo_cb uvcb)
765 : : {
766 : : struct addrinfo hints;
767 : 10 : memset(&hints, 0, sizeof(hints));
768 : 10 : hints.ai_family = PF_UNSPEC;
769 : 10 : hints.ai_socktype = SOCK_STREAM;
770 : 10 : hints.ai_flags |= AI_CANONNAME;
771 : :
772 : 10 : req->data = NULL;
773 : 10 : return uv_getaddrinfo(loop, req, uvcb, host, service, &hints);
774 : : }
775 : :
776 : 24 : JL_DLLEXPORT int jl_getnameinfo(uv_loop_t *loop, uv_getnameinfo_t *req,
777 : : void *host, uint16_t port, int flags, uv_getnameinfo_cb uvcb, int ipv6)
778 : : {
779 : : uv_sockaddr_in addr;
780 : 24 : jl_sockaddr_fill(&addr, port, host, ipv6);
781 : 24 : return uv_getnameinfo(loop, req, uvcb, (struct sockaddr*)&addr, flags);
782 : : }
783 : :
784 : 15 : JL_DLLEXPORT struct sockaddr *jl_sockaddr_from_addrinfo(struct addrinfo *addrinfo)
785 : : {
786 : 15 : return addrinfo->ai_addr;
787 : : }
788 : :
789 : 15 : JL_DLLEXPORT struct addrinfo *jl_next_from_addrinfo(struct addrinfo *addrinfo)
790 : : {
791 : 15 : return addrinfo->ai_next;
792 : : }
793 : :
794 : 101 : JL_DLLEXPORT int jl_sockaddr_is_ip4(struct sockaddr *addr)
795 : : {
796 : 101 : return (addr->sa_family == AF_INET);
797 : : }
798 : :
799 : 24 : JL_DLLEXPORT int jl_sockaddr_is_ip6(struct sockaddr *addr)
800 : : {
801 : 24 : return (addr->sa_family == AF_INET6);
802 : : }
803 : :
804 : 68 : JL_DLLEXPORT uint32_t jl_sockaddr_host4(struct sockaddr_in *addr)
805 : : {
806 : 68 : return addr->sin_addr.s_addr;
807 : : }
808 : :
809 : 19 : JL_DLLEXPORT unsigned jl_sockaddr_host6(struct sockaddr_in6 *addr, char *host)
810 : : {
811 : 19 : memcpy(host, &addr->sin6_addr, 16);
812 : 19 : return addr->sin6_scope_id;
813 : : }
814 : :
815 : 35 : JL_DLLEXPORT uint16_t jl_sockaddr_port4(struct sockaddr_in *addr)
816 : : {
817 : 35 : return addr->sin_port;
818 : : }
819 : :
820 : 5 : JL_DLLEXPORT uint16_t jl_sockaddr_port6(struct sockaddr_in6 *addr)
821 : : {
822 : 5 : return addr->sin6_port;
823 : : }
824 : :
825 : :
826 : 0 : JL_DLLEXPORT void jl_sockaddr_set_port(uv_sockaddr_in *addr, uint16_t port)
827 : : {
828 [ # # ]: 0 : if (addr->in.sa_family == AF_INET)
829 : 0 : addr->v4.sin_port = port;
830 : : else
831 : 0 : addr->v6.sin6_port = port;
832 : 0 : }
833 : :
834 : 593 : JL_DLLEXPORT int jl_tcp_connect(uv_tcp_t *handle, void *host, uint16_t port,
835 : : uv_connect_cb cb, int ipv6)
836 : : {
837 : : uv_sockaddr_in addr;
838 : 593 : jl_sockaddr_fill(&addr, port, host, ipv6);
839 : 593 : uv_connect_t *req = (uv_connect_t*)malloc_s(sizeof(uv_connect_t));
840 : 593 : req->data = NULL;
841 : 593 : int r = uv_tcp_connect(req, handle, &addr.in, cb);
842 [ - + ]: 593 : if (r)
843 : 0 : free(req);
844 : 593 : return r;
845 : : }
846 : :
847 : : #ifdef _OS_LINUX_
848 : 375 : JL_DLLEXPORT int jl_tcp_quickack(uv_tcp_t *handle, int on)
849 : : {
850 : 375 : int fd = (handle)->io_watcher.fd;
851 [ + - ]: 375 : if (fd != -1) {
852 [ - + ]: 375 : if (setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &on, sizeof(on))) {
853 : 0 : return -1;
854 : : }
855 : : }
856 : 375 : return 0;
857 : : }
858 : :
859 : : #endif
860 : :
861 : 148 : JL_DLLEXPORT int jl_has_so_reuseport(void)
862 : : {
863 : : #if defined(SO_REUSEPORT) && !defined(_OS_DARWIN_)
864 : 148 : return 1;
865 : : #else
866 : : return 0;
867 : : #endif
868 : : }
869 : :
870 : 147 : JL_DLLEXPORT int jl_tcp_reuseport(uv_tcp_t *handle)
871 : : {
872 : : #if defined(SO_REUSEPORT)
873 : 147 : int fd = (handle)->io_watcher.fd;
874 : 147 : int yes = 1;
875 [ - + ]: 147 : if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) {
876 : 0 : return -1;
877 : : }
878 : 147 : return 0;
879 : : #else
880 : : return -1;
881 : : #endif
882 : : }
883 : :
884 : : #ifndef _OS_WINDOWS_
885 : :
886 : 570 : JL_DLLEXPORT int jl_uv_unix_fd_is_watched(int fd, uv_poll_t *handle,
887 : : uv_loop_t *loop)
888 : : {
889 : 570 : JL_UV_LOCK();
890 [ + + ]: 570 : if (fd >= loop->nwatchers) {
891 : 73 : JL_UV_UNLOCK();
892 : 73 : return 0;
893 : : }
894 [ + - ]: 497 : if (loop->watchers[fd] == NULL) {
895 : 497 : JL_UV_UNLOCK();
896 : 497 : return 0;
897 : : }
898 [ # # # # ]: 0 : if (handle && loop->watchers[fd] == &handle->io_watcher) {
899 : 0 : JL_UV_UNLOCK();
900 : 0 : return 0;
901 : : }
902 : 0 : JL_UV_UNLOCK();
903 : 0 : return 1;
904 : : }
905 : :
906 : : #endif
907 : :
908 : : #ifdef _OS_WINDOWS_
909 : : static inline int ishexchar(char c)
910 : : {
911 : : if (c >= '0' && c <= '9') return 1;
912 : : if (c >= 'a' && c <= 'z') return 1;
913 : : return 0;
914 : : }
915 : :
916 : : JL_DLLEXPORT int jl_ispty(uv_pipe_t *pipe)
917 : : {
918 : : if (pipe->type != UV_NAMED_PIPE) return 0;
919 : : size_t len = 0;
920 : : if (uv_pipe_getpeername(pipe, NULL, &len) != UV_ENOBUFS) return 0;
921 : : char *name = (char*)alloca(len + 1);
922 : : if (uv_pipe_getpeername(pipe, name, &len)) return 0;
923 : : name[len] = '\0';
924 : : // return true if name matches regex:
925 : : // ^\\\\?\\pipe\\(msys|cygwin)-[0-9a-z]{16}-[pt]ty[1-9][0-9]*-
926 : : //jl_printf(JL_STDERR,"pipe_name: %s\n", name);
927 : : int n = 0;
928 : : if (!strncmp(name,"\\\\?\\pipe\\msys-",14))
929 : : n = 14;
930 : : else if (!strncmp(name,"\\\\?\\pipe\\cygwin-",16))
931 : : n = 16;
932 : : else
933 : : return 0;
934 : : //jl_printf(JL_STDERR,"prefix pass\n");
935 : : name += n;
936 : : for (int n = 0; n < 16; n++)
937 : : if (!ishexchar(*name++)) return 0;
938 : : //jl_printf(JL_STDERR,"hex pass\n");
939 : : if ((*name++)!='-') return 0;
940 : : if (*name != 'p' && *name != 't') return 0;
941 : : name++;
942 : : if (*name++ != 't' || *name++ != 'y') return 0;
943 : : //jl_printf(JL_STDERR,"tty pass\n");
944 : : return 1;
945 : : }
946 : : #endif
947 : :
948 : 1692 : JL_DLLEXPORT uv_handle_type jl_uv_handle_type(uv_handle_t *handle)
949 : : {
950 : : #ifdef _OS_WINDOWS_
951 : : if (jl_ispty((uv_pipe_t*)handle))
952 : : return UV_TTY;
953 : : #endif
954 : 1692 : return handle->type;
955 : : }
956 : :
957 : 114 : JL_DLLEXPORT int jl_tty_set_mode(uv_tty_t *handle, int mode)
958 : : {
959 [ - + ]: 114 : if (handle->type != UV_TTY) return 0;
960 : 114 : uv_tty_mode_t mode_enum = UV_TTY_MODE_NORMAL;
961 [ + + ]: 114 : if (mode)
962 : 42 : mode_enum = UV_TTY_MODE_RAW;
963 : : // TODO: do we need lock?
964 : 114 : return uv_tty_set_mode(handle, mode_enum);
965 : : }
966 : :
967 : : typedef int (*work_cb_t)(void *, void *, void *);
968 : : typedef void (*notify_cb_t)(int);
969 : :
970 : : struct work_baton {
971 : : uv_work_t req;
972 : : work_cb_t work_func;
973 : : void *ccall_fptr;
974 : : void *work_args;
975 : : void *work_retval;
976 : : notify_cb_t notify_func;
977 : : int notify_idx;
978 : : };
979 : :
980 : : #ifdef _OS_LINUX_
981 : : #include <sys/syscall.h>
982 : : #endif
983 : :
984 : 1028 : void jl_work_wrapper(uv_work_t *req)
985 : : {
986 : 1028 : struct work_baton *baton = (struct work_baton*) req->data;
987 : 1028 : baton->work_func(baton->ccall_fptr, baton->work_args, baton->work_retval);
988 : 1028 : }
989 : :
990 : 1028 : void jl_work_notifier(uv_work_t *req, int status)
991 : : {
992 : 1028 : struct work_baton *baton = (struct work_baton*) req->data;
993 : 1028 : baton->notify_func(baton->notify_idx);
994 : 1028 : free(baton);
995 : 1028 : }
996 : :
997 : 1028 : JL_DLLEXPORT int jl_queue_work(work_cb_t work_func, void *ccall_fptr, void *work_args, void *work_retval,
998 : : notify_cb_t notify_func, int notify_idx)
999 : : {
1000 : 1028 : struct work_baton *baton = (struct work_baton*)malloc_s(sizeof(struct work_baton));
1001 : 1028 : baton->req.data = (void*) baton;
1002 : 1028 : baton->work_func = work_func;
1003 : 1028 : baton->ccall_fptr = ccall_fptr;
1004 : 1028 : baton->work_args = work_args;
1005 : 1028 : baton->work_retval = work_retval;
1006 : 1028 : baton->notify_func = notify_func;
1007 : 1028 : baton->notify_idx = notify_idx;
1008 : :
1009 : 1028 : JL_UV_LOCK();
1010 : 1028 : uv_queue_work(jl_io_loop, &baton->req, jl_work_wrapper, jl_work_notifier);
1011 : 1028 : JL_UV_UNLOCK();
1012 : :
1013 : 1028 : return 0;
1014 : : }
1015 : :
1016 : : #ifndef _OS_WINDOWS_
1017 : : #if defined(__APPLE__)
1018 : : int uv___stream_fd(uv_stream_t *handle);
1019 : : #define uv__stream_fd(handle) (uv___stream_fd((uv_stream_t*)(handle)))
1020 : : #else
1021 : : #define uv__stream_fd(handle) ((handle)->io_watcher.fd)
1022 : : #endif /* defined(__APPLE__) */
1023 : 0 : JL_DLLEXPORT int jl_uv_handle(uv_stream_t *handle)
1024 : : {
1025 : 0 : return uv__stream_fd(handle);
1026 : : }
1027 : : #else
1028 : : JL_DLLEXPORT HANDLE jl_uv_handle(uv_stream_t *handle)
1029 : : {
1030 : : switch (handle->type) {
1031 : : case UV_TTY:
1032 : : return ((uv_tty_t*)handle)->handle;
1033 : : case UV_NAMED_PIPE:
1034 : : return ((uv_pipe_t*)handle)->handle;
1035 : : default:
1036 : : return INVALID_HANDLE_VALUE;
1037 : : }
1038 : : }
1039 : : #endif
1040 : :
1041 : : #ifdef __cplusplus
1042 : : }
1043 : : #endif
|