Coverage Report

Created: 2017-06-23 10:30

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