Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/io/io.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Delegatory functions that assert we have a capable handle, then delegate
4
 * through the IO table to the correct operation. */
5
6
14.2k
static MVMOSHandle * verify_is_handle(MVMThreadContext *tc, MVMObject *oshandle, const char *op) {
7
14.2k
    if (REPR(oshandle)->ID != MVM_REPR_ID_MVMOSHandle)
8
0
        MVM_exception_throw_adhoc(tc, "%s requires an object with REPR MVMOSHandle (got %s with REPR %s)", op, MVM_6model_get_debug_name(tc, oshandle), REPR(oshandle)->name);
9
14.2k
    if (!IS_CONCRETE(oshandle))
10
0
        MVM_exception_throw_adhoc(tc, "%s requires a concrete MVMOSHandle, but got a type object", op);
11
14.2k
    return (MVMOSHandle *)oshandle;
12
14.2k
}
13
14
14.2k
static uv_mutex_t * acquire_mutex(MVMThreadContext *tc, MVMOSHandle *handle) {
15
14.2k
    uv_mutex_t *mutex = handle->body.mutex;
16
14.2k
    MVM_gc_mark_thread_blocked(tc);
17
14.2k
    uv_mutex_lock(mutex);
18
14.2k
    MVM_gc_mark_thread_unblocked(tc);
19
14.2k
    MVM_tc_set_ex_release_mutex(tc, mutex);
20
14.2k
    return mutex;
21
14.2k
}
22
23
14.2k
static void release_mutex(MVMThreadContext *tc, uv_mutex_t *mutex) {
24
14.2k
    uv_mutex_unlock(mutex);
25
14.2k
    MVM_tc_clear_ex_release_mutex(tc);
26
14.2k
}
27
28
212
MVMint64 MVM_io_close(MVMThreadContext *tc, MVMObject *oshandle) {
29
212
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "close");
30
212
    if (handle->body.ops->closable) {
31
212
        MVMint64 ret;
32
212
        MVMROOT(tc, handle, {
33
212
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
34
212
            ret = handle->body.ops->closable->close(tc, handle);
35
212
            release_mutex(tc, mutex);
36
212
        });
37
212
        return ret;
38
212
    }
39
212
    else
40
0
        MVM_exception_throw_adhoc(tc, "Cannot close this kind of handle");
41
212
}
42
43
1
MVMint64 MVM_io_is_tty(MVMThreadContext *tc, MVMObject *oshandle) {
44
1
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "istty");
45
1
    /* We need the extra check on is_tty because it is NULL for pipes. */
46
1
    if (handle->body.ops->introspection && handle->body.ops->introspection->is_tty) {
47
1
        MVMint64 ret;
48
1
        MVMROOT(tc, handle, {
49
1
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
50
1
            ret = handle->body.ops->introspection->is_tty(tc, handle);
51
1
            release_mutex(tc, mutex);
52
1
        });
53
1
        return ret;
54
1
    }
55
0
    else {
56
0
        return 0;
57
0
    }
58
1
}
59
60
0
MVMint64 MVM_io_fileno(MVMThreadContext *tc, MVMObject *oshandle) {
61
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "get native descriptor");
62
0
    if (handle->body.ops->introspection) {
63
0
        MVMint64 ret;
64
0
        MVMROOT(tc, handle, {
65
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
66
0
            ret = handle->body.ops->introspection->native_descriptor(tc, handle);
67
0
            release_mutex(tc, mutex);
68
0
        });
69
0
        return ret;
70
0
    }
71
0
    else {
72
0
        return -1;
73
0
    }
74
0
}
75
76
6
void MVM_io_seek(MVMThreadContext *tc, MVMObject *oshandle, MVMint64 offset, MVMint64 flag) {
77
6
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "seek");
78
6
    if (handle->body.ops->seekable) {
79
6
        MVMROOT(tc, handle, {
80
6
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
81
6
            handle->body.ops->seekable->seek(tc, handle, offset, flag);
82
6
            release_mutex(tc, mutex);
83
6
        });
84
6
    }
85
6
    else
86
0
        MVM_exception_throw_adhoc(tc, "Cannot seek this kind of handle");
87
6
}
88
89
9
MVMint64 MVM_io_tell(MVMThreadContext *tc, MVMObject *oshandle) {
90
9
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "tell");
91
9
    if (handle->body.ops->seekable) {
92
9
        MVMint64 result;
93
9
        MVMROOT(tc, handle, {
94
9
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
95
9
            result = handle->body.ops->seekable->tell(tc, handle);
96
9
            release_mutex(tc, mutex);
97
9
        });
98
9
        return result;
99
9
    }
100
9
    else
101
0
        MVM_exception_throw_adhoc(tc, "Cannot tell this kind of handle");
102
9
}
103
104
387
void MVM_io_read_bytes(MVMThreadContext *tc, MVMObject *oshandle, MVMObject *result, MVMint64 length) {
105
387
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "read bytes");
106
387
    MVMint64 bytes_read;
107
387
    char *buf;
108
387
109
387
    /* Ensure the target is in the correct form. */
110
387
    if (!IS_CONCRETE(result) || REPR(result)->ID != MVM_REPR_ID_VMArray)
111
0
        MVM_exception_throw_adhoc(tc, "read_fhb requires a native array to write to");
112
387
    if (((MVMArrayREPRData *)STABLE(result)->REPR_data)->slot_type != MVM_ARRAY_U8
113
2
        && ((MVMArrayREPRData *)STABLE(result)->REPR_data)->slot_type != MVM_ARRAY_I8)
114
0
        MVM_exception_throw_adhoc(tc, "read_fhb requires a native array of uint8 or int8");
115
387
116
387
    if (length < 1)
117
0
        MVM_exception_throw_adhoc(tc, "Out of range: attempted to read %"PRId64" bytes from filehandle", length);
118
387
119
387
    if (handle->body.ops->sync_readable) {
120
387
        MVMROOT2(tc, handle, result, {
121
387
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
122
387
            bytes_read = handle->body.ops->sync_readable->read_bytes(tc, handle, &buf, length);
123
387
            release_mutex(tc, mutex);
124
387
        });
125
387
    }
126
387
    else
127
0
        MVM_exception_throw_adhoc(tc, "Cannot read characters from this kind of handle");
128
387
129
387
    /* Stash the data in the VMArray. */
130
387
    ((MVMArray *)result)->body.slots.i8 = (MVMint8 *)buf;
131
387
    ((MVMArray *)result)->body.start    = 0;
132
387
    ((MVMArray *)result)->body.ssize    = bytes_read;
133
387
    ((MVMArray *)result)->body.elems    = bytes_read;
134
387
}
135
136
12.9k
void MVM_io_write_bytes(MVMThreadContext *tc, MVMObject *oshandle, MVMObject *buffer) {
137
12.9k
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "write bytes");
138
12.9k
    char *output;
139
12.9k
    MVMint64 output_size;
140
12.9k
141
12.9k
    /* Ensure the target is in the correct form. */
142
12.9k
    if (!IS_CONCRETE(buffer) || REPR(buffer)->ID != MVM_REPR_ID_VMArray)
143
0
        MVM_exception_throw_adhoc(tc, "write_fhb requires a native array to read from");
144
12.9k
    if (((MVMArrayREPRData *)STABLE(buffer)->REPR_data)->slot_type != MVM_ARRAY_U8
145
0
        && ((MVMArrayREPRData *)STABLE(buffer)->REPR_data)->slot_type != MVM_ARRAY_I8)
146
0
        MVM_exception_throw_adhoc(tc, "write_fhb requires a native array of uint8 or int8");
147
12.9k
148
12.9k
    output = (char *)(((MVMArray *)buffer)->body.slots.i8 + ((MVMArray *)buffer)->body.start);
149
12.9k
    output_size = ((MVMArray *)buffer)->body.elems;
150
12.9k
151
12.9k
    if (handle->body.ops->sync_writable) {
152
12.9k
        MVMROOT(tc, handle, {
153
12.9k
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
154
12.9k
            handle->body.ops->sync_writable->write_bytes(tc, handle, output, output_size);
155
12.9k
            release_mutex(tc, mutex);
156
12.9k
        });
157
12.9k
    }
158
12.9k
    else
159
0
        MVM_exception_throw_adhoc(tc, "Cannot write bytes to this kind of handle");
160
12.9k
}
161
162
void MVM_io_write_bytes_c(MVMThreadContext *tc, MVMObject *oshandle, char *output,
163
316
                          MVMuint64 output_size) {
164
316
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "write bytes");
165
316
    if (handle->body.ops->sync_writable) {
166
316
        MVMROOT(tc, handle, {
167
316
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
168
316
            handle->body.ops->sync_writable->write_bytes(tc, handle, output, output_size);
169
316
            release_mutex(tc, mutex);
170
316
        });
171
316
    }
172
316
    else
173
0
        MVM_exception_throw_adhoc(tc, "Cannot write bytes to this kind of handle");
174
316
}
175
176
MVMObject * MVM_io_read_bytes_async(MVMThreadContext *tc, MVMObject *oshandle, MVMObject *queue,
177
0
                                    MVMObject *schedulee, MVMObject *buf_type, MVMObject *async_type) {
178
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "read bytes asynchronously");
179
0
    if (handle->body.ops->async_readable) {
180
0
        MVMObject *result;
181
0
        MVMROOT5(tc, queue, schedulee, buf_type, async_type, handle, {
182
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
183
0
            result = (MVMObject *)handle->body.ops->async_readable->read_bytes(tc,
184
0
                handle, queue, schedulee, buf_type, async_type);
185
0
            release_mutex(tc, mutex);
186
0
        });
187
0
        return result;
188
0
    }
189
0
    else
190
0
        MVM_exception_throw_adhoc(tc, "Cannot read bytes asynchronously from this kind of handle");
191
0
}
192
193
MVMObject * MVM_io_write_bytes_async(MVMThreadContext *tc, MVMObject *oshandle, MVMObject *queue,
194
0
                                     MVMObject *schedulee, MVMObject *buffer, MVMObject *async_type) {
195
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "write buffer asynchronously");
196
0
    if (buffer == NULL)
197
0
        MVM_exception_throw_adhoc(tc, "Failed to write to filehandle: NULL buffer given");
198
0
    if (handle->body.ops->async_writable) {
199
0
        MVMObject *result;
200
0
        MVMROOT5(tc, queue, schedulee, buffer, async_type, handle, {
201
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
202
0
            result = (MVMObject *)handle->body.ops->async_writable->write_bytes(tc,
203
0
                handle, queue, schedulee, buffer, async_type);
204
0
            release_mutex(tc, mutex);
205
0
        });
206
0
        return result;
207
0
    }
208
0
    else
209
0
        MVM_exception_throw_adhoc(tc, "Cannot write bytes asynchronously to this kind of handle");
210
0
}
211
212
MVMObject * MVM_io_write_bytes_to_async(MVMThreadContext *tc, MVMObject *oshandle, MVMObject *queue,
213
                                        MVMObject *schedulee, MVMObject *buffer, MVMObject *async_type,
214
0
                                        MVMString *host, MVMint64 port) {
215
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "write buffer asynchronously to destination");
216
0
    if (buffer == NULL)
217
0
        MVM_exception_throw_adhoc(tc, "Failed to write to filehandle: NULL buffer given");
218
0
    if (handle->body.ops->async_writable_to) {
219
0
        MVMObject *result;
220
0
        MVMROOT6(tc, host, queue, schedulee, buffer, async_type, handle, {
221
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
222
0
            result = (MVMObject *)handle->body.ops->async_writable_to->write_bytes_to(tc,
223
0
                handle, queue, schedulee, buffer, async_type, host, port);
224
0
            release_mutex(tc, mutex);
225
0
        });
226
0
        return result;
227
0
    }
228
0
    else
229
0
        MVM_exception_throw_adhoc(tc, "Cannot write bytes to a destination asynchronously to this kind of handle");
230
0
}
231
232
16
MVMint64 MVM_io_eof(MVMThreadContext *tc, MVMObject *oshandle) {
233
16
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "eof");
234
16
    if (handle->body.ops->sync_readable) {
235
16
        MVMint64 result;
236
16
        MVMROOT(tc, handle, {
237
16
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
238
16
            result = handle->body.ops->sync_readable->eof(tc, handle);
239
16
            release_mutex(tc, mutex);
240
16
        });
241
16
        return result;
242
16
    }
243
16
    else
244
0
        MVM_exception_throw_adhoc(tc, "Cannot eof this kind of handle");
245
16
}
246
247
0
MVMint64 MVM_io_lock(MVMThreadContext *tc, MVMObject *oshandle, MVMint64 flag) {
248
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "lock");
249
0
    if (handle->body.ops->lockable) {
250
0
        MVMint64 result;
251
0
        MVMROOT(tc, handle, {
252
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
253
0
            result = handle->body.ops->lockable->lock(tc, handle, flag);
254
0
            release_mutex(tc, mutex);
255
0
        });
256
0
        return result;
257
0
    }
258
0
    else
259
0
        MVM_exception_throw_adhoc(tc, "Cannot lock this kind of handle");
260
0
}
261
262
0
void MVM_io_unlock(MVMThreadContext *tc, MVMObject *oshandle) {
263
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "unlock");
264
0
    if (handle->body.ops->lockable) {
265
0
        MVMROOT(tc, handle, {
266
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
267
0
            handle->body.ops->lockable->unlock(tc, handle);
268
0
            release_mutex(tc, mutex);
269
0
        });
270
0
    }
271
0
    else
272
0
        MVM_exception_throw_adhoc(tc, "Cannot unlock this kind of handle");
273
0
}
274
275
288
void MVM_io_flush(MVMThreadContext *tc, MVMObject *oshandle, MVMint32 sync) {
276
288
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "flush");
277
288
    if (handle->body.ops->sync_writable) {
278
288
        MVMROOT(tc, handle, {
279
288
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
280
288
            handle->body.ops->sync_writable->flush(tc, handle, sync);
281
288
            release_mutex(tc, mutex);
282
288
        });
283
288
    }
284
288
    else
285
0
        MVM_exception_throw_adhoc(tc, "Cannot flush this kind of handle");
286
288
}
287
288
0
void MVM_io_truncate(MVMThreadContext *tc, MVMObject *oshandle, MVMint64 offset) {
289
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "truncate");
290
0
    if (handle->body.ops->sync_writable) {
291
0
        MVMROOT(tc, handle, {
292
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
293
0
            handle->body.ops->sync_writable->truncate(tc, handle, offset);
294
0
            release_mutex(tc, mutex);
295
0
        });
296
0
    }
297
0
    else
298
0
        MVM_exception_throw_adhoc(tc, "Cannot truncate this kind of handle");
299
0
}
300
301
0
void MVM_io_connect(MVMThreadContext *tc, MVMObject *oshandle, MVMString *host, MVMint64 port) {
302
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "connect");
303
0
    if (handle->body.ops->sockety) {
304
0
        MVMROOT2(tc, host, handle, {
305
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
306
0
            handle->body.ops->sockety->connect(tc, handle, host, port);
307
0
            release_mutex(tc, mutex);
308
0
        });
309
0
    }
310
0
    else
311
0
        MVM_exception_throw_adhoc(tc, "Cannot connect this kind of handle");
312
0
}
313
314
0
void MVM_io_bind(MVMThreadContext *tc, MVMObject *oshandle, MVMString *host, MVMint64 port, MVMint32 backlog) {
315
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "bind");
316
0
    if (handle->body.ops->sockety) {
317
0
        MVMROOT2(tc, host, handle, {
318
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
319
0
            handle->body.ops->sockety->bind(tc, handle, host, port, backlog);
320
0
            release_mutex(tc, mutex);
321
0
        });
322
0
    }
323
0
    else
324
0
        MVM_exception_throw_adhoc(tc, "Cannot bind this kind of handle");
325
0
}
326
327
0
MVMint64 MVM_io_getport(MVMThreadContext *tc, MVMObject *oshandle) {
328
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "getport");
329
0
    if (handle->body.ops->sockety) {
330
0
        MVMint64 result;
331
0
        MVMROOT(tc, handle, {
332
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
333
0
            result = handle->body.ops->sockety->getport(tc, handle);
334
0
            release_mutex(tc, mutex);
335
0
        });
336
0
        return result;
337
0
    }
338
0
    else
339
0
        MVM_exception_throw_adhoc(tc, "Cannot getport for this kind of handle");
340
0
}
341
342
0
MVMObject * MVM_io_accept(MVMThreadContext *tc, MVMObject *oshandle) {
343
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "accept");
344
0
    if (handle->body.ops->sockety) {
345
0
        MVMObject *result;
346
0
        MVMROOT(tc, handle, {
347
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
348
0
            result = handle->body.ops->sockety->accept(tc, handle);
349
0
            release_mutex(tc, mutex);
350
0
        });
351
0
        return result;
352
0
    }
353
0
    else
354
0
        MVM_exception_throw_adhoc(tc, "Cannot accept this kind of handle");
355
0
}
356
357
0
void MVM_io_set_buffer_size(MVMThreadContext *tc, MVMObject *oshandle, MVMint64 size) {
358
0
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "set buffer size");
359
0
    if (handle->body.ops->set_buffer_size) {
360
0
        MVMROOT(tc, handle, {
361
0
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
362
0
            handle->body.ops->set_buffer_size(tc, handle, size);
363
0
            release_mutex(tc, mutex);
364
0
        });
365
0
    }
366
0
    else
367
0
        MVM_exception_throw_adhoc(tc, "Cannot set buffer size on this kind of handle");
368
0
}
369
370
14
MVMObject * MVM_io_get_async_task_handle(MVMThreadContext *tc, MVMObject *oshandle) {
371
14
    MVMOSHandle *handle = verify_is_handle(tc, oshandle, "get async task handle");
372
14
    if (handle->body.ops->get_async_task_handle) {
373
14
        MVMObject *ath;
374
14
        MVMROOT(tc, handle, {
375
14
            uv_mutex_t *mutex = acquire_mutex(tc, handle);
376
14
            ath = handle->body.ops->get_async_task_handle(tc, handle);
377
14
            release_mutex(tc, mutex);
378
14
        });
379
14
        return ath;
380
14
    }
381
14
    else
382
0
        MVM_exception_throw_adhoc(tc, "Cannot get async task handle from this kind of handle");
383
14
}
384
385
144
void MVM_io_flush_standard_handles(MVMThreadContext *tc) {
386
144
    MVM_io_flush(tc, tc->instance->stdout_handle, 0);
387
144
    MVM_io_flush(tc, tc->instance->stderr_handle, 0);
388
144
}