From: Brendan Hansen Date: Fri, 4 Nov 2022 03:38:34 +0000 (-0500) Subject: added alloc/atomic; network bugfixes; iter bugfix X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=dee267ba10527f831b00c01e46863baae5c9767e;p=onyx.git added alloc/atomic; network bugfixes; iter bugfix --- diff --git a/core/alloc/atomic.onyx b/core/alloc/atomic.onyx new file mode 100644 index 00000000..3272d3fa --- /dev/null +++ b/core/alloc/atomic.onyx @@ -0,0 +1,31 @@ +package core.alloc.atomic + +use core {sync} + +AtomicAllocator :: struct { + a: Allocator; + m: sync.Mutex; +} + +make :: (a: Allocator) -> AtomicAllocator { + atomic: AtomicAllocator = .{ a = a }; + + sync.mutex_init(^atomic.m); + + return atomic; +} + +make_allocator :: (atomic: ^AtomicAllocator) => + Allocator.{ atomic, atomic_alloc }; + +#overload +core.alloc.as_allocator :: make_allocator + + +#local +atomic_alloc :: (atomic: ^AtomicAllocator, aa: AllocationAction, size: u32, align: u32, oldptr: rawptr) -> rawptr { + sync.scoped_mutex(^atomic.m); + return atomic.a.func(atomic.a.data, aa, size, align, oldptr); +} + + diff --git a/core/container/iter.onyx b/core/container/iter.onyx index dc6a463c..b9684fbd 100644 --- a/core/container/iter.onyx +++ b/core/container/iter.onyx @@ -33,7 +33,7 @@ ImplicitIterator :: interface (t: $T) { #overload #precedence 10000 as_iterator :: (x: ^$T/ImplicitIterator) => { x->iter_open(); - return generator(x, T.iter_next, T.iter_close); + return generator_no_copy(x, T.iter_next, T.iter_close); } @@ -728,6 +728,17 @@ generator :: (ctx: ^$Ctx, gen: (^Ctx) -> ($T, bool), close: (^Ctx) -> void) -> I }; } +generator_no_copy :: #match #local {} + +#overload +generator_no_copy :: (ctx: ^$Ctx, gen: (^Ctx) -> ($T, bool)) => + Iterator(T).{ ctx, gen } + +#overload +generator_no_copy :: (ctx: ^$Ctx, gen: (^Ctx) -> ($T, bool), close: (^Ctx) -> void) => + Iterator(T).{ ctx, gen, close } + + #if runtime.Multi_Threading_Enabled { #local sync :: core.sync diff --git a/core/net/net.onyx b/core/net/net.onyx index 7a84b0f0..c27f0175 100644 --- a/core/net/net.onyx +++ b/core/net/net.onyx @@ -21,6 +21,7 @@ Socket :: struct { listen :: socket_listen accept :: socket_accept connect :: socket_connect + shutdown :: socket_shutdown send :: socket_send sendto :: socket_sendto sendall :: socket_sendall @@ -48,8 +49,15 @@ SocketType :: enum { } SocketSetting :: enum { - NonBlocking :: 0x01; - Broadcast :: 0x02; + NonBlocking :: 0x01; + Broadcast :: 0x02; + ReuseAddress :: 0x03; +} + +SocketShutdown :: enum { + Read :: 0; + Write :: 1; + ReadWrite :: 2; } #local UNIX_SOCKET_PATH_LEN :: 256 @@ -133,6 +141,10 @@ socket_listen :: (s: ^Socket, backlog := 32) { __net_listen(s.handle, backlog); } +socket_shutdown :: (s: ^Socket, how: SocketShutdown) { + __net_shutdown(s.handle, cast(u32) how); +} + socket_accept :: (s: ^Socket) -> (Socket, Socket_Address) { new_socket: Socket; new_addr: Socket_Address; @@ -271,6 +283,7 @@ network_to_host :: #match {} #package __net_accept :: (handle: Socket.Handle, out_address: ^Socket_Address) -> Socket.Handle --- #package __net_connect_unix :: (handle: Socket.Handle, path: str) -> SocketError --- #package __net_connect_ipv4 :: (handle: Socket.Handle, host: str, port: u16) -> SocketError --- + #package __net_shutdown :: (handle: Socket.Handle, how: u32) -> void --- #package __net_send :: (handle: Socket.Handle, data: [] u8) -> i32 --- #package __net_sendto :: (handle: Socket.Handle, data: [] u8, addr: ^Socket_Address) -> i32 --- #package __net_recv :: (handle: Socket.Handle, data: [] u8, async_would_block: ^bool) -> i32 --- diff --git a/core/net/tcp.onyx b/core/net/tcp.onyx index 8885b5a8..65bad059 100644 --- a/core/net/tcp.onyx +++ b/core/net/tcp.onyx @@ -14,6 +14,8 @@ TCP_Connection :: struct { event_allocator: Allocator; events: [..] TCP_Event; event_cursor := 0; + + event_mutex: sync.Mutex; } TCP_Event :: struct { @@ -57,32 +59,32 @@ TCP_Event :: struct { } } -tcp_get_events :: (use conn: ^TCP_Connection) => { - conn.event_cursor = 0; - - return iter.generator( - conn, +// Iterator implementation for TCP_Connection +#inject TCP_Connection { + iter_open :: (use conn: ^TCP_Connection) { + conn.event_cursor = 0; + } - (use conn: ^TCP_Connection) -> (TCP_Event, bool) { - if event_cursor == events.count do return .{}, false; + iter_next :: (use conn: ^TCP_Connection) -> (TCP_Event, bool) { + if event_cursor == events.count do return .{}, false; - defer event_cursor += 1; - return events[event_cursor], true; - }, + defer event_cursor += 1; + return events[event_cursor], true; + } - (use conn: ^TCP_Connection) { - for events { - switch it.kind { - case .Data { - raw_free(event_allocator, (cast(^TCP_Event.Data) it.data).contents.data); - } + iter_close :: (use conn: ^TCP_Connection) { + for events { + switch it.kind { + case .Data { + raw_free(event_allocator, (cast(^TCP_Event.Data) it.data).contents.data); } - - raw_free(event_allocator, it.data); } - array.clear(^events); - }); + raw_free(event_allocator, it.data); + } + + array.clear(^events); + } } @@ -106,8 +108,8 @@ TCP_Server :: struct { emit_data_events := true; - get_events :: tcp_get_events listen :: tcp_server_listen + stop :: tcp_server_stop pulse :: tcp_server_pulse send :: tcp_server_send broadcast :: tcp_server_broadcast @@ -151,17 +153,22 @@ tcp_server_make :: (max_clients := 32, allocator := context.allocator) -> ^TCP_S server.clients = make([] ^TCP_Server.Client, max_clients, allocator=allocator); array.fill(server.clients, null); + sync.mutex_init(^server.event_mutex); + return server; } #local tcp_server_listener :: (use server: ^TCP_Server) { while server.alive { if server.client_count == server.clients.count { - os.sleep(100); + os.sleep(1); continue; } client_socket, client_addr := socket->accept(); + if !client_socket.vtable { + continue; + } client := new(TCP_Server.Client, allocator=client_allocator); client.state = .Alive; @@ -174,7 +181,10 @@ tcp_server_make :: (max_clients := 32, allocator := context.allocator) -> ^TCP_S conn_event := new(TCP_Event.Connection, allocator=server.event_allocator); conn_event.address = ^client.address; conn_event.client = client; - server.events << .{ .Connection, conn_event }; // @Threading // This operation should be protected by a mutex? + + sync.critical_section(^server.event_mutex) { + server.events << .{ .Connection, conn_event }; // @Threading + } } } @@ -188,10 +198,24 @@ tcp_server_listen :: (use server: ^TCP_Server, port: u16) -> bool { return true; } +tcp_server_stop :: (use server: ^TCP_Server) { + server.alive = false; + + for clients { + if !it do continue; + + if it.state == .Alive do server->kill_client(it); + } + + server.socket->close(); + thread.kill(^listener_thread); +} + tcp_server_pulse :: (use server: ^TCP_Server) -> bool { for^ clients { client := *it; - if client == null do continue; + if !client do continue; + switch client.state { case .Being_Killed { // Before, there was not a "being killed" state and the code made @@ -247,14 +271,18 @@ tcp_server_pulse :: (use server: ^TCP_Server) -> bool { data_event.client = it; data_event.address = ^it.address; data_event.contents = memory.copy_slice(msg_buffer[0 .. bytes_read], allocator=server.event_allocator); - server.events << .{ .Data, data_event }; // @Threading // See comment above. + sync.critical_section(^server.event_mutex) { + server.events << .{ .Data, data_event }; // @Threading // See comment above. + } } elseif !it.recv_ready_event_present { it.recv_ready_event_present = true; ready_event := new(TCP_Event.Ready, allocator=server.event_allocator); ready_event.client = it; ready_event.address = ^it.address; - server.events << .{ .Ready, ready_event }; // @Threading // See comment above. + sync.critical_section(^server.event_mutex) { + server.events << .{ .Ready, ready_event }; // @Threading // See comment above. + } } } @@ -264,7 +292,9 @@ tcp_server_pulse :: (use server: ^TCP_Server) -> bool { disconnect_event := new(TCP_Event.Disconnection, allocator=server.event_allocator); disconnect_event.client = it; disconnect_event.address = ^it.address; - server.events << .{ .Disconnection, disconnect_event }; // @Threading // See comment above. + sync.critical_section(^server.event_mutex) { + server.events << .{ .Disconnection, disconnect_event }; // @Threading // See comment above. + } } } @@ -298,12 +328,15 @@ tcp_server_broadcast :: (use server: ^TCP_Server, data: [] u8, except: ^TCP_Serv tcp_server_handle_events :: macro (server: ^TCP_Server, handler: Code) { while server->pulse() { - for server->get_events() do switch it.kind do #unquote handler; + for iter.as_iterator(^server.connection) { + switch it.kind do #unquote handler; + } } } tcp_server_kill_client :: (use server: ^TCP_Server, client: ^TCP_Server.Client) { client.state = .Being_Killed; + client.socket->shutdown(.ReadWrite); client.socket->close(); client.socket.vtable = null; } @@ -316,8 +349,6 @@ tcp_server_kill_client :: (use server: ^TCP_Server, client: ^TCP_Server.Client) TCP_Client :: struct { use connection: TCP_Connection; - - get_events :: tcp_get_events } diff --git a/core/onyx/fault_handling.onyx b/core/onyx/fault_handling.onyx new file mode 100644 index 00000000..10e1454b --- /dev/null +++ b/core/onyx/fault_handling.onyx @@ -0,0 +1,33 @@ +package core.os + +Fault_Handler :: struct { + handle: (rawptr) -> void; + ctx: rawptr; +} + +register_fault_handler :: (ctx: rawptr, handle: (rawptr) -> void) { + fault_handlers << .{ handle, ctx }; + + if !global_fault_handle_registered { + assert(__register_cleanup(#export_name global_fault_handler), "Failed to register global fault handler"); + global_fault_handle_registered = true; + } +} + +#local { + #foreign "onyx_runtime" { + __register_cleanup :: (name: str) -> bool --- + } + + global_fault_handler :: () { + for fault_handlers { + it.handle(it.ctx); + } + } + + fault_handlers: [..] Fault_Handler + global_fault_handle_registered := false; +} + + + diff --git a/core/std.onyx b/core/std.onyx index 669887c5..4cdfa5fe 100644 --- a/core/std.onyx +++ b/core/std.onyx @@ -65,6 +65,7 @@ package core #load "./onyx/fs" #load "./onyx/cptr" #load "./onyx/cbindgen" + #load "./onyx/fault_handling" } #if runtime.runtime == .Wasi { #load "./wasi/wasi" diff --git a/interpreter/build.sh b/interpreter/build.sh index adbb53ce..778c7307 100755 --- a/interpreter/build.sh +++ b/interpreter/build.sh @@ -2,7 +2,7 @@ . ../settings.sh -# FLAGS="-g3" +# FLAGS="-g3 -DOVM_DEBUG=1" # FLAGS="-g3 -DOVM_VERBOSE=1" FLAGS="-Ofast" LIBS="-pthread" diff --git a/interpreter/src/debug/debug_thread.c b/interpreter/src/debug/debug_thread.c index d8e2dcef..b87843b9 100644 --- a/interpreter/src/debug/debug_thread.c +++ b/interpreter/src/debug/debug_thread.c @@ -202,6 +202,8 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { break; brk_send_error: + printf("[WARN ] Failed to set breakpoint at %s:%d (%x)\n", filename, line, instr); + send_response_header(debug, msg_id); send_bool(debug, false); send_int(debug, -1); diff --git a/interpreter/src/vm/vm.c b/interpreter/src/vm/vm.c index 46f2f9bd..adb2247d 100644 --- a/interpreter/src/vm/vm.c +++ b/interpreter/src/vm/vm.c @@ -1246,8 +1246,6 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t #undef CMPXCHG case OVMI_BREAK: - printf("onyx: exiting early due to reaching an unreachable instruction.\n"); - if (state->debug) { state->debug->state = debug_state_pausing; state->debug->pause_reason = debug_pause_exception; @@ -1256,6 +1254,8 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t sem_wait(&state->debug->wait_semaphore); } + printf("onyx: exiting early due to reaching an unreachable instruction.\n"); + return ((ovm_value_t) {0}); default: diff --git a/runtime/onyx_runtime.c b/runtime/onyx_runtime.c index c8bbacaf..f7eebfca 100644 --- a/runtime/onyx_runtime.c +++ b/runtime/onyx_runtime.c @@ -70,6 +70,7 @@ ONYX_LIBRARY { ONYX_FUNC(__exit) ONYX_FUNC(__sleep) ONYX_FUNC(__time) + ONYX_FUNC(__register_cleanup) ONYX_FUNC(__time_localtime) ONYX_FUNC(__time_gmtime) @@ -83,6 +84,7 @@ ONYX_LIBRARY { ONYX_FUNC(__net_accept) ONYX_FUNC(__net_connect_unix) ONYX_FUNC(__net_connect_ipv4) + ONYX_FUNC(__net_shutdown) ONYX_FUNC(__net_send) ONYX_FUNC(__net_sendto) ONYX_FUNC(__net_recv) diff --git a/runtime/src/ort_net.h b/runtime/src/ort_net.h index 9b2e4c5d..c021b1c4 100644 --- a/runtime/src/ort_net.h +++ b/runtime/src/ort_net.h @@ -90,6 +90,12 @@ ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) { setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) ¶ms->data[2].of.i32, sizeof(int)); break; } + + case 3: { // :EnumDependent Reuse-Address + int s = params->data[0].of.i32; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) ¶ms->data[2].of.i32, sizeof(int)); + break; + } } #endif @@ -234,6 +240,16 @@ ONYX_DEF(__net_connect_ipv4, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32 #endif } +ONYX_DEF(__net_shutdown, (WASM_I32, WASM_I32), ()) { + #ifdef _BH_LINUX + shutdown(params->data[0].of.i32, params->data[1].of.i32); + return NULL; + #endif + + #ifdef _BH_WINDOWS + #endif +} + ONYX_DEF(__net_send, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { #ifdef _BH_LINUX // TODO: The flags at the end should be controllable. diff --git a/runtime/src/ort_os.h b/runtime/src/ort_os.h index 05fbf652..860784a0 100644 --- a/runtime/src/ort_os.h +++ b/runtime/src/ort_os.h @@ -53,3 +53,60 @@ ONYX_DEF(__time, (), (WASM_I64)) { return NULL; } + + + + + +#ifdef _BH_LINUX +static wasm_func_t *wasm_cleanup_func; + +static void unix_signal_handler(int signo, siginfo_t *info, void *context) { + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + runtime->wasm_func_call(wasm_cleanup_func, &args, &results); +} +#endif + +ONYX_DEF(__register_cleanup, (WASM_I32, WASM_I32), (WASM_I32)) { + #ifdef _BH_LINUX + + int len = (127 < params->data[1].of.i32 ? 127 : params->data[1].of.i32); + char name[128]; + memcpy(name, ONYX_PTR(params->data[0].of.i32), len); + name[len] = '\0'; + + wasm_extern_t *signal_extern = runtime->wasm_extern_lookup_by_name( + runtime->wasm_module, + runtime->wasm_instance, + name); + + wasm_cleanup_func = runtime->wasm_extern_as_func(signal_extern); + if (!wasm_cleanup_func) { + results->data[0] = WASM_I32_VAL(0); + return NULL; + } + + // This is probably not the most complete list, but seems + // sufficient for now. + if ( + (signal(SIGSEGV, &unix_signal_handler) == SIG_ERR) || + (signal(SIGQUIT, &unix_signal_handler) == SIG_ERR) || + (signal(SIGINT, &unix_signal_handler) == SIG_ERR) || + (signal(SIGPIPE, &unix_signal_handler) == SIG_ERR) || + (signal(SIGTERM, &unix_signal_handler) == SIG_ERR) || + (signal(SIGHUP, &unix_signal_handler) == SIG_ERR) || + (signal(SIGFPE, &unix_signal_handler) == SIG_ERR)) + { + results->data[0] = WASM_I32_VAL(0); + return NULL; + } + + results->data[0] = WASM_I32_VAL(1); + return NULL; + #endif + + #ifdef _BH_WINDOWS + #endif +} + diff --git a/runtime/src/ort_threads.h b/runtime/src/ort_threads.h index 75cf4710..0893131f 100644 --- a/runtime/src/ort_threads.h +++ b/runtime/src/ort_threads.h @@ -105,7 +105,8 @@ ONYX_DEF(__kill_thread, (WASM_I32), (WASM_I32)) { #ifdef _BH_LINUX // This leads to some weirdness and bugs... // - pthread_kill(thread->thread, SIGKILL); + // pthread_kill(thread->thread, SIGKILL); + pthread_cancel(thread->thread); #endif #ifdef _BH_WINDOWS diff --git a/shared/lib/linux_x86_64/lib/libovmwasm.so b/shared/lib/linux_x86_64/lib/libovmwasm.so index 6319498f..7d1249f7 100755 Binary files a/shared/lib/linux_x86_64/lib/libovmwasm.so and b/shared/lib/linux_x86_64/lib/libovmwasm.so differ