/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename); char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); uv_fs_t req; uv_file fd; /* Resolve mode description to flags. */ int flag; if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fmode, NULL }; MVM_free(fname); MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode: %s", fmode); } MVM_free(fmode); /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { char *waste[] = { fname, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, uv_strerror(req.result)); } /* Set up handle. */ data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
MVMObject * MVM_io_socket_create(MVMThreadContext *tc, MVMint64 listen) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOSyncSocketData * const data = MVM_calloc(1, sizeof(MVMIOSyncSocketData)); data->ss.handle = NULL; data->ss.encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->ss.sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
/* Creates a sync pipe handle. */ MVMObject * MVM_io_syncpipe(MVMThreadContext *tc) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOSyncPipeData * const data = MVM_calloc(1, sizeof(MVMIOSyncPipeData)); uv_pipe_t *handle = MVM_malloc(sizeof(uv_pipe_t)); uv_pipe_init(tc->loop, handle, 0); data->ss.handle = (uv_stream_t *)handle; data->ss.encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->ss.sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
static MVMObject * socket_accept(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; while (!data->accept_server) { if (tc->loop != data->ss.handle->loop) { MVM_exception_throw_adhoc(tc, "Tried to accept() on a socket from outside its originating thread"); } uv_ref((uv_handle_t *)data->ss.handle); MVM_gc_mark_thread_blocked(tc); uv_run(tc->loop, UV_RUN_DEFAULT); MVM_gc_mark_thread_unblocked(tc); } /* Check the accept worked out. */ if (data->accept_status < 0) { MVM_exception_throw_adhoc(tc, "Failed to listen: unknown error"); } else { uv_tcp_t *client = MVM_malloc(sizeof(uv_tcp_t)); uv_stream_t *server = data->accept_server; int r; uv_tcp_init(tc->loop, client); data->accept_server = NULL; if ((r = uv_accept(server, (uv_stream_t *)client)) == 0) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOSyncSocketData * const data = MVM_calloc(1, sizeof(MVMIOSyncSocketData)); data->ss.handle = (uv_stream_t *)client; data->ss.encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->ss.sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } else { uv_close((uv_handle_t*)client, NULL); MVM_free(client); MVM_exception_throw_adhoc(tc, "Failed to accept: %s", uv_strerror(r)); } } }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename); uv_fs_t req; uv_file fd; int flag; /* Resolve mode description to flags. */ { char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fname, fmode, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode for file %s: %s", fname, fmode); } MVM_free(fmode); } /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { char *waste[] = { fname, NULL }; const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err); } uv_fs_req_cleanup(&req); /* Check that we didn't open a directory by accident. If fstat fails, just move on: Most of the documented error cases should already have triggered when opening the file, and we can't do anything about the others; a failure also does not necessarily imply that the file descriptor cannot be used for reading/writing. */ if (uv_fs_fstat(tc->loop, &req, fd, NULL) == 0 && (req.statbuf.st_mode & S_IFMT) == S_IFDIR) { char *waste[] = { fname, NULL }; uv_fs_req_cleanup(&req); if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) { const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s", fname, err); } uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname); } uv_fs_req_cleanup(&req); /* Set up handle. */ { MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } }