zig/lib/std/once.zig
Andrew Kelley 0347df82e8 improvements & fixes for general purpose allocator integration
* std.Mutex API is improved to not have init() deinit(). This API is
   designed to support static initialization and does not require any
   resource cleanup. This also happens to work around some kind of
   stage1 behavior that wasn't letting the new allocator mutex code
   get compiled.
 * the general purpose allocator now returns a bool from deinit()
   which tells if there were any leaks. This value is used by the test
   runner to fail the tests if there are any.
 * self-hosted compiler is updated to use the general purpose allocator
   when not linking against libc.
2020-08-07 23:26:58 -07:00

67 lines
1.7 KiB
Zig

const std = @import("std.zig");
const builtin = std.builtin;
const testing = std.testing;
pub fn once(comptime f: fn () void) Once(f) {
return Once(f){};
}
/// An object that executes the function `f` just once.
pub fn Once(comptime f: fn () void) type {
return struct {
done: bool = false,
mutex: std.Mutex = std.Mutex{},
/// Call the function `f`.
/// If `call` is invoked multiple times `f` will be executed only the
/// first time.
/// The invocations are thread-safe.
pub fn call(self: *@This()) void {
if (@atomicLoad(bool, &self.done, .Acquire))
return;
return self.callSlow();
}
fn callSlow(self: *@This()) void {
@setCold(true);
const T = self.mutex.acquire();
defer T.release();
// The first thread to acquire the mutex gets to run the initializer
if (!self.done) {
f();
@atomicStore(bool, &self.done, true, .Release);
}
}
};
}
var global_number: i32 = 0;
var global_once = once(incr);
fn incr() void {
global_number += 1;
}
test "Once executes its function just once" {
if (builtin.single_threaded) {
global_once.call();
global_once.call();
} else {
var threads: [10]*std.Thread = undefined;
defer for (threads) |handle| handle.wait();
for (threads) |*handle| {
handle.* = try std.Thread.spawn(@as(u8, 0), struct {
fn thread_fn(x: u8) void {
global_once.call();
}
}.thread_fn);
}
}
testing.expectEqual(@as(i32, 1), global_number);
}