static MVMObject * socket_accept(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; Socket s; unsigned int interval_id = MVM_telemetry_interval_start(tc, "syncsocket accept"); do { MVM_gc_mark_thread_blocked(tc); s = accept(data->handle, NULL, NULL); MVM_gc_mark_thread_unblocked(tc); } while(s == -1 && errno == EINTR); if (MVM_IS_SOCKET_ERROR(s)) { MVM_telemetry_interval_stop(tc, interval_id, "syncsocket accept failed"); throw_error(tc, s, "accept socket connection"); } else { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOSyncSocketData * const data = MVM_calloc(1, sizeof(MVMIOSyncSocketData)); data->handle = s; result->body.ops = &op_table; result->body.data = data; MVM_telemetry_interval_stop(tc, interval_id, "syncsocket accept succeeded"); return (MVMObject *)result; } }
/* Establishes a connection. */ static void socket_connect(MVMThreadContext *tc, MVMOSHandle *h, MVMString *host, MVMint64 port) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; unsigned int interval_id; interval_id = MVM_telemetry_interval_start(tc, "syncsocket connect"); if (!data->handle) { struct sockaddr *dest = MVM_io_resolve_host_name(tc, host, port); int r; Socket s = socket(dest->sa_family , SOCK_STREAM , 0); if (MVM_IS_SOCKET_ERROR(s)) { MVM_free(dest); MVM_telemetry_interval_stop(tc, interval_id, "syncsocket connect"); throw_error(tc, s, "create socket"); } do { MVM_gc_mark_thread_blocked(tc); r = connect(s, dest, (socklen_t)get_struct_size_for_family(dest->sa_family)); MVM_gc_mark_thread_unblocked(tc); } while(r == -1 && errno == EINTR); MVM_free(dest); if (MVM_IS_SOCKET_ERROR(r)) { MVM_telemetry_interval_stop(tc, interval_id, "syncsocket connect"); throw_error(tc, s, "connect socket"); } data->handle = s; } else { MVM_telemetry_interval_stop(tc, interval_id, "syncsocket didn't connect"); MVM_exception_throw_adhoc(tc, "Socket is already bound or connected"); } }
/* Writes the specified bytes to the stream. */ MVMint64 socket_write_bytes(MVMThreadContext *tc, MVMOSHandle *h, char *buf, MVMint64 bytes) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; MVMint64 sent = 0; unsigned int interval_id; interval_id = MVM_telemetry_interval_start(tc, "syncsocket.write_bytes"); MVM_gc_mark_thread_blocked(tc); while (bytes > 0) { int r; do { r = send(data->handle, buf, (int)bytes, 0); } while(r == -1 && errno == EINTR); if (MVM_IS_SOCKET_ERROR(r)) { MVM_gc_mark_thread_unblocked(tc); MVM_telemetry_interval_stop(tc, interval_id, "syncsocket.write_bytes"); throw_error(tc, r, "send data to socket"); } sent += r; buf += r; bytes -= r; } MVM_gc_mark_thread_unblocked(tc); MVM_telemetry_interval_annotate(bytes, interval_id, "written this many bytes"); MVM_telemetry_interval_stop(tc, interval_id, "syncsocket.write_bytes"); return bytes; }
static void run_gc(MVMThreadContext *tc, MVMuint8 what_to_do) { MVMuint8 gen; MVMuint32 i, n; unsigned int interval_id; #if MVM_GC_DEBUG if (tc->in_spesh) MVM_panic(1, "Must not GC when in the specializer/JIT\n"); #endif /* Decide nursery or full collection. */ gen = tc->instance->gc_full_collect ? MVMGCGenerations_Both : MVMGCGenerations_Nursery; if (tc->instance->gc_full_collect) { interval_id = MVM_telemetry_interval_start(tc, "start full collection"); } else { interval_id = MVM_telemetry_interval_start(tc, "start minor collection"); } /* Do GC work for ourselves and any work threads. */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; tc->gc_work[i].limit = other->nursery_alloc; GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : starting collection for thread %d\n", other->thread_id); other->gc_promoted_bytes = 0; MVM_gc_collect(other, (other == tc ? what_to_do : MVMGCWhatToDo_NoInstance), gen); } /* Wait for everybody to agree we're done. */ finish_gc(tc, gen, what_to_do == MVMGCWhatToDo_All); MVM_telemetry_interval_stop(tc, interval_id, "finished run_gc"); }
/* Reads the specified number of bytes into a the supplied buffer, returning * the number actually read. */ static MVMint64 read_bytes(MVMThreadContext *tc, MVMOSHandle *h, char **buf_out, MVMint64 bytes) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; char *buf = MVM_malloc(bytes); unsigned int interval_id = MVM_telemetry_interval_start(tc, "syncfile.read_to_buffer"); MVMint32 bytes_read; #ifdef _WIN32 /* Can only perform relatively small reads from a Windows console; * trying to do larger ones gives back ENOMEM, most likely due to * limitations of the Windows console subsystem. */ if (bytes > 16387 && _isatty(data->fd)) bytes = 16387; #endif flush_output_buffer(tc, data); MVM_gc_mark_thread_blocked(tc); if ((bytes_read = read(data->fd, buf, bytes)) == -1) { int save_errno = errno; MVM_free(buf); MVM_gc_mark_thread_unblocked(tc); MVM_exception_throw_adhoc(tc, "Reading from filehandle failed: %s", strerror(save_errno)); } *buf_out = buf; MVM_gc_mark_thread_unblocked(tc); MVM_telemetry_interval_annotate(bytes_read, interval_id, "read this many bytes"); MVM_telemetry_interval_stop(tc, interval_id, "syncfile.read_to_buffer"); data->byte_position += bytes_read; if (bytes_read == 0 && bytes != 0) data->eof_reported = 1; return bytes_read; }
/* Read a packet worth of data into the last packet buffer. */ static void read_one_packet(MVMThreadContext *tc, MVMIOSyncSocketData *data) { unsigned int interval_id = MVM_telemetry_interval_start(tc, "syncsocket.read_one_packet"); int r; data->last_packet = MVM_malloc(PACKET_SIZE); do { MVM_gc_mark_thread_blocked(tc); r = recv(data->handle, data->last_packet, PACKET_SIZE, 0); MVM_gc_mark_thread_unblocked(tc); } while(r == -1 && errno == EINTR); MVM_telemetry_interval_stop(tc, interval_id, "syncsocket.read_one_packet"); if (MVM_IS_SOCKET_ERROR(r) || r == 0) { MVM_free(data->last_packet); data->last_packet = NULL; if (r != 0) throw_error(tc, r, "receive data from socket"); } else { data->last_packet_start = 0; data->last_packet_end = r; } }
static void callback_handler(ffi_cif *cif, void *cb_result, void **cb_args, void *cb_data) { CallbackInvokeData cid; MVMint32 num_roots, i; MVMRegister res; MVMRegister *args; MVMNativeCallback *data = (MVMNativeCallback *)cb_data; void **values = MVM_malloc(sizeof(void *) * (data->cs->arg_count ? data->cs->arg_count : 1)); unsigned int interval_id; /* Locate the MoarVM thread this callback is being run on. */ MVMThreadContext *tc = MVM_nativecall_find_thread_context(data->instance); /* Unblock GC if needed, so this thread can do work. */ MVMint32 was_blocked = MVM_gc_is_thread_blocked(tc); if (was_blocked) MVM_gc_mark_thread_unblocked(tc); interval_id = MVM_telemetry_interval_start(tc, "nativecall callback handler"); /* Build a callsite and arguments buffer. */ args = MVM_malloc(data->num_types * sizeof(MVMRegister)); num_roots = 0; for (i = 1; i < data->num_types; i++) { MVMObject *type = data->types[i]; MVMint16 typeinfo = data->typeinfos[i]; switch (typeinfo & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: args[i - 1].i64 = *(signed char *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_SHORT: args[i - 1].i64 = *(signed short *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_INT: args[i - 1].i64 = *(signed int *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_LONG: args[i - 1].i64 = *(signed long *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_LONGLONG: args[i - 1].i64 = *(signed long long *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_FLOAT: args[i - 1].n64 = *(float *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_DOUBLE: args[i - 1].n64 = *(double *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_ASCIISTR: case MVM_NATIVECALL_ARG_UTF8STR: case MVM_NATIVECALL_ARG_UTF16STR: args[i - 1].o = MVM_nativecall_make_str(tc, type, typeinfo, *(char **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CSTRUCT: args[i - 1].o = MVM_nativecall_make_cstruct(tc, type, *(void **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CPPSTRUCT: args[i - 1].o = MVM_nativecall_make_cppstruct(tc, type, *(void **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CPOINTER: args[i - 1].o = MVM_nativecall_make_cpointer(tc, type, *(void **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CARRAY: args[i - 1].o = MVM_nativecall_make_carray(tc, type, *(void **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CUNION: args[i - 1].o = MVM_nativecall_make_cunion(tc, type, *(void **)cb_args[i - 1]); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CALLBACK: /* TODO: A callback -return- value means that we have a C method * that needs to be wrapped similarly to a is native(...) Perl 6 * sub. */ /* XXX do something with the function pointer: *(void **)cb_args[i - 1] */ args[i - 1].o = type; MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; case MVM_NATIVECALL_ARG_UCHAR: args[i - 1].i64 = *(unsigned char *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_USHORT: args[i - 1].i64 = *(unsigned short *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_UINT: args[i - 1].i64 = *(unsigned int *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_ULONG: args[i - 1].i64 = *(unsigned long *)cb_args[i - 1]; break; case MVM_NATIVECALL_ARG_ULONGLONG: args[i - 1].i64 = *(unsigned long long *)cb_args[i - 1]; break; default: MVM_telemetry_interval_stop(tc, interval_id, "nativecall callback handler failed"); MVM_exception_throw_adhoc(tc, "Internal error: unhandled libffi callback argument type"); } } /* Call into a nested interpreter (since we already are in one). Need to * save a bunch of state around each side of this. */ cid.invokee = data->target; cid.args = args; cid.cs = data->cs; { MVMuint8 **backup_interp_cur_op = tc->interp_cur_op; MVMuint8 **backup_interp_bytecode_start = tc->interp_bytecode_start; MVMRegister **backup_interp_reg_base = tc->interp_reg_base; MVMCompUnit **backup_interp_cu = tc->interp_cu; MVMFrame *backup_cur_frame = MVM_frame_force_to_heap(tc, tc->cur_frame); MVMFrame *backup_thread_entry_frame = tc->thread_entry_frame; void **backup_jit_return_address = tc->jit_return_address; tc->jit_return_address = NULL; MVMROOT2(tc, backup_cur_frame, backup_thread_entry_frame, { MVMuint32 backup_mark = MVM_gc_root_temp_mark(tc); jmp_buf backup_interp_jump; memcpy(backup_interp_jump, tc->interp_jump, sizeof(jmp_buf)); tc->cur_frame->return_value = &res; tc->cur_frame->return_type = MVM_RETURN_OBJ; MVM_interp_run(tc, callback_invoke, &cid); tc->interp_cur_op = backup_interp_cur_op; tc->interp_bytecode_start = backup_interp_bytecode_start; tc->interp_reg_base = backup_interp_reg_base; tc->interp_cu = backup_interp_cu; tc->cur_frame = backup_cur_frame; tc->current_frame_nr = backup_cur_frame->sequence_nr; tc->thread_entry_frame = backup_thread_entry_frame; tc->jit_return_address = backup_jit_return_address; memcpy(tc->interp_jump, backup_interp_jump, sizeof(jmp_buf)); MVM_gc_root_temp_mark_reset(tc, backup_mark); }); }