aboutsummaryrefslogtreecommitdiff
path: root/std/mutex.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-02-01 17:49:29 -0500
committerAndrew Kelley <andrew@ziglang.org>2019-02-01 18:05:54 -0500
commit9b8e23934bc87f1fd6a42cdfdd551212994b6e58 (patch)
tree0ac63357b6504f7bf44e66002b0ccca49dc64b45 /std/mutex.zig
parent8bedb10939b511e39787b2693249d2d3e8102854 (diff)
downloadzig-9b8e23934bc87f1fd6a42cdfdd551212994b6e58.tar.gz
zig-9b8e23934bc87f1fd6a42cdfdd551212994b6e58.zip
introduce --single-threaded build option
closes #1764 This adds another boolean to the test matrix; hopefully it does not inflate the time too much. std.event.Loop does not work with this option yet. See #1908
Diffstat (limited to 'std/mutex.zig')
-rw-r--r--std/mutex.zig66
1 files changed, 48 insertions, 18 deletions
diff --git a/std/mutex.zig b/std/mutex.zig
index 723581cbef..54173fa38a 100644
--- a/std/mutex.zig
+++ b/std/mutex.zig
@@ -14,7 +14,36 @@ const windows = std.os.windows;
/// If you need static initialization, use std.StaticallyInitializedMutex.
/// The Linux implementation is based on mutex3 from
/// https://www.akkadia.org/drepper/futex.pdf
-pub const Mutex = switch(builtin.os) {
+/// When an application is built in single threaded release mode, all the functions are
+/// no-ops. In single threaded debug mode, there is deadlock detection.
+pub const Mutex = if (builtin.single_threaded)
+ struct {
+ lock: @typeOf(lock_init),
+
+ const lock_init = if (std.debug.runtime_safety) false else {};
+
+ pub const Held = struct {
+ mutex: *Mutex,
+
+ pub fn release(self: Held) void {
+ if (std.debug.runtime_safety) {
+ self.mutex.lock = false;
+ }
+ }
+ };
+ pub fn init() Mutex {
+ return Mutex{ .lock = lock_init };
+ }
+ pub fn deinit(self: *Mutex) void {}
+
+ pub fn acquire(self: *Mutex) Held {
+ if (std.debug.runtime_safety and self.lock) {
+ @panic("deadlock detected");
+ }
+ return Held{ .mutex = self };
+ }
+ }
+else switch (builtin.os) {
builtin.Os.linux => struct {
/// 0: unlocked
/// 1: locked, no waiters
@@ -39,9 +68,7 @@ pub const Mutex = switch(builtin.os) {
};
pub fn init() Mutex {
- return Mutex {
- .lock = 0,
- };
+ return Mutex{ .lock = 0 };
}
pub fn deinit(self: *Mutex) void {}
@@ -60,7 +87,7 @@ pub const Mutex = switch(builtin.os) {
}
c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire);
}
- return Held { .mutex = self };
+ return Held{ .mutex = self };
}
},
// TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a
@@ -78,21 +105,19 @@ pub const Mutex = switch(builtin.os) {
mutex: *Mutex,
pub fn release(self: Held) void {
- SpinLock.Held.release(SpinLock.Held { .spinlock = &self.mutex.lock });
+ SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.lock });
}
};
pub fn init() Mutex {
- return Mutex {
- .lock = SpinLock.init(),
- };
+ return Mutex{ .lock = SpinLock.init() };
}
pub fn deinit(self: *Mutex) void {}
pub fn acquire(self: *Mutex) Held {
_ = self.lock.acquire();
- return Held { .mutex = self };
+ return Held{ .mutex = self };
}
},
};
@@ -122,15 +147,20 @@ test "std.Mutex" {
.data = 0,
};
- const thread_count = 10;
- var threads: [thread_count]*std.os.Thread = undefined;
- for (threads) |*t| {
- t.* = try std.os.spawnThread(&context, worker);
- }
- for (threads) |t|
- t.wait();
+ if (builtin.single_threaded) {
+ worker(&context);
+ std.debug.assertOrPanic(context.data == TestContext.incr_count);
+ } else {
+ const thread_count = 10;
+ var threads: [thread_count]*std.os.Thread = undefined;
+ for (threads) |*t| {
+ t.* = try std.os.spawnThread(&context, worker);
+ }
+ for (threads) |t|
+ t.wait();
- std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count);
+ std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count);
+ }
}
fn worker(ctx: *TestContext) void {