aboutsummaryrefslogtreecommitdiff
path: root/src/ThreadSafeQueue.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-10-23 22:56:04 -0700
committerGitHub <noreply@github.com>2024-10-23 22:56:04 -0700
commitc563ba6b15b65ecdc1cb538c9437e11dfb330453 (patch)
tree99dd968efc3daea52a1d3628b7d8cedba53e84b7 /src/ThreadSafeQueue.zig
parent33d07f4b6efe461ee3fbfa32cb18f60aac8c2827 (diff)
parent4bdc2d38717b5655acd862a5762e069419b158c7 (diff)
downloadzig-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.zig72
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;
+ }
+ };
+}