diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b4c067ae6..272cdc6921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -512,7 +512,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/Cache.zig" "${CMAKE_SOURCE_DIR}/src/Compilation.zig" "${CMAKE_SOURCE_DIR}/src/DepTokenizer.zig" - "${CMAKE_SOURCE_DIR}/src/Event.zig" "${CMAKE_SOURCE_DIR}/src/Module.zig" "${CMAKE_SOURCE_DIR}/src/Package.zig" "${CMAKE_SOURCE_DIR}/src/RangeSet.zig" diff --git a/ci/drone/linux_script b/ci/drone/linux_script index 8c5dc1be2a..fdc1704fb7 100755 --- a/ci/drone/linux_script +++ b/ci/drone/linux_script @@ -17,8 +17,7 @@ git config core.abbrev 9 mkdir build cd build -# TODO figure out why Drone CI is deadlocking and stop passing -DZIG_SINGLE_THREADED=ON -cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local -GNinja -DZIG_SINGLE_THREADED=ON +cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local -GNinja samu install ./zig build test -Dskip-release -Dskip-non-native diff --git a/src/Event.zig b/src/Event.zig deleted file mode 100644 index 2b8d7be998..0000000000 --- a/src/Event.zig +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2020 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("std"); -const Event = @This(); - -lock: std.Mutex = .{}, -event: std.ResetEvent = undefined, -state: enum { empty, waiting, notified } = .empty, - -pub fn wait(self: *Event) void { - const held = self.lock.acquire(); - - switch (self.state) { - .empty => { - self.state = .waiting; - self.event = @TypeOf(self.event).init(); - held.release(); - self.event.wait(); - self.event.deinit(); - }, - .waiting => unreachable, - .notified => held.release(), - } -} - -pub fn set(self: *Event) void { - const held = self.lock.acquire(); - - switch (self.state) { - .empty => { - self.state = .notified; - held.release(); - }, - .waiting => { - held.release(); - self.event.set(); - }, - .notified => unreachable, - } -} diff --git a/src/ThreadPool.zig b/src/ThreadPool.zig index 00cb26772a..71c72fb8da 100644 --- a/src/ThreadPool.zig +++ b/src/ThreadPool.zig @@ -9,12 +9,12 @@ const ThreadPool = @This(); lock: std.Mutex = .{}, is_running: bool = true, allocator: *std.mem.Allocator, -running: usize = 0, +spawned: usize = 0, threads: []*std.Thread, run_queue: RunQueue = .{}, idle_queue: IdleQueue = .{}, -const IdleQueue = std.SinglyLinkedList(std.AutoResetEvent); +const IdleQueue = std.SinglyLinkedList(std.ResetEvent); const RunQueue = std.SinglyLinkedList(Runnable); const Runnable = struct { runFn: fn (*Runnable) void, @@ -30,49 +30,37 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void { errdefer self.deinit(); - var num_threads = std.Thread.cpuCount() catch 1; - if (num_threads > 0) - self.threads = try allocator.alloc(*std.Thread, num_threads); + var num_threads = std.math.max(1, std.Thread.cpuCount() catch 1); + self.threads = try allocator.alloc(*std.Thread, num_threads); while (num_threads > 0) : (num_threads -= 1) { const thread = try std.Thread.spawn(self, runWorker); - self.threads[self.running] = thread; - self.running += 1; + self.threads[self.spawned] = thread; + self.spawned += 1; } } pub fn deinit(self: *ThreadPool) void { - self.shutdown(); + { + const held = self.lock.acquire(); + defer held.release(); - std.debug.assert(!self.is_running); - for (self.threads[0..self.running]) |thread| + self.is_running = false; + while (self.idle_queue.popFirst()) |idle_node| + idle_node.data.set(); + } + + defer self.allocator.free(self.threads); + for (self.threads[0..self.spawned]) |thread| thread.wait(); - - defer self.threads = &[_]*std.Thread{}; - if (self.running > 0) - self.allocator.free(self.threads); -} - -pub fn shutdown(self: *ThreadPool) void { - const held = self.lock.acquire(); - - if (!self.is_running) - return held.release(); - - var idle_queue = self.idle_queue; - self.idle_queue = .{}; - self.is_running = false; - held.release(); - - while (idle_queue.popFirst()) |idle_node| - idle_node.data.set(); } pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { if (std.builtin.single_threaded) { - @call(.{}, func, args); + const result = @call(.{}, func, args); return; } + const Args = @TypeOf(args); const Closure = struct { arguments: Args, @@ -83,24 +71,26 @@ pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { const run_node = @fieldParentPtr(RunQueue.Node, "data", runnable); const closure = @fieldParentPtr(@This(), "run_node", run_node); const result = @call(.{}, func, closure.arguments); + + const held = closure.pool.lock.acquire(); + defer held.release(); closure.pool.allocator.destroy(closure); } }; + const held = self.lock.acquire(); + defer held.release(); + const closure = try self.allocator.create(Closure); closure.* = .{ .arguments = args, .pool = self, }; - const held = self.lock.acquire(); self.run_queue.prepend(&closure.run_node); - const idle_node = self.idle_queue.popFirst(); - held.release(); - - if (idle_node) |node| - node.data.set(); + if (self.idle_queue.popFirst()) |idle_node| + idle_node.data.set(); } fn runWorker(self: *ThreadPool) void { @@ -113,14 +103,18 @@ fn runWorker(self: *ThreadPool) void { continue; } - if (!self.is_running) { + if (self.is_running) { + var idle_node = IdleQueue.Node{ .data = std.ResetEvent.init() }; + defer idle_node.data.deinit(); + + self.idle_queue.prepend(&idle_node); held.release(); - return; + + idle_node.data.wait(); + continue; } - var idle_node = IdleQueue.Node{ .data = .{} }; - self.idle_queue.prepend(&idle_node); held.release(); - idle_node.data.wait(); + return; } } diff --git a/src/WaitGroup.zig b/src/WaitGroup.zig index 2c1b49224b..e5d4e600e2 100644 --- a/src/WaitGroup.zig +++ b/src/WaitGroup.zig @@ -5,11 +5,10 @@ // and substantial portions of the software. const std = @import("std"); const WaitGroup = @This(); -const Event = @import("Event.zig"); lock: std.Mutex = .{}, counter: usize = 0, -event: ?*Event = null, +event: ?*std.ResetEvent = null, pub fn start(self: *WaitGroup) void { const held = self.lock.acquire(); @@ -19,28 +18,33 @@ pub fn start(self: *WaitGroup) void { } pub fn stop(self: *WaitGroup) void { - var event: ?*Event = null; - defer if (event) |waiter| - waiter.set(); - const held = self.lock.acquire(); defer held.release(); self.counter -= 1; - if (self.counter == 0) - std.mem.swap(?*Event, &self.event, &event); + + if (self.counter == 0) { + if (self.event) |event| { + self.event = null; + event.set(); + } + } } pub fn wait(self: *WaitGroup) void { - var event = Event{}; - var has_event = false; - defer if (has_event) - event.wait(); - const held = self.lock.acquire(); - defer held.release(); - has_event = self.counter != 0; - if (has_event) - self.event = &event; + if (self.counter == 0) { + held.release(); + return; + } + + var event = std.ResetEvent.init(); + defer event.deinit(); + + std.debug.assert(self.event == null); + self.event = &event; + + held.release(); + event.wait(); }