/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 | 7 | static MVMint64 do_close(MVMThreadContext *tc, MVMIOSyncPipeData *data) { |
12 | 7 | #ifdef _WIN32 |
13 | | DWORD status = 0; |
14 | | #else |
15 | 7 | int status = 0; |
16 | 7 | #endif |
17 | 7 | if (data->ss.handle == NULL || uv_is_closing((uv_handle_t*)data->ss.handle)) |
18 | 2 | return 0; |
19 | 7 | /* closing the in-/output std filehandle will shutdown the child process. */ |
20 | 5 | uv_unref((uv_handle_t*)data->ss.handle); |
21 | 5 | uv_close((uv_handle_t*)data->ss.handle, NULL); |
22 | 5 | if (data->process) { |
23 | 5 | #ifdef _WIN32 |
24 | | if (!uv_is_closing((uv_handle_t*)data->process)) |
25 | | uv_process_close(tc->loop, data->process); |
26 | | GetExitCodeProcess(data->process->process_handle, &status); |
27 | | status = status << 8; |
28 | | #else |
29 | 5 | pid_t wpid; |
30 | 5 | do |
31 | 5 | wpid = waitpid(data->process->pid, &status, 0); |
32 | 5 | while (wpid == -1 && errno == EINTR); |
33 | 5 | #endif |
34 | 5 | } |
35 | 5 | if (!status && data->process->data) { |
36 | 4 | status = *(MVMint64*)data->process->data; |
37 | 4 | MVM_free(data->process->data); |
38 | 4 | data->process->data = NULL; |
39 | 4 | } |
40 | 5 | uv_unref((uv_handle_t *)data->process); |
41 | 5 | uv_run(tc->loop, UV_RUN_DEFAULT); |
42 | 5 | data->process = NULL; |
43 | 5 | data->ss.handle = NULL; |
44 | 5 | if (data->ss.ds) { |
45 | 5 | MVM_string_decodestream_destroy(tc, data->ss.ds); |
46 | 5 | data->ss.ds = NULL; |
47 | 5 | } |
48 | 5 | return (MVMint64)status; |
49 | 7 | } |
50 | 7 | static MVMint64 closefh(MVMThreadContext *tc, MVMOSHandle *h) { |
51 | 7 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
52 | 7 | return do_close(tc, data); |
53 | 7 | } |
54 | | |
55 | | /* Operations aiding process spawning and I/O handling. */ |
56 | | static void bind_stdio_handle(MVMThreadContext *tc, MVMOSHandle *h, uv_stdio_container_t *stdio, |
57 | 0 | uv_process_t *process) { |
58 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
59 | 0 | stdio->flags = UV_INHERIT_STREAM; |
60 | 0 | stdio->data.stream = data->ss.handle; |
61 | 0 | } |
62 | | |
63 | | /* Frees data associated with the pipe, closing it if needed. */ |
64 | 0 | static void gc_free(MVMThreadContext *tc, MVMObject *h, void *d) { |
65 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)d; |
66 | 0 | do_close(tc, data); |
67 | 0 | } |
68 | | |
69 | | /* Get native file descriptor. */ |
70 | 0 | static MVMint64 mvm_fileno(MVMThreadContext *tc, MVMOSHandle *h) { |
71 | 0 | MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data; |
72 | 0 | uv_os_fd_t fd; |
73 | 0 | if (uv_fileno((uv_handle_t *)data->ss.handle, &fd) >= 0) |
74 | 0 | return (MVMint64)fd; |
75 | 0 | return -1; |
76 | 0 | } |
77 | | |
78 | | /* IO ops table, populated with functions. */ |
79 | | static const MVMIOClosable closable = { closefh }; |
80 | | static const MVMIOEncodable encodable = { MVM_io_syncstream_set_encoding }; |
81 | | static const MVMIOSyncReadable sync_readable = { MVM_io_syncstream_set_separator, |
82 | | MVM_io_syncstream_read_line, |
83 | | MVM_io_syncstream_slurp, |
84 | | MVM_io_syncstream_read_chars, |
85 | | MVM_io_syncstream_read_bytes, |
86 | | MVM_io_syncstream_eof }; |
87 | | static const MVMIOSyncWritable sync_writable = { MVM_io_syncstream_write_str, |
88 | | MVM_io_syncstream_write_bytes, |
89 | | MVM_io_syncstream_flush, |
90 | | MVM_io_syncstream_truncate }; |
91 | | static const MVMIOSeekable seekable = { MVM_io_syncstream_seek, |
92 | | MVM_io_syncstream_tell }; |
93 | | static const MVMIOPipeable pipeable = { bind_stdio_handle }; |
94 | | static const MVMIOIntrospection introspection = { NULL, mvm_fileno }; |
95 | | static const MVMIOOps op_table = { |
96 | | &closable, |
97 | | &encodable, |
98 | | &sync_readable, |
99 | | &sync_writable, |
100 | | NULL, |
101 | | NULL, |
102 | | NULL, |
103 | | &seekable, |
104 | | NULL, |
105 | | &pipeable, |
106 | | NULL, |
107 | | &introspection, |
108 | | NULL, |
109 | | gc_free |
110 | | }; |
111 | | |
112 | | /* Creates a sync pipe handle. */ |
113 | 6 | MVMObject * MVM_io_syncpipe(MVMThreadContext *tc) { |
114 | 6 | MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); |
115 | 6 | MVMIOSyncPipeData * const data = MVM_calloc(1, sizeof(MVMIOSyncPipeData)); |
116 | 6 | uv_pipe_t *handle = MVM_malloc(sizeof(uv_pipe_t)); |
117 | 6 | uv_pipe_init(tc->loop, handle, 0); |
118 | 6 | data->ss.handle = (uv_stream_t *)handle; |
119 | 6 | data->ss.encoding = MVM_encoding_type_utf8; |
120 | 6 | data->ss.translate_newlines = 1; |
121 | 6 | MVM_string_decode_stream_sep_default(tc, &(data->ss.sep_spec)); |
122 | 6 | result->body.ops = &op_table; |
123 | 6 | result->body.data = data; |
124 | 6 | return (MVMObject *)result; |
125 | 6 | } |