Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/io/filewatchers.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Info we convey about a file watcher. */
4
typedef struct {
5
    char             *path;
6
    uv_fs_event_t     handle;
7
    MVMThreadContext *tc;
8
    int               work_idx;
9
} WatchInfo;
10
11
0
static void on_changed(uv_fs_event_t *handle, const char *filename, int events, int status) {
12
0
    WatchInfo        *wi  = (WatchInfo *)handle->data;
13
0
    MVMThreadContext *tc  = wi->tc;
14
0
    MVMObject        *arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray);
15
0
    MVMAsyncTask     *t   = MVM_io_eventloop_get_active_work(tc, wi->work_idx);
16
0
    MVM_repr_push_o(tc, arr, t->body.schedulee);
17
0
    MVMROOT2(tc, t, arr, {
18
0
        MVMObject *filename_boxed;
19
0
        MVMObject *rename_boxed;
20
0
        if (filename) {
21
0
            MVMString *filename_str = MVM_string_utf8_c8_decode(tc,
22
0
                tc->instance->VMString, filename, strlen(filename));
23
0
            filename_boxed = MVM_repr_box_str(tc,
24
0
                tc->instance->boot_types.BOOTStr,
25
0
                filename_str);
26
0
        }
27
0
        else {
28
0
            filename_boxed = tc->instance->boot_types.BOOTStr;
29
0
        }
30
0
        MVM_repr_push_o(tc, arr, filename_boxed);
31
0
        rename_boxed = MVM_repr_box_int(tc,
32
0
            tc->instance->boot_types.BOOTInt,
33
0
            events == UV_RENAME ? 1 : 0);
34
0
        MVM_repr_push_o(tc, arr, rename_boxed);
35
0
        MVM_repr_push_o(tc, arr, tc->instance->boot_types.BOOTStr);
36
0
    });
37
0
    MVM_repr_push_o(tc, t->body.queue, arr);
38
0
}
39
40
/* Sets the signal handler up on the event loop. */
41
0
static void setup(MVMThreadContext *tc, uv_loop_t *loop, MVMObject *async_task, void *data) {
42
0
    WatchInfo *wi = (WatchInfo *)data;
43
0
    int        r;
44
0
45
0
    /* Add task to active list. */
46
0
    wi->work_idx    = MVM_io_eventloop_add_active_work(tc, async_task);
47
0
    wi->tc          = tc;
48
0
    wi->handle.data = wi;
49
0
50
0
    /* Start watching. */
51
0
    uv_fs_event_init(loop, &wi->handle);
52
0
    if ((r = uv_fs_event_start(&wi->handle, on_changed, wi->path, 0)) != 0) {
53
0
        /* Error; need to notify. */
54
0
        MVMROOT(tc, async_task, {
55
0
            MVMObject    *arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray);
56
0
            MVMAsyncTask *t   = (MVMAsyncTask *)async_task;
57
0
            MVM_repr_push_o(tc, arr, t->body.schedulee);
58
0
            MVM_repr_push_o(tc, arr, tc->instance->boot_types.BOOTStr);
59
0
            MVM_repr_push_o(tc, arr, tc->instance->boot_types.BOOTInt);
60
0
            MVMROOT(tc, arr, {
61
0
                MVMString *msg_str = MVM_string_ascii_decode_nt(tc,
62
0
                    tc->instance->VMString, uv_strerror(r));
63
0
                MVMObject *msg_box = MVM_repr_box_str(tc,
64
0
                    tc->instance->boot_types.BOOTStr, msg_str);
65
0
                MVM_repr_push_o(tc, arr, msg_box);
66
0
            });
67
0
            MVM_repr_push_o(tc, t->body.queue, arr);
68
0
        });
69
0
    }
70
0
}
71
72
/* Frees data associated with a file watcher task. */
73
0
static void gc_free(MVMThreadContext *tc, MVMObject *t, void *data) {
74
0
    if (data)
75
0
        MVM_free(data);
76
0
}
77
78
/* Operations table for a file watcher task. */
79
static const MVMAsyncTaskOps op_table = {
80
    setup,
81
    NULL,
82
    NULL,
83
    NULL,
84
    gc_free
85
};
86
87
MVMObject * MVM_io_file_watch(MVMThreadContext *tc, MVMObject *queue,
88
                              MVMObject *schedulee, MVMString *path,
89
0
                              MVMObject *async_type) {
90
0
    MVMAsyncTask *task;
91
0
    WatchInfo    *watch_info;
92
0
93
0
    /* Encode path. */
94
0
    char *c_path = MVM_string_utf8_c8_encode_C_string(tc, path);
95
0
96
0
    /* Validate REPRs. */
97
0
    if (REPR(queue)->ID != MVM_REPR_ID_ConcBlockingQueue)
98
0
        MVM_exception_throw_adhoc(tc,
99
0
            "file watch target queue must have ConcBlockingQueue REPR");
100
0
    if (REPR(async_type)->ID != MVM_REPR_ID_MVMAsyncTask)
101
0
        MVM_exception_throw_adhoc(tc,
102
0
            "file watch result type must have REPR AsyncTask");
103
0
104
0
    /* Create async task handle. */
105
0
    MVMROOT2(tc, queue, schedulee, {
106
0
        task = (MVMAsyncTask *)MVM_repr_alloc_init(tc, async_type);
107
0
    });
108
0
    MVM_ASSIGN_REF(tc, &(task->common.header), task->body.queue, queue);
109
0
    MVM_ASSIGN_REF(tc, &(task->common.header), task->body.schedulee, schedulee);
110
0
    task->body.ops   = &op_table;
111
0
    watch_info       = MVM_malloc(sizeof(WatchInfo));
112
0
    watch_info->path = c_path;
113
0
    task->body.data  = watch_info;
114
0
115
0
    /* Hand the task off to the event loop. */
116
0
    MVMROOT(tc, task, {
117
0
        MVM_io_eventloop_queue_work(tc, (MVMObject *)task);
118
0
    });
119
0
120
0
    return (MVMObject *)task;
121
0
}