authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-22 19:53:07+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-26 20:00:57+02:00
log622b7c47468bc4508f4cfe840e0f8c51b54949dd
tree987bad278d24c50313ec104e60a0fc6b00d20d50
parent834609038c83e0122b506fadfa38b9acb7ee9068
signature Commit is signed but in an unrecognized format.

free allocated memory upon call `join`

When `join` detects a thread has completed, it will free the allocated memory of the thread. For this we must first copy the allocator. This is required as the allocated memory holds a reference to the original allocator. If we free the memory, we would end up with UB as the allocator would free itself.

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

lib/std/Thread.zig+22-20
...@@ -762,13 +762,13 @@ const WasiThreadImpl = struct {...@@ -762,13 +762,13 @@ const WasiThreadImpl = struct {
762 /// A meta-data structure used to bootstrap a thread762 /// A meta-data structure used to bootstrap a thread
763 const Instance = struct {763 const Instance = struct {
764 thread: WasiThread,764 thread: WasiThread,
765 /// Address of this `Instance`765 /// Contains the offset to the new __tls_base.
766 base: usize,766 /// The offset starting from the memory's base.
767 /// Contains the pointer of the new __tls_base.767 tls_offset: usize,
768 tls_base: usize,768 /// Contains the offset to the stack for the newly spawned thread.
769 /// Contains the pointer to the stack for the newly spawned thread.769 /// The offset is calculated starting from the memory's base.
770 stack_pointer: usize,770 stack_offset: usize,
771 /// Contains the pointer to the wrapper which holds all arguments771 /// Contains the raw pointer value to the wrapper which holds all arguments
772 /// for the callback.772 /// for the callback.
773 raw_ptr: usize,773 raw_ptr: usize,
774 /// Function pointer to a wrapping function which will call the user's774 /// Function pointer to a wrapping function which will call the user's
...@@ -790,9 +790,12 @@ const WasiThreadImpl = struct {...@@ -790,9 +790,12 @@ const WasiThreadImpl = struct {
790 }790 }
791791
792 fn join(self: Impl) void {792 fn join(self: Impl) void {
793 // TODO cleanup memory793 defer {
794 // The memory also contains the thread's stack, which is problematic while freeing the memory794 // Create a copy of the allocator so we do not free the reference to the
795 // defer self.thread.allocator.free(self.thread.memory);795 // original allocator while freeing the memory.
796 var allocator = self.thread.allocator;
797 allocator.free(self.thread.memory);
798 }
796799
797 var spin: u8 = 10;800 var spin: u8 = 10;
798 while (true) {801 while (true) {
...@@ -808,11 +811,11 @@ const WasiThreadImpl = struct {...@@ -808,11 +811,11 @@ const WasiThreadImpl = struct {
808 }811 }
809812
810 const result = asm (813 const result = asm (
811 \\local.get %[ptr]814 \\ local.get %[ptr]
812 \\local.get %[expected]815 \\ local.get %[expected]
813 \\i64.const -1 # infinite816 \\ i64.const -1 # infinite
814 \\memory.atomic.wait32 0817 \\ memory.atomic.wait32 0
815 \\local.set %[ret]818 \\ local.set %[ret]
816 : [ret] "=r" (-> u32),819 : [ret] "=r" (-> u32),
817 : [ptr] "r" (&self.thread.tid.value),820 : [ptr] "r" (&self.thread.tid.value),
818 [expected] "r" (tid),821 [expected] "r" (tid),
...@@ -883,9 +886,8 @@ const WasiThreadImpl = struct {...@@ -883,9 +886,8 @@ const WasiThreadImpl = struct {
883 const instance = @ptrCast(*Instance, @alignCast(@alignOf(Instance), &allocated_memory[instance_offset]));886 const instance = @ptrCast(*Instance, @alignCast(@alignOf(Instance), &allocated_memory[instance_offset]));
884 instance.* = .{887 instance.* = .{
885 .thread = .{ .memory = allocated_memory, .allocator = config.allocator.? },888 .thread = .{ .memory = allocated_memory, .allocator = config.allocator.? },
886 .base = @ptrToInt(allocated_memory.ptr),889 .tls_offset = tls_offset,
887 .tls_base = tls_offset,890 .stack_offset = stack_offset,
888 .stack_pointer = stack_offset,
889 .raw_ptr = @ptrToInt(wrapper),891 .raw_ptr = @ptrToInt(wrapper),
890 .call_back = &Wrapper.entry,892 .call_back = &Wrapper.entry,
891 };893 };
...@@ -903,8 +905,8 @@ const WasiThreadImpl = struct {...@@ -903,8 +905,8 @@ const WasiThreadImpl = struct {
903905
904 /// Bootstrap procedure, called by the HOST environment after thread creation.906 /// Bootstrap procedure, called by the HOST environment after thread creation.
905 export fn wasi_thread_start(tid: i32, arg: *Instance) void {907 export fn wasi_thread_start(tid: i32, arg: *Instance) void {
906 __set_stack_pointer(arg.thread.memory.ptr + arg.stack_pointer);908 __set_stack_pointer(arg.thread.memory.ptr + arg.stack_offset);
907 __wasm_init_tls(arg.thread.memory.ptr + arg.tls_base);909 __wasm_init_tls(arg.thread.memory.ptr + arg.tls_offset);
908 WasiThreadImpl.tls_thread_id = @intCast(u32, tid);910 WasiThreadImpl.tls_thread_id = @intCast(u32, tid);
909911
910 // Finished bootstrapping, call user's procedure.912 // Finished bootstrapping, call user's procedure.