Coverage Report

Created: 2017-04-15 07:07

/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
}