Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/io/signals.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
#include <signal.h>
4
#ifdef _WIN32
5
/* Add signals used by libuv but not defined in the Windows signal.h */
6
#define SIGHUP      1
7
#define SIGKILL     9
8
#define SIGBREAK    21
9
#define SIGWINCH    28
10
#endif
11
12
/* Info we convey about a signal handler. */
13
typedef struct {
14
    int               signum;
15
    uv_signal_t       handle;
16
    MVMThreadContext *tc;
17
    int               work_idx;
18
} SignalInfo;
19
20
/* Signal callback; dispatches schedulee to the queue. */
21
0
static void signal_cb(uv_signal_t *handle, int sig_num) {
22
0
    SignalInfo       *si  = (SignalInfo *)handle->data;
23
0
    MVMThreadContext *tc  = si->tc;
24
0
    MVMObject        *arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray);
25
0
    MVMAsyncTask     *t   = MVM_io_eventloop_get_active_work(tc, si->work_idx);
26
0
    MVM_repr_push_o(tc, arr, t->body.schedulee);
27
0
    MVMROOT2(tc, t, arr, {
28
0
        MVMObject *sig_num_boxed = MVM_repr_box_int(tc,
29
0
            tc->instance->boot_types.BOOTInt, sig_num);
30
0
        MVM_repr_push_o(tc, arr, sig_num_boxed);
31
0
    });
32
0
    MVM_repr_push_o(tc, t->body.queue, arr);
33
0
}
34
35
/* Sets the signal handler up on the event loop. */
36
0
static void setup(MVMThreadContext *tc, uv_loop_t *loop, MVMObject *async_task, void *data) {
37
0
    SignalInfo *si = (SignalInfo *)data;
38
0
    uv_signal_init(loop, &si->handle);
39
0
    si->work_idx    = MVM_io_eventloop_add_active_work(tc, async_task);
40
0
    si->tc          = tc;
41
0
    si->handle.data = si;
42
0
    uv_signal_start(&si->handle, signal_cb, si->signum);
43
0
}
44
45
0
static void cancel(MVMThreadContext *tc, uv_loop_t *loop, MVMObject *async_task, void *data) {
46
0
    SignalInfo *si = (SignalInfo *)data;
47
0
    if (si->work_idx >= 0) {
48
0
        if (!uv_is_closing((uv_handle_t *)&(si->handle)))
49
0
            uv_signal_stop(&si->handle);
50
0
        MVM_io_eventloop_remove_active_work(tc, &(si->work_idx));
51
0
    }
52
0
}
53
54
/* Frees data associated with a timer async task. */
55
0
static void gc_free(MVMThreadContext *tc, MVMObject *t, void *data) {
56
0
    if (data)
57
0
        MVM_free(data);
58
0
}
59
60
/* Operations table for async timer task. */
61
static const MVMAsyncTaskOps op_table = {
62
    setup,
63
    NULL,
64
    cancel,
65
    NULL,
66
    gc_free
67
};
68
69
0
#define NUM_SIG_WANTED  35
70
#define PROCESS_SIGS(X) \
71
    X( MVM_SIGHUP    )  \
72
    X( MVM_SIGINT    )  \
73
    X( MVM_SIGQUIT   )  \
74
    X( MVM_SIGILL    )  \
75
    X( MVM_SIGTRAP   )  \
76
    X( MVM_SIGABRT   )  \
77
    X( MVM_SIGEMT    )  \
78
    X( MVM_SIGFPE    )  \
79
    X( MVM_SIGKILL   )  \
80
    X( MVM_SIGBUS    )  \
81
    X( MVM_SIGSEGV   )  \
82
    X( MVM_SIGSYS    )  \
83
    X( MVM_SIGPIPE   )  \
84
    X( MVM_SIGALRM   )  \
85
    X( MVM_SIGTERM   )  \
86
    X( MVM_SIGURG    )  \
87
    X( MVM_SIGSTOP   )  \
88
    X( MVM_SIGTSTP   )  \
89
    X( MVM_SIGCONT   )  \
90
    X( MVM_SIGCHLD   )  \
91
    X( MVM_SIGTTIN   )  \
92
    X( MVM_SIGTTOU   )  \
93
    X( MVM_SIGIO     )  \
94
    X( MVM_SIGXCPU   )  \
95
    X( MVM_SIGXFSZ   )  \
96
    X( MVM_SIGVTALRM )  \
97
    X( MVM_SIGPROF   )  \
98
    X( MVM_SIGWINCH  )  \
99
    X( MVM_SIGINFO   )  \
100
    X( MVM_SIGUSR1   )  \
101
    X( MVM_SIGUSR2   )  \
102
    X( MVM_SIGTHR    )  \
103
    X( MVM_SIGSTKFLT )  \
104
    X( MVM_SIGPWR    )  \
105
    X( MVM_SIGBREAK  )
106
107
#define GEN_ENUMS(v)   v,
108
#define GEN_STRING(v) #v,
109
110
static enum {
111
    PROCESS_SIGS(GEN_ENUMS)
112
} MVM_sig_names;
113
114
static char const * const SIG_WANTED[NUM_SIG_WANTED] = {
115
    PROCESS_SIGS(GEN_STRING)
116
};
117
118
0
static void populate_sig_values(MVMint8 *sig_vals) {
119
0
    MVMint8 i;
120
0
    for (i = 0; i < NUM_SIG_WANTED; i++) { sig_vals[i] = 0; }
121
0
122
0
#ifdef SIGHUP
123
0
    sig_vals[MVM_SIGHUP]    = SIGHUP;
124
0
#endif
125
0
#ifdef SIGINT
126
0
    sig_vals[MVM_SIGINT]    = SIGINT;
127
0
#endif
128
0
#ifdef SIGQUIT
129
0
    sig_vals[MVM_SIGQUIT]   = SIGQUIT;
130
0
#endif
131
0
#ifdef SIGILL
132
0
    sig_vals[MVM_SIGILL]    = SIGILL;
133
0
#endif
134
0
#ifdef SIGTRAP
135
0
    sig_vals[MVM_SIGTRAP]   = SIGTRAP;
136
0
#endif
137
0
#ifdef SIGABRT
138
0
    sig_vals[MVM_SIGABRT]   = SIGABRT;
139
0
#endif
140
0
#ifdef SIGEMT
141
    sig_vals[MVM_SIGEMT]    = SIGEMT;
142
#endif
143
0
#ifdef SIGFPE
144
0
    sig_vals[MVM_SIGFPE]    = SIGFPE;
145
0
#endif
146
0
#ifdef SIGKILL
147
0
    sig_vals[MVM_SIGKILL]   = SIGKILL;
148
0
#endif
149
0
#ifdef SIGBUS
150
0
    sig_vals[MVM_SIGBUS]    = SIGBUS;
151
0
#endif
152
0
#ifdef SIGSEGV
153
0
    sig_vals[MVM_SIGSEGV]   = SIGSEGV;
154
0
#endif
155
0
#ifdef SIGSYS
156
0
    sig_vals[MVM_SIGSYS]    = SIGSYS;
157
0
#endif
158
0
#ifdef SIGPIPE
159
0
    sig_vals[MVM_SIGPIPE]   = SIGPIPE;
160
0
#endif
161
0
#ifdef SIGALRM
162
0
    sig_vals[MVM_SIGALRM]   = SIGALRM;
163
0
#endif
164
0
#ifdef SIGTERM
165
0
    sig_vals[MVM_SIGTERM]   = SIGTERM;
166
0
#endif
167
0
#ifdef SIGURG
168
0
    sig_vals[MVM_SIGURG]    = SIGURG;
169
0
#endif
170
0
#ifdef SIGSTOP
171
0
    sig_vals[MVM_SIGSTOP]   = SIGSTOP;  /* hammer time */
172
0
#endif
173
0
#ifdef SIGTSTP
174
0
    sig_vals[MVM_SIGTSTP]   = SIGTSTP;
175
0
#endif
176
0
#ifdef SIGCONT
177
0
    sig_vals[MVM_SIGCONT]   = SIGCONT;
178
0
#endif
179
0
#ifdef SIGCHLD
180
0
    sig_vals[MVM_SIGCHLD]   = SIGCHLD;
181
0
#endif
182
0
#ifdef SIGTTIN
183
0
    sig_vals[MVM_SIGTTIN]   = SIGTTIN;
184
0
#endif
185
0
#ifdef SIGTTOU
186
0
    sig_vals[MVM_SIGTTOU]   = SIGTTOU;
187
0
#endif
188
0
#ifdef SIGIO
189
0
    sig_vals[MVM_SIGIO]     = SIGIO;
190
0
#endif
191
0
#ifdef SIGXCPU
192
0
    sig_vals[MVM_SIGXCPU]   = SIGXCPU;
193
0
#endif
194
0
#ifdef SIGXFSZ
195
0
    sig_vals[MVM_SIGXFSZ]   = SIGXFSZ;
196
0
#endif
197
0
#ifdef SIGVTALRM
198
0
    sig_vals[MVM_SIGVTALRM] = SIGVTALRM;
199
0
#endif
200
0
#ifdef SIGPROF
201
0
    sig_vals[MVM_SIGPROF]   = SIGPROF;
202
0
#endif
203
0
#ifdef SIGWINCH
204
0
    sig_vals[MVM_SIGWINCH]  = SIGWINCH;
205
0
#endif
206
0
#ifdef SIGINFO
207
    sig_vals[MVM_SIGINFO]   = SIGINFO;
208
#endif
209
0
#ifdef SIGUSR1
210
0
    sig_vals[MVM_SIGUSR1]   = SIGUSR1;
211
0
#endif
212
0
#ifdef SIGUSR2
213
0
    sig_vals[MVM_SIGUSR2]   = SIGUSR2;
214
0
#endif
215
0
#ifdef SIGTHR
216
    sig_vals[MVM_SIGTHR]    = SIGTHR;
217
#endif
218
0
#ifdef SIGSTKFLT
219
0
    sig_vals[MVM_SIGSTKFLT] = SIGSTKFLT;
220
0
#endif
221
0
#ifdef SIGPWR
222
0
    sig_vals[MVM_SIGPWR]    = SIGPWR;
223
0
#endif
224
0
#ifdef SIGBREAK
225
    sig_vals[MVM_SIGBREAK]  = SIGBREAK;
226
#endif
227
0
}
228
229
0
#define SIG_SHIFT(s) (1 << ((s) - 1))
230
231
0
static void populate_instance_valid_sigs(MVMThreadContext *tc, MVMint8 *sig_vals) {
232
0
    MVMuint64 valid_sigs = 0;
233
0
    MVMint8 i;
234
0
235
0
    if ( tc->instance->valid_sigs ) return;
236
0
237
0
    for (i = 0; i < NUM_SIG_WANTED; i++) {
238
0
        if (sig_vals[i]) {
239
0
            valid_sigs |=  SIG_SHIFT(sig_vals[i]);
240
0
        }
241
0
    }
242
0
    tc->instance->valid_sigs = valid_sigs;
243
0
}
244
245
0
MVMObject * MVM_io_get_signals(MVMThreadContext *tc) {
246
0
    MVMInstance  * const instance = tc->instance;
247
0
    MVMHLLConfig *       hll      = MVM_hll_current(tc);
248
0
    MVMObject    *       sig_arr;
249
0
250
0
    MVMint8 sig_wanted_vals[NUM_SIG_WANTED];
251
0
    populate_sig_values(sig_wanted_vals);
252
0
253
0
    if (instance->sig_arr) {
254
0
        return instance->sig_arr;
255
0
    }
256
0
257
0
    sig_arr = MVM_repr_alloc_init(tc, hll->slurpy_array_type);
258
0
    MVMROOT(tc, sig_arr, {
259
0
        MVMint8 i;
260
0
        for (i = 0; i < NUM_SIG_WANTED; i++) {
261
0
            MVMObject *key      = NULL;
262
0
            MVMString *full_key = NULL;
263
0
            MVMObject *val      = NULL;
264
0
265
0
            MVMROOT3(tc, key, full_key, val, {
266
0
                full_key = MVM_string_utf8_c8_decode(
267
0
                    tc, instance->VMString, SIG_WANTED[i], strlen(SIG_WANTED[i])
268
0
                );
269
0
270
0
                key = MVM_repr_box_str(tc, hll->str_box_type,
271
0
                    MVM_string_substring(tc, full_key, 4, -1)
272
0
                );
273
0
                val = MVM_repr_box_int(tc, hll->int_box_type, sig_wanted_vals[i]);
274
0
275
0
                MVM_repr_push_o(tc, sig_arr, key);
276
0
                MVM_repr_push_o(tc, sig_arr, val);
277
0
            });
278
0
        }
279
0
280
0
        populate_instance_valid_sigs(tc, sig_wanted_vals);
281
0
        instance->sig_arr = sig_arr;
282
0
    });
283
0
284
0
    return sig_arr;
285
0
}
286
287
/* Register a new signal handler. */
288
MVMObject * MVM_io_signal_handle(MVMThreadContext *tc, MVMObject *queue,
289
                                 MVMObject *schedulee, MVMint64 signal,
290
0
                                 MVMObject *async_type) {
291
0
    MVMAsyncTask *task;
292
0
    SignalInfo   *signal_info;
293
0
    MVMInstance  * const instance = tc->instance;
294
0
295
0
    if ( !instance->valid_sigs ) {
296
0
        MVMint8 sig_wanted_vals[NUM_SIG_WANTED];
297
0
        populate_sig_values(sig_wanted_vals);
298
0
        populate_instance_valid_sigs(tc, sig_wanted_vals);
299
0
    }
300
0
    if ( signal <= 0 || !(instance->valid_sigs & SIG_SHIFT(signal) ) ) {
301
0
        MVM_exception_throw_adhoc(tc, "Unsupported signal handler %d",
302
0
            (int)signal);
303
0
    }
304
0
305
0
    /* Validate REPRs. */
306
0
    if (REPR(queue)->ID != MVM_REPR_ID_ConcBlockingQueue)
307
0
        MVM_exception_throw_adhoc(tc,
308
0
            "signal target queue must have ConcBlockingQueue REPR");
309
0
    if (REPR(async_type)->ID != MVM_REPR_ID_MVMAsyncTask)
310
0
        MVM_exception_throw_adhoc(tc,
311
0
            "signal result type must have REPR AsyncTask");
312
0
313
0
    /* Create async task handle. */
314
0
    MVMROOT2(tc, queue, schedulee, {
315
0
        task = (MVMAsyncTask *)MVM_repr_alloc_init(tc, async_type);
316
0
    });
317
0
    MVM_ASSIGN_REF(tc, &(task->common.header), task->body.queue, queue);
318
0
    MVM_ASSIGN_REF(tc, &(task->common.header), task->body.schedulee, schedulee);
319
0
    task->body.ops      = &op_table;
320
0
    signal_info         = MVM_malloc(sizeof(SignalInfo));
321
0
    signal_info->signum = signal;
322
0
    task->body.data     = signal_info;
323
0
324
0
    /* Hand the task off to the event loop. */
325
0
    MVMROOT(tc, task, {
326
0
        MVM_io_eventloop_queue_work(tc, (MVMObject *)task);
327
0
    });
328
0
329
0
    return (MVMObject *)task;
330
0
}