| author | |
| committer | |
| log | 5b90fa05a4e5b155f25319713acfc67ad9516c69 |
| tree | 6aaffe4ec16f7f6a18539bf2397176e001bf71cf |
| parent | 0b744d7d670d00fa865ebd17847cbdc1a909ba70 |
11 files changed, 211 insertions(+), 209 deletions(-)
CMakeLists.txt+2-2| ... | @@ -506,7 +506,9 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -506,7 +506,9 @@ set(ZIG_STAGE2_SOURCES |
| 506 | "${CMAKE_SOURCE_DIR}/lib/std/Thread.zig" | 506 | "${CMAKE_SOURCE_DIR}/lib/std/Thread.zig" |
| 507 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/Futex.zig" | 507 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/Futex.zig" |
| 508 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/Mutex.zig" | 508 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/Mutex.zig" |
| 509 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/Pool.zig" | ||
| 509 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/ResetEvent.zig" | 510 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/ResetEvent.zig" |
| 511 | "${CMAKE_SOURCE_DIR}/lib/std/Thread/WaitGroup.zig" | ||
| 510 | "${CMAKE_SOURCE_DIR}/lib/std/time.zig" | 512 | "${CMAKE_SOURCE_DIR}/lib/std/time.zig" |
| 511 | "${CMAKE_SOURCE_DIR}/lib/std/treap.zig" | 513 | "${CMAKE_SOURCE_DIR}/lib/std/treap.zig" |
| 512 | "${CMAKE_SOURCE_DIR}/lib/std/unicode.zig" | 514 | "${CMAKE_SOURCE_DIR}/lib/std/unicode.zig" |
| ... | @@ -530,9 +532,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -530,9 +532,7 @@ set(ZIG_STAGE2_SOURCES |
| 530 | "${CMAKE_SOURCE_DIR}/src/Package.zig" | 532 | "${CMAKE_SOURCE_DIR}/src/Package.zig" |
| 531 | "${CMAKE_SOURCE_DIR}/src/RangeSet.zig" | 533 | "${CMAKE_SOURCE_DIR}/src/RangeSet.zig" |
| 532 | "${CMAKE_SOURCE_DIR}/src/Sema.zig" | 534 | "${CMAKE_SOURCE_DIR}/src/Sema.zig" |
| 533 | "${CMAKE_SOURCE_DIR}/src/ThreadPool.zig" | ||
| 534 | "${CMAKE_SOURCE_DIR}/src/TypedValue.zig" | 535 | "${CMAKE_SOURCE_DIR}/src/TypedValue.zig" |
| 535 | "${CMAKE_SOURCE_DIR}/src/WaitGroup.zig" | ||
| 536 | "${CMAKE_SOURCE_DIR}/src/Zir.zig" | 536 | "${CMAKE_SOURCE_DIR}/src/Zir.zig" |
| 537 | "${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig" | 537 | "${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig" |
| 538 | "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig" | 538 | "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig" |
lib/std/Thread.zig+2| ... | @@ -16,6 +16,8 @@ pub const Mutex = @import("Thread/Mutex.zig"); | ... | @@ -16,6 +16,8 @@ pub const Mutex = @import("Thread/Mutex.zig"); |
| 16 | pub const Semaphore = @import("Thread/Semaphore.zig"); | 16 | pub const Semaphore = @import("Thread/Semaphore.zig"); |
| 17 | pub const Condition = @import("Thread/Condition.zig"); | 17 | pub const Condition = @import("Thread/Condition.zig"); |
| 18 | pub const RwLock = @import("Thread/RwLock.zig"); | 18 | pub const RwLock = @import("Thread/RwLock.zig"); |
| 19 | pub const Pool = @import("Thread/Pool.zig"); | ||
| 20 | pub const WaitGroup = @import("Thread/WaitGroup.zig"); | ||
| 19 | 21 | ||
| 20 | pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc; | 22 | pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc; |
| 21 | const is_gnu = target.abi.isGnu(); | 23 | const is_gnu = target.abi.isGnu(); |
lib/std/Thread/Pool.zig created+152| ... | @@ -0,0 +1,152 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const Pool = @This(); | ||
| 4 | const WaitGroup = @import("WaitGroup.zig"); | ||
| 5 | |||
| 6 | mutex: std.Thread.Mutex = .{}, | ||
| 7 | cond: std.Thread.Condition = .{}, | ||
| 8 | run_queue: RunQueue = .{}, | ||
| 9 | is_running: bool = true, | ||
| 10 | allocator: std.mem.Allocator, | ||
| 11 | threads: []std.Thread, | ||
| 12 | |||
| 13 | const RunQueue = std.SinglyLinkedList(Runnable); | ||
| 14 | const Runnable = struct { | ||
| 15 | runFn: RunProto, | ||
| 16 | }; | ||
| 17 | |||
| 18 | const RunProto = *const fn (*Runnable) void; | ||
| 19 | |||
| 20 | pub fn init(pool: *Pool, allocator: std.mem.Allocator) !void { | ||
| 21 | pool.* = .{ | ||
| 22 | .allocator = allocator, | ||
| 23 | .threads = &[_]std.Thread{}, | ||
| 24 | }; | ||
| 25 | |||
| 26 | if (builtin.single_threaded) { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | const thread_count = std.math.max(1, std.Thread.getCpuCount() catch 1); | ||
| 31 | pool.threads = try allocator.alloc(std.Thread, thread_count); | ||
| 32 | errdefer allocator.free(pool.threads); | ||
| 33 | |||
| 34 | // kill and join any threads we spawned previously on error. | ||
| 35 | var spawned: usize = 0; | ||
| 36 | errdefer pool.join(spawned); | ||
| 37 | |||
| 38 | for (pool.threads) |*thread| { | ||
| 39 | thread.* = try std.Thread.spawn(.{}, worker, .{pool}); | ||
| 40 | spawned += 1; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn deinit(pool: *Pool) void { | ||
| 45 | pool.join(pool.threads.len); // kill and join all threads. | ||
| 46 | pool.* = undefined; | ||
| 47 | } | ||
| 48 | |||
| 49 | fn join(pool: *Pool, spawned: usize) void { | ||
| 50 | if (builtin.single_threaded) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | { | ||
| 55 | pool.mutex.lock(); | ||
| 56 | defer pool.mutex.unlock(); | ||
| 57 | |||
| 58 | // ensure future worker threads exit the dequeue loop | ||
| 59 | pool.is_running = false; | ||
| 60 | } | ||
| 61 | |||
| 62 | // wake up any sleeping threads (this can be done outside the mutex) | ||
| 63 | // then wait for all the threads we know are spawned to complete. | ||
| 64 | pool.cond.broadcast(); | ||
| 65 | for (pool.threads[0..spawned]) |thread| { | ||
| 66 | thread.join(); | ||
| 67 | } | ||
| 68 | |||
| 69 | pool.allocator.free(pool.threads); | ||
| 70 | } | ||
| 71 | |||
| 72 | pub fn spawn(pool: *Pool, comptime func: anytype, args: anytype) !void { | ||
| 73 | if (builtin.single_threaded) { | ||
| 74 | @call(.auto, func, args); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | |||
| 78 | const Args = @TypeOf(args); | ||
| 79 | const Closure = struct { | ||
| 80 | arguments: Args, | ||
| 81 | pool: *Pool, | ||
| 82 | run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } }, | ||
| 83 | |||
| 84 | fn runFn(runnable: *Runnable) void { | ||
| 85 | const run_node = @fieldParentPtr(RunQueue.Node, "data", runnable); | ||
| 86 | const closure = @fieldParentPtr(@This(), "run_node", run_node); | ||
| 87 | @call(.auto, func, closure.arguments); | ||
| 88 | |||
| 89 | // The thread pool's allocator is protected by the mutex. | ||
| 90 | const mutex = &closure.pool.mutex; | ||
| 91 | mutex.lock(); | ||
| 92 | defer mutex.unlock(); | ||
| 93 | |||
| 94 | closure.pool.allocator.destroy(closure); | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | |||
| 98 | { | ||
| 99 | pool.mutex.lock(); | ||
| 100 | defer pool.mutex.unlock(); | ||
| 101 | |||
| 102 | const closure = try pool.allocator.create(Closure); | ||
| 103 | closure.* = .{ | ||
| 104 | .arguments = args, | ||
| 105 | .pool = pool, | ||
| 106 | }; | ||
| 107 | |||
| 108 | pool.run_queue.prepend(&closure.run_node); | ||
| 109 | } | ||
| 110 | |||
| 111 | // Notify waiting threads outside the lock to try and keep the critical section small. | ||
| 112 | pool.cond.signal(); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn worker(pool: *Pool) void { | ||
| 116 | pool.mutex.lock(); | ||
| 117 | defer pool.mutex.unlock(); | ||
| 118 | |||
| 119 | while (true) { | ||
| 120 | while (pool.run_queue.popFirst()) |run_node| { | ||
| 121 | // Temporarily unlock the mutex in order to execute the run_node | ||
| 122 | pool.mutex.unlock(); | ||
| 123 | defer pool.mutex.lock(); | ||
| 124 | |||
| 125 | const runFn = run_node.data.runFn; | ||
| 126 | runFn(&run_node.data); | ||
| 127 | } | ||
| 128 | |||
| 129 | // Stop executing instead of waiting if the thread pool is no longer running. | ||
| 130 | if (pool.is_running) { | ||
| 131 | pool.cond.wait(&pool.mutex); | ||
| 132 | } else { | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void { | ||
| 139 | while (!wait_group.isDone()) { | ||
| 140 | if (blk: { | ||
| 141 | pool.mutex.lock(); | ||
| 142 | defer pool.mutex.unlock(); | ||
| 143 | break :blk pool.run_queue.popFirst(); | ||
| 144 | }) |run_node| { | ||
| 145 | run_node.data.runFn(&run_node.data); | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | |||
| 149 | wait_group.wait(); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | } | ||
lib/std/Thread/WaitGroup.zig created+46| ... | @@ -0,0 +1,46 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Atomic = std.atomic.Atomic; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const WaitGroup = @This(); | ||
| 5 | |||
| 6 | const is_waiting: usize = 1 << 0; | ||
| 7 | const one_pending: usize = 1 << 1; | ||
| 8 | |||
| 9 | state: Atomic(usize) = Atomic(usize).init(0), | ||
| 10 | event: std.Thread.ResetEvent = .{}, | ||
| 11 | |||
| 12 | pub fn start(self: *WaitGroup) void { | ||
| 13 | const state = self.state.fetchAdd(one_pending, .Monotonic); | ||
| 14 | assert((state / one_pending) < (std.math.maxInt(usize) / one_pending)); | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn finish(self: *WaitGroup) void { | ||
| 18 | const state = self.state.fetchSub(one_pending, .Release); | ||
| 19 | assert((state / one_pending) > 0); | ||
| 20 | |||
| 21 | if (state == (one_pending | is_waiting)) { | ||
| 22 | self.state.fence(.Acquire); | ||
| 23 | self.event.set(); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | pub fn wait(self: *WaitGroup) void { | ||
| 28 | var state = self.state.fetchAdd(is_waiting, .Acquire); | ||
| 29 | assert(state & is_waiting == 0); | ||
| 30 | |||
| 31 | if ((state / one_pending) > 0) { | ||
| 32 | self.event.wait(); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | pub fn reset(self: *WaitGroup) void { | ||
| 37 | self.state.store(0, .Monotonic); | ||
| 38 | self.event.reset(); | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn isDone(wg: *WaitGroup) bool { | ||
| 42 | const state = wg.state.load(.Acquire); | ||
| 43 | assert(state & is_waiting == 0); | ||
| 44 | |||
| 45 | return (state / one_pending) == 0; | ||
| 46 | } | ||
src/Compilation.zig+2-2| ... | @@ -7,6 +7,8 @@ const Allocator = std.mem.Allocator; | ... | @@ -7,6 +7,8 @@ const Allocator = std.mem.Allocator; |
| 7 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const log = std.log.scoped(.compilation); | 8 | const log = std.log.scoped(.compilation); |
| 9 | const Target = std.Target; | 9 | const Target = std.Target; |
| 10 | const ThreadPool = std.Thread.Pool; | ||
| 11 | const WaitGroup = std.Thread.WaitGroup; | ||
| 10 | 12 | ||
| 11 | const Value = @import("value.zig").Value; | 13 | const Value = @import("value.zig").Value; |
| 12 | const Type = @import("type.zig").Type; | 14 | const Type = @import("type.zig").Type; |
| ... | @@ -30,8 +32,6 @@ const Cache = std.Build.Cache; | ... | @@ -30,8 +32,6 @@ const Cache = std.Build.Cache; |
| 30 | const translate_c = @import("translate_c.zig"); | 32 | const translate_c = @import("translate_c.zig"); |
| 31 | const clang = @import("clang.zig"); | 33 | const clang = @import("clang.zig"); |
| 32 | const c_codegen = @import("codegen/c.zig"); | 34 | const c_codegen = @import("codegen/c.zig"); |
| 33 | const ThreadPool = @import("ThreadPool.zig"); | ||
| 34 | const WaitGroup = @import("WaitGroup.zig"); | ||
| 35 | const libtsan = @import("libtsan.zig"); | 35 | const libtsan = @import("libtsan.zig"); |
| 36 | const Zir = @import("Zir.zig"); | 36 | const Zir = @import("Zir.zig"); |
| 37 | const Autodoc = @import("Autodoc.zig"); | 37 | const Autodoc = @import("Autodoc.zig"); |
src/Package.zig+2-2| ... | @@ -8,11 +8,11 @@ const Allocator = mem.Allocator; | ... | @@ -8,11 +8,11 @@ const Allocator = mem.Allocator; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const log = std.log.scoped(.package); | 9 | const log = std.log.scoped(.package); |
| 10 | const main = @import("main.zig"); | 10 | const main = @import("main.zig"); |
| 11 | const ThreadPool = std.Thread.Pool; | ||
| 12 | const WaitGroup = std.Thread.WaitGroup; | ||
| 11 | 13 | ||
| 12 | const Compilation = @import("Compilation.zig"); | 14 | const Compilation = @import("Compilation.zig"); |
| 13 | const Module = @import("Module.zig"); | 15 | const Module = @import("Module.zig"); |
| 14 | const ThreadPool = @import("ThreadPool.zig"); | ||
| 15 | const WaitGroup = @import("WaitGroup.zig"); | ||
| 16 | const Cache = std.Build.Cache; | 16 | const Cache = std.Build.Cache; |
| 17 | const build_options = @import("build_options"); | 17 | const build_options = @import("build_options"); |
| 18 | const Manifest = @import("Manifest.zig"); | 18 | const Manifest = @import("Manifest.zig"); |
src/ThreadPool.zig deleted-152| ... | @@ -1,152 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const ThreadPool = @This(); | ||
| 4 | const WaitGroup = @import("WaitGroup.zig"); | ||
| 5 | |||
| 6 | mutex: std.Thread.Mutex = .{}, | ||
| 7 | cond: std.Thread.Condition = .{}, | ||
| 8 | run_queue: RunQueue = .{}, | ||
| 9 | is_running: bool = true, | ||
| 10 | allocator: std.mem.Allocator, | ||
| 11 | threads: []std.Thread, | ||
| 12 | |||
| 13 | const RunQueue = std.SinglyLinkedList(Runnable); | ||
| 14 | const Runnable = struct { | ||
| 15 | runFn: RunProto, | ||
| 16 | }; | ||
| 17 | |||
| 18 | const RunProto = *const fn (*Runnable) void; | ||
| 19 | |||
| 20 | pub fn init(pool: *ThreadPool, allocator: std.mem.Allocator) !void { | ||
| 21 | pool.* = .{ | ||
| 22 | .allocator = allocator, | ||
| 23 | .threads = &[_]std.Thread{}, | ||
| 24 | }; | ||
| 25 | |||
| 26 | if (builtin.single_threaded) { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | const thread_count = std.math.max(1, std.Thread.getCpuCount() catch 1); | ||
| 31 | pool.threads = try allocator.alloc(std.Thread, thread_count); | ||
| 32 | errdefer allocator.free(pool.threads); | ||
| 33 | |||
| 34 | // kill and join any threads we spawned previously on error. | ||
| 35 | var spawned: usize = 0; | ||
| 36 | errdefer pool.join(spawned); | ||
| 37 | |||
| 38 | for (pool.threads) |*thread| { | ||
| 39 | thread.* = try std.Thread.spawn(.{}, worker, .{pool}); | ||
| 40 | spawned += 1; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn deinit(pool: *ThreadPool) void { | ||
| 45 | pool.join(pool.threads.len); // kill and join all threads. | ||
| 46 | pool.* = undefined; | ||
| 47 | } | ||
| 48 | |||
| 49 | fn join(pool: *ThreadPool, spawned: usize) void { | ||
| 50 | if (builtin.single_threaded) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | { | ||
| 55 | pool.mutex.lock(); | ||
| 56 | defer pool.mutex.unlock(); | ||
| 57 | |||
| 58 | // ensure future worker threads exit the dequeue loop | ||
| 59 | pool.is_running = false; | ||
| 60 | } | ||
| 61 | |||
| 62 | // wake up any sleeping threads (this can be done outside the mutex) | ||
| 63 | // then wait for all the threads we know are spawned to complete. | ||
| 64 | pool.cond.broadcast(); | ||
| 65 | for (pool.threads[0..spawned]) |thread| { | ||
| 66 | thread.join(); | ||
| 67 | } | ||
| 68 | |||
| 69 | pool.allocator.free(pool.threads); | ||
| 70 | } | ||
| 71 | |||
| 72 | pub fn spawn(pool: *ThreadPool, comptime func: anytype, args: anytype) !void { | ||
| 73 | if (builtin.single_threaded) { | ||
| 74 | @call(.auto, func, args); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | |||
| 78 | const Args = @TypeOf(args); | ||
| 79 | const Closure = struct { | ||
| 80 | arguments: Args, | ||
| 81 | pool: *ThreadPool, | ||
| 82 | run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } }, | ||
| 83 | |||
| 84 | fn runFn(runnable: *Runnable) void { | ||
| 85 | const run_node = @fieldParentPtr(RunQueue.Node, "data", runnable); | ||
| 86 | const closure = @fieldParentPtr(@This(), "run_node", run_node); | ||
| 87 | @call(.auto, func, closure.arguments); | ||
| 88 | |||
| 89 | // The thread pool's allocator is protected by the mutex. | ||
| 90 | const mutex = &closure.pool.mutex; | ||
| 91 | mutex.lock(); | ||
| 92 | defer mutex.unlock(); | ||
| 93 | |||
| 94 | closure.pool.allocator.destroy(closure); | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | |||
| 98 | { | ||
| 99 | pool.mutex.lock(); | ||
| 100 | defer pool.mutex.unlock(); | ||
| 101 | |||
| 102 | const closure = try pool.allocator.create(Closure); | ||
| 103 | closure.* = .{ | ||
| 104 | .arguments = args, | ||
| 105 | .pool = pool, | ||
| 106 | }; | ||
| 107 | |||
| 108 | pool.run_queue.prepend(&closure.run_node); | ||
| 109 | } | ||
| 110 | |||
| 111 | // Notify waiting threads outside the lock to try and keep the critical section small. | ||
| 112 | pool.cond.signal(); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn worker(pool: *ThreadPool) void { | ||
| 116 | pool.mutex.lock(); | ||
| 117 | defer pool.mutex.unlock(); | ||
| 118 | |||
| 119 | while (true) { | ||
| 120 | while (pool.run_queue.popFirst()) |run_node| { | ||
| 121 | // Temporarily unlock the mutex in order to execute the run_node | ||
| 122 | pool.mutex.unlock(); | ||
| 123 | defer pool.mutex.lock(); | ||
| 124 | |||
| 125 | const runFn = run_node.data.runFn; | ||
| 126 | runFn(&run_node.data); | ||
| 127 | } | ||
| 128 | |||
| 129 | // Stop executing instead of waiting if the thread pool is no longer running. | ||
| 130 | if (pool.is_running) { | ||
| 131 | pool.cond.wait(&pool.mutex); | ||
| 132 | } else { | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn waitAndWork(pool: *ThreadPool, wait_group: *WaitGroup) void { | ||
| 139 | while (!wait_group.isDone()) { | ||
| 140 | if (blk: { | ||
| 141 | pool.mutex.lock(); | ||
| 142 | defer pool.mutex.unlock(); | ||
| 143 | break :blk pool.run_queue.popFirst(); | ||
| 144 | }) |run_node| { | ||
| 145 | run_node.data.runFn(&run_node.data); | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | |||
| 149 | wait_group.wait(); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | } | ||
src/WaitGroup.zig deleted-46| ... | @@ -1,46 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Atomic = std.atomic.Atomic; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const WaitGroup = @This(); | ||
| 5 | |||
| 6 | const is_waiting: usize = 1 << 0; | ||
| 7 | const one_pending: usize = 1 << 1; | ||
| 8 | |||
| 9 | state: Atomic(usize) = Atomic(usize).init(0), | ||
| 10 | event: std.Thread.ResetEvent = .{}, | ||
| 11 | |||
| 12 | pub fn start(self: *WaitGroup) void { | ||
| 13 | const state = self.state.fetchAdd(one_pending, .Monotonic); | ||
| 14 | assert((state / one_pending) < (std.math.maxInt(usize) / one_pending)); | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn finish(self: *WaitGroup) void { | ||
| 18 | const state = self.state.fetchSub(one_pending, .Release); | ||
| 19 | assert((state / one_pending) > 0); | ||
| 20 | |||
| 21 | if (state == (one_pending | is_waiting)) { | ||
| 22 | self.state.fence(.Acquire); | ||
| 23 | self.event.set(); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | pub fn wait(self: *WaitGroup) void { | ||
| 28 | var state = self.state.fetchAdd(is_waiting, .Acquire); | ||
| 29 | assert(state & is_waiting == 0); | ||
| 30 | |||
| 31 | if ((state / one_pending) > 0) { | ||
| 32 | self.event.wait(); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | pub fn reset(self: *WaitGroup) void { | ||
| 37 | self.state.store(0, .Monotonic); | ||
| 38 | self.event.reset(); | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn isDone(wg: *WaitGroup) bool { | ||
| 42 | const state = wg.state.load(.Acquire); | ||
| 43 | assert(state & is_waiting == 0); | ||
| 44 | |||
| 45 | return (state / one_pending) == 0; | ||
| 46 | } | ||
src/link/MachO/CodeSignature.zig+2-2| ... | @@ -7,12 +7,12 @@ const log = std.log.scoped(.link); | ... | @@ -7,12 +7,12 @@ const log = std.log.scoped(.link); |
| 7 | const macho = std.macho; | 7 | const macho = std.macho; |
| 8 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const ThreadPool = std.Thread.Pool; | ||
| 11 | const WaitGroup = std.Thread.WaitGroup; | ||
| 10 | 12 | ||
| 11 | const Allocator = mem.Allocator; | 13 | const Allocator = mem.Allocator; |
| 12 | const Compilation = @import("../../Compilation.zig"); | 14 | const Compilation = @import("../../Compilation.zig"); |
| 13 | const Sha256 = std.crypto.hash.sha2.Sha256; | 15 | const Sha256 = std.crypto.hash.sha2.Sha256; |
| 14 | const ThreadPool = @import("../../ThreadPool.zig"); | ||
| 15 | const WaitGroup = @import("../../WaitGroup.zig"); | ||
| 16 | 16 | ||
| 17 | const hash_size = Sha256.digest_length; | 17 | const hash_size = Sha256.digest_length; |
| 18 | 18 |
src/main.zig+1-1| ... | @@ -9,6 +9,7 @@ const Allocator = mem.Allocator; | ... | @@ -9,6 +9,7 @@ const Allocator = mem.Allocator; |
| 9 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 10 | const Ast = std.zig.Ast; | 10 | const Ast = std.zig.Ast; |
| 11 | const warn = std.log.warn; | 11 | const warn = std.log.warn; |
| 12 | const ThreadPool = std.Thread.Pool; | ||
| 12 | 13 | ||
| 13 | const tracy = @import("tracy.zig"); | 14 | const tracy = @import("tracy.zig"); |
| 14 | const Compilation = @import("Compilation.zig"); | 15 | const Compilation = @import("Compilation.zig"); |
| ... | @@ -22,7 +23,6 @@ const translate_c = @import("translate_c.zig"); | ... | @@ -22,7 +23,6 @@ const translate_c = @import("translate_c.zig"); |
| 22 | const clang = @import("clang.zig"); | 23 | const clang = @import("clang.zig"); |
| 23 | const Cache = std.Build.Cache; | 24 | const Cache = std.Build.Cache; |
| 24 | const target_util = @import("target.zig"); | 25 | const target_util = @import("target.zig"); |
| 25 | const ThreadPool = @import("ThreadPool.zig"); | ||
| 26 | const crash_report = @import("crash_report.zig"); | 26 | const crash_report = @import("crash_report.zig"); |
| 27 | 27 | ||
| 28 | pub const std_options = struct { | 28 | pub const std_options = struct { |
src/test.zig+2-2| ... | @@ -4,14 +4,14 @@ const Allocator = std.mem.Allocator; | ... | @@ -4,14 +4,14 @@ const Allocator = std.mem.Allocator; |
| 4 | const CrossTarget = std.zig.CrossTarget; | 4 | const CrossTarget = std.zig.CrossTarget; |
| 5 | const print = std.debug.print; | 5 | const print = std.debug.print; |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const ThreadPool = std.Thread.Pool; | ||
| 8 | const WaitGroup = std.Thread.WaitGroup; | ||
| 7 | 9 | ||
| 8 | const link = @import("link.zig"); | 10 | const link = @import("link.zig"); |
| 9 | const Compilation = @import("Compilation.zig"); | 11 | const Compilation = @import("Compilation.zig"); |
| 10 | const Package = @import("Package.zig"); | 12 | const Package = @import("Package.zig"); |
| 11 | const introspect = @import("introspect.zig"); | 13 | const introspect = @import("introspect.zig"); |
| 12 | const build_options = @import("build_options"); | 14 | const build_options = @import("build_options"); |
| 13 | const ThreadPool = @import("ThreadPool.zig"); | ||
| 14 | const WaitGroup = @import("WaitGroup.zig"); | ||
| 15 | const zig_h = link.File.C.zig_h; | 15 | const zig_h = link.File.C.zig_h; |
| 16 | 16 | ||
| 17 | const enable_qemu: bool = build_options.enable_qemu; | 17 | const enable_qemu: bool = build_options.enable_qemu; |