diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-10-23 22:56:04 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-23 22:56:04 -0700 |
| commit | c563ba6b15b65ecdc1cb538c9437e11dfb330453 (patch) | |
| tree | 99dd968efc3daea52a1d3628b7d8cedba53e84b7 /src/ThreadSafeQueue.zig | |
| parent | 33d07f4b6efe461ee3fbfa32cb18f60aac8c2827 (diff) | |
| parent | 4bdc2d38717b5655acd862a5762e069419b158c7 (diff) | |
| download | zig-c563ba6b15b65ecdc1cb538c9437e11dfb330453.tar.gz zig-c563ba6b15b65ecdc1cb538c9437e11dfb330453.zip | |
Merge pull request #21700 from ziglang/cli-lib-dirs
move linker input file parsing to the frontend
Diffstat (limited to 'src/ThreadSafeQueue.zig')
| -rw-r--r-- | src/ThreadSafeQueue.zig | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/ThreadSafeQueue.zig b/src/ThreadSafeQueue.zig new file mode 100644 index 0000000000..74bbdc418f --- /dev/null +++ b/src/ThreadSafeQueue.zig @@ -0,0 +1,72 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; + +pub fn ThreadSafeQueue(comptime T: type) type { + return struct { + worker_owned: std.ArrayListUnmanaged(T), + /// Protected by `mutex`. + shared: std.ArrayListUnmanaged(T), + mutex: std.Thread.Mutex, + state: State, + + const Self = @This(); + + pub const State = enum { wait, run }; + + pub const empty: Self = .{ + .worker_owned = .empty, + .shared = .empty, + .mutex = .{}, + .state = .wait, + }; + + pub fn deinit(self: *Self, gpa: Allocator) void { + self.worker_owned.deinit(gpa); + self.shared.deinit(gpa); + self.* = undefined; + } + + /// Must be called from the worker thread. + pub fn check(self: *Self) ?[]T { + assert(self.worker_owned.items.len == 0); + { + self.mutex.lock(); + defer self.mutex.unlock(); + assert(self.state == .run); + if (self.shared.items.len == 0) { + self.state = .wait; + return null; + } + std.mem.swap(std.ArrayListUnmanaged(T), &self.worker_owned, &self.shared); + } + const result = self.worker_owned.items; + self.worker_owned.clearRetainingCapacity(); + return result; + } + + /// Adds items to the queue, returning true if and only if the worker + /// thread is waiting. Thread-safe. + /// Not safe to call from the worker thread. + pub fn enqueue(self: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!bool { + self.mutex.lock(); + defer self.mutex.unlock(); + try self.shared.appendSlice(gpa, items); + return switch (self.state) { + .run => false, + .wait => { + self.state = .run; + return true; + }, + }; + } + + /// Safe only to call exactly once when initially starting the worker. + pub fn start(self: *Self) bool { + assert(self.state == .wait); + if (self.shared.items.len == 0) return false; + self.state = .run; + return true; + } + }; +} |
