added alloc/atomic; network bugfixes; iter bugfix
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Nov 2022 03:38:34 +0000 (22:38 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Nov 2022 03:38:34 +0000 (22:38 -0500)
14 files changed:
core/alloc/atomic.onyx [new file with mode: 0644]
core/container/iter.onyx
core/net/net.onyx
core/net/tcp.onyx
core/onyx/fault_handling.onyx [new file with mode: 0644]
core/std.onyx
interpreter/build.sh
interpreter/src/debug/debug_thread.c
interpreter/src/vm/vm.c
runtime/onyx_runtime.c
runtime/src/ort_net.h
runtime/src/ort_os.h
runtime/src/ort_threads.h
shared/lib/linux_x86_64/lib/libovmwasm.so

diff --git a/core/alloc/atomic.onyx b/core/alloc/atomic.onyx
new file mode 100644 (file)
index 0000000..3272d3f
--- /dev/null
@@ -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);
+}
+
+
index dc6a463c5652682fd9a84c00f62937a15ea518f8..b9684fbd0dd26be899d155a89eabfa065b50c32c 100644 (file)
@@ -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
index 7a84b0f03cd156a752fcde3cb9c8f3080e644ad4..c27f01752126154aa059dd244a0f097dc3a9c03f 100644 (file)
@@ -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 ---
index 8885b5a8e07ad37b9d6fd66f25a30e574150a9fb..65bad059981fba36e3531ef76a66f91e8b6667e5 100644 (file)
@@ -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 (file)
index 0000000..10e1454
--- /dev/null
@@ -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;
+}
+
+
+
index 669887c57d99a0fc3075c9f7e4a262c1d7da54b3..4cdfa5fef447e34328c763b5071a1816acfcc447 100644 (file)
@@ -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"
index adbb53ce9f69b896941ab66bb6542d06cb9f73d9..778c730770566229a222eb1f5368d7249bbd1afe 100755 (executable)
@@ -2,7 +2,7 @@
 
 . ../settings.sh
 
-# FLAGS="-g3"
+# FLAGS="-g3 -DOVM_DEBUG=1"
 # FLAGS="-g3 -DOVM_VERBOSE=1"
 FLAGS="-Ofast"
 LIBS="-pthread"
index d8e2dcef482ca72c69ec6587a875055ee4e17065..b87843b9a629a89415ae3a9b4058b7a5fff70af7 100644 (file)
@@ -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);
index 46f2f9bdbc244045365c81192026248974e1b89e..adb2247d89556f704c3a9f5698eaf3544b3872b2 100644 (file)
@@ -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:
index c8bbacaff07bdea6fd873c06a5a92f15a722ca3b..f7eebfca46457ad9fee2e18decf460b447aaa017 100644 (file)
@@ -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)
index 9b2e4c5d478d7b076ac249bd241605f6c1daa64f..c021b1c48fe53a0905f9b275c4042f83f0a333f9 100644 (file)
@@ -90,6 +90,12 @@ ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) {
             setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &params->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 *) &params->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.
index 05fbf652d6730e917e070dff7ecd3bd5ae68e6bc..860784a070cc64dfe92e7a5e0115202795971406 100644 (file)
@@ -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
+}
+
index 75cf47107c682c8115b8fa562d9c62c444408cf3..0893131f541f4185aad9eaff9d235b13132fb9c7 100644 (file)
@@ -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
index 6319498f846a1ad98771deebf4a2847b5d969fa3..7d1249f7f18bd9cf784f01790378bfacf774d914 100755 (executable)
Binary files a/shared/lib/linux_x86_64/lib/libovmwasm.so and b/shared/lib/linux_x86_64/lib/libovmwasm.so differ