authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-21 21:43:11+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-26 20:00:57+02:00
log10bf58b2db0e340137228f706ee2e8a67b46a892
tree4bee037f76f15189cf25a819cddf08b5da27274b
parenta97dbdfa0b1246913ba90cd5c05ff633e9003cb9
signaturelock-open Commit is signed but in an unrecognized format.

store allocator & remove global assembly

We now store the original allocator that was used to allocate the memory required for the thread. This allocator can then be used in any cleanup functionality to ensure the memory is freed correctly. Secondly, we now use a function to set the stack pointer instead of generating a function using global assembly. This is a lot cleaner and more readable.

1 files changed, 26 insertions(+), 22 deletions(-)

lib/std/Thread.zig+26-22
...@@ -739,32 +739,24 @@ const PosixThreadImpl = struct {...@@ -739,32 +739,24 @@ const PosixThreadImpl = struct {
739};739};
740740
741const WasiThreadImpl = struct {741const WasiThreadImpl = struct {
742 comptime {
743 // Sets the stack pointer, which is needed after creating a new thread
744 // to ensure the stack of the main thread isn't being poluted.
745 asm (
746 \\ .text
747 \\ .export_name __set_stack_pointer, __set_stack_pointer
748 \\ .globaltype __stack_pointer, i32
749 \\ .hidden wasi_thread_start
750 \\ .globl wasi_thread_start
751 \\ .type __set_stack_pointer, @function
752 \\
753 \\ __set_stack_pointer:
754 \\ .functype __set_stack_pointer (i32) -> ()
755 \\ local.get 0 # The raw pointer which replaces the stack pointer
756 \\ global.set __stack_pointer
757 \\ end_function
758 );
759 }
760 thread: *WasiThread,742 thread: *WasiThread,
761743
762 pub const ThreadHandle = i32;744 pub const ThreadHandle = i32;
763 threadlocal var tls_thread_id: Id = 0;745 threadlocal var tls_thread_id: Id = 0;
764746
765 const WasiThread = struct {747 const WasiThread = struct {
748 /// Thread ID
766 tid: Atomic(i32) = Atomic(i32).init(0),749 tid: Atomic(i32) = Atomic(i32).init(0),
750 /// Contains all memory which was allocated to bootstrap this thread, including:
751 /// - Guard page
752 /// - Stack
753 /// - TLS segment
754 /// - `Instance`
755 /// All memory is freed upon call to `join`
767 memory: []u8,756 memory: []u8,
757 /// The allocator used to allocate the thread's memory,
758 /// which is also used during `join` to ensure clean-up.
759 allocator: std.mem.Allocator,
768 };760 };
769761
770 /// A meta-data structure used to bootstrap a thread762 /// A meta-data structure used to bootstrap a thread
...@@ -790,7 +782,7 @@ const WasiThreadImpl = struct {...@@ -790,7 +782,7 @@ const WasiThreadImpl = struct {
790 }782 }
791783
792 fn getHandle(self: Impl) ThreadHandle {784 fn getHandle(self: Impl) ThreadHandle {
793 return self.thread.tid;785 return self.thread.tid.load(.SeqCst);
794 }786 }
795787
796 fn detach(self: Impl) void {788 fn detach(self: Impl) void {
...@@ -813,7 +805,6 @@ const WasiThreadImpl = struct {...@@ -813,7 +805,6 @@ const WasiThreadImpl = struct {
813 }805 }
814 };806 };
815807
816 var guard_offset: usize = undefined;
817 var stack_offset: usize = undefined;808 var stack_offset: usize = undefined;
818 var tls_offset: usize = undefined;809 var tls_offset: usize = undefined;
819 var wrapper_offset: usize = undefined;810 var wrapper_offset: usize = undefined;
...@@ -824,8 +815,11 @@ const WasiThreadImpl = struct {...@@ -824,8 +815,11 @@ const WasiThreadImpl = struct {
824 // - The TLS segment815 // - The TLS segment
825 // - `Instance` - containing information about how to call the user's function.816 // - `Instance` - containing information about how to call the user's function.
826 const map_bytes = blk: {817 const map_bytes = blk: {
818 // start with atleast a single page, which is used as a guard to prevent
819 // other threads clobbering our new thread.
820 // Unfortunately, WebAssembly has no notion of read-only segments, so this
821 // is only a temporary measure until the entire page is "run over".
827 var bytes: usize = std.wasm.page_size;822 var bytes: usize = std.wasm.page_size;
828 guard_offset = bytes;
829823
830 bytes = std.mem.alignForward(usize, bytes, 16); // align stack to 16 bytes824 bytes = std.mem.alignForward(usize, bytes, 16); // align stack to 16 bytes
831 stack_offset = bytes;825 stack_offset = bytes;
...@@ -855,7 +849,7 @@ const WasiThreadImpl = struct {...@@ -855,7 +849,7 @@ const WasiThreadImpl = struct {
855849
856 const instance = @ptrCast(*Instance, @alignCast(@alignOf(Instance), &allocated_memory[instance_offset]));850 const instance = @ptrCast(*Instance, @alignCast(@alignOf(Instance), &allocated_memory[instance_offset]));
857 instance.* = .{851 instance.* = .{
858 .thread = .{ .memory = allocated_memory },852 .thread = .{ .memory = allocated_memory, .allocator = config.allocator.? },
859 .base = @ptrToInt(allocated_memory.ptr),853 .base = @ptrToInt(allocated_memory.ptr),
860 .tls_base = tls_offset,854 .tls_base = tls_offset,
861 .stack_pointer = stack_offset,855 .stack_pointer = stack_offset,
...@@ -923,6 +917,16 @@ const WasiThreadImpl = struct {...@@ -923,6 +917,16 @@ const WasiThreadImpl = struct {
923 : [ret] "=r" (-> u32),917 : [ret] "=r" (-> u32),
924 );918 );
925 }919 }
920
921 /// Allows for setting the stack pointer in the WebAssembly module.
922 inline fn __set_stack_pointer(addr: [*]u8) void {
923 asm volatile (
924 \\ local.get %[ptr]
925 \\ global.set __stack_pointer
926 :
927 : [ptr] "r" (addr),
928 );
929 }
926};930};
927931
928const LinuxThreadImpl = struct {932const LinuxThreadImpl = struct {