/home/travis/build/MoarVM/MoarVM/src/io/syncpipe.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | #ifndef _WIN32 |
4 | | #include <sys/wait.h> |
5 | | #endif |
6 | | |
7 | | /* This heavily re-uses the logic from syncstream, but with different close |
8 | | * and gc_free semantics. */ |
9 | | |
10 | | /* Closes the pipe. */ |
11 | 0 | static MVMint64 do_close(MVMThreadContext *tc, MVMIOSyncPipeData *data) { |
12 | 0 | #ifdef _WIN32 |
13 | | DWORD status = 0; |
14 | | #else |
15 | 0 | int status = 0; |
16 | 0 | #endif |
17 | 0 | if (!data) return 0; |
18 | 0 | if (data->ss.handle == NULL || uv_is_closing((uv_handle_t*)data->ss.handle)) |
19 | 0 | return 0; |
20 | 0 | /* closing the in-/output std filehandle will shutdown the child process. */ |
21 | 0 | uv_unref((uv_handle_t*)data->ss.handle); |
22 | 0 | uv_close((uv_handle_t*)data->ss.handle, NULL); |
23 | 0 | if (data->process) { |
24 | 0 | #ifdef _WIN32 |
25 | | if (!uv_is_closing((uv_handle_t*)data->process)) |
26 | | uv_process_close(tc->loop, data->process); |
27 | | GetExitCodeProcess(data->process->process_handle, &status); |
28 | | status = status << 8; |
29 | | #else |
30 | 0 | pid_t wpid; |
31 | 0 | do |
32 | 0 | wpid = waitpid(data->process->pid, &status, 0); |
33 | 0 | while (wpid == -1 && errno == EINTR); |
34 | 0 | #endif |
35 | 0 | } |
36 | 0 | if (!status && data->process->data) { |
37 | 0 | status = *(MVMint64*)data->process->data; |
38 | 0 | MVM_free(data->process->data); |
39 | 0 | data->process->data = NULL; |
40 | 0 | } |
41 | 0 | uv_unref((uv_handle_t *)data->process); |
42 | 0 | uv_run(tc->loop, UV_RUN_DEFAULT); |
43 | 0 | data->process = NULL; |
44 | 0 | data->ss.handle = NULL; |
45 | 0 | MVM_free(data); |
46 | 0 | return (MVMint64)status; |
47 | 0 | } |
48 | 0 | static MVMint64 closefh(MVMThreadContext *tc, MVMOSHandle *h) { |
49 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
50 | 0 | h->body.data = NULL; /* data will be freed by do_close */ |
51 | 0 | return do_close(tc, data); |
52 | 0 | } |
53 | | |
54 | | /* Operations aiding process spawning and I/O handling. */ |
55 | 0 | static void bind_stdio_handle(MVMThreadContext *tc, MVMOSHandle *h, uv_stdio_container_t *stdio) { |
56 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
57 | 0 | stdio->flags = UV_INHERIT_STREAM; |
58 | 0 | stdio->data.stream = data->ss.handle; |
59 | 0 | } |
60 | | |
61 | | /* Frees data associated with the pipe, closing it if needed. */ |
62 | 0 | static void gc_free(MVMThreadContext *tc, MVMObject *h, void *d) { |
63 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)d; |
64 | 0 | do_close(tc, data); |
65 | 0 | } |
66 | | |
67 | | /* Get native file descriptor. */ |
68 | 0 | static MVMint64 mvm_fileno(MVMThreadContext *tc, MVMOSHandle *h) { |
69 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
70 | 0 | uv_os_fd_t fd; |
71 | 0 | if (uv_fileno((uv_handle_t *)data->ss.handle, &fd) >= 0) |
72 | 0 | return (MVMint64)fd; |
73 | 0 | return -1; |
74 | 0 | } |
75 | | |
76 | | /* IO ops table, populated with functions. */ |
77 | | static const MVMIOClosable closable = { closefh }; |
78 | | static const MVMIOSyncReadable sync_readable = { MVM_io_syncstream_read_bytes, |
79 | | MVM_io_syncstream_eof }; |
80 | | static const MVMIOSyncWritable sync_writable = { MVM_io_syncstream_write_bytes, |
81 | | MVM_io_syncstream_flush, |
82 | | MVM_io_syncstream_truncate }; |
83 | | static const MVMIOSeekable seekable = { MVM_io_syncstream_seek, |
84 | | MVM_io_syncstream_tell }; |
85 | | static const MVMIOPipeable pipeable = { bind_stdio_handle }; |
86 | | static const MVMIOIntrospection introspection = { NULL, mvm_fileno }; |
87 | | static const MVMIOOps op_table = { |
88 | | &closable, |
89 | | &sync_readable, |
90 | | &sync_writable, |
91 | | NULL, |
92 | | NULL, |
93 | | NULL, |
94 | | &seekable, |
95 | | NULL, |
96 | | &pipeable, |
97 | | NULL, |
98 | | &introspection, |
99 | | NULL, |
100 | | NULL, |
101 | | gc_free |
102 | | }; |
103 | | |
104 | | /* Creates a sync pipe handle. */ |
105 | 0 | MVMObject * MVM_io_syncpipe(MVMThreadContext *tc) { |
106 | 0 | MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); |
107 | 0 | MVMIOSyncPipeData * const data = MVM_calloc(1, sizeof(MVMIOSyncPipeData)); |
108 | 0 | uv_pipe_t *handle = MVM_malloc(sizeof(uv_pipe_t)); |
109 | 0 | uv_pipe_init(tc->loop, handle, 0); |
110 | 0 | data->ss.handle = (uv_stream_t *)handle; |
111 | 0 | result->body.ops = &op_table; |
112 | 0 | result->body.data = data; |
113 | 0 | return (MVMObject *)result; |
114 | 0 | } |