aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-07-16 20:52:50 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-07-16 20:52:50 -0400
commit97bfeac13f89e1b5a22fcd7d4705341b4c3e1950 (patch)
tree4a3e23a8b3908450b23f2dbba72e5f6c091d7114 /std
parent0fa24b6b7568557c29c9b3ee213ce2b06fcd6367 (diff)
downloadzig-97bfeac13f89e1b5a22fcd7d4705341b4c3e1950.tar.gz
zig-97bfeac13f89e1b5a22fcd7d4705341b4c3e1950.zip
self-hosted: create tmp dir for .o files and emit .o file for fn
Diffstat (limited to 'std')
-rw-r--r--std/atomic/int.zig4
-rw-r--r--std/buffer.zig13
-rw-r--r--std/dwarf.zig37
-rw-r--r--std/event/future.zig39
-rw-r--r--std/index.zig3
-rw-r--r--std/lazy_init.zig85
6 files changed, 173 insertions, 8 deletions
diff --git a/std/atomic/int.zig b/std/atomic/int.zig
index d51454c673..4103d52719 100644
--- a/std/atomic/int.zig
+++ b/std/atomic/int.zig
@@ -25,5 +25,9 @@ pub fn Int(comptime T: type) type {
pub fn get(self: *Self) T {
return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
}
+
+ pub fn xchg(self: *Self, new_value: T) T {
+ return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst);
+ }
};
}
diff --git a/std/buffer.zig b/std/buffer.zig
index aff7fa86ef..3b58002aba 100644
--- a/std/buffer.zig
+++ b/std/buffer.zig
@@ -54,6 +54,19 @@ pub const Buffer = struct {
return result;
}
+ pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: ...) !Buffer {
+ const countSize = struct {
+ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
+ size.* += bytes.len;
+ }
+ }.countSize;
+ var size: usize = 0;
+ std.fmt.format(&size, error{}, countSize, format, args) catch |err| switch (err) {};
+ var self = try Buffer.initSize(allocator, size);
+ assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
+ return self;
+ }
+
pub fn deinit(self: *Buffer) void {
self.list.deinit();
}
diff --git a/std/dwarf.zig b/std/dwarf.zig
index 76ed122447..2cf8ed953e 100644
--- a/std/dwarf.zig
+++ b/std/dwarf.zig
@@ -639,3 +639,40 @@ pub const LNE_define_file = 0x03;
pub const LNE_set_discriminator = 0x04;
pub const LNE_lo_user = 0x80;
pub const LNE_hi_user = 0xff;
+
+pub const LANG_C89 = 0x0001;
+pub const LANG_C = 0x0002;
+pub const LANG_Ada83 = 0x0003;
+pub const LANG_C_plus_plus = 0x0004;
+pub const LANG_Cobol74 = 0x0005;
+pub const LANG_Cobol85 = 0x0006;
+pub const LANG_Fortran77 = 0x0007;
+pub const LANG_Fortran90 = 0x0008;
+pub const LANG_Pascal83 = 0x0009;
+pub const LANG_Modula2 = 0x000a;
+pub const LANG_Java = 0x000b;
+pub const LANG_C99 = 0x000c;
+pub const LANG_Ada95 = 0x000d;
+pub const LANG_Fortran95 = 0x000e;
+pub const LANG_PLI = 0x000f;
+pub const LANG_ObjC = 0x0010;
+pub const LANG_ObjC_plus_plus = 0x0011;
+pub const LANG_UPC = 0x0012;
+pub const LANG_D = 0x0013;
+pub const LANG_Python = 0x0014;
+pub const LANG_Go = 0x0016;
+pub const LANG_C_plus_plus_11 = 0x001a;
+pub const LANG_Rust = 0x001c;
+pub const LANG_C11 = 0x001d;
+pub const LANG_C_plus_plus_14 = 0x0021;
+pub const LANG_Fortran03 = 0x0022;
+pub const LANG_Fortran08 = 0x0023;
+pub const LANG_lo_user = 0x8000;
+pub const LANG_hi_user = 0xffff;
+pub const LANG_Mips_Assembler = 0x8001;
+pub const LANG_Upc = 0x8765;
+pub const LANG_HP_Bliss = 0x8003;
+pub const LANG_HP_Basic91 = 0x8004;
+pub const LANG_HP_Pascal91 = 0x8005;
+pub const LANG_HP_IMacro = 0x8006;
+pub const LANG_HP_Assembler = 0x8007;
diff --git a/std/event/future.zig b/std/event/future.zig
index 0f27b4131b..f5d14d1ca6 100644
--- a/std/event/future.zig
+++ b/std/event/future.zig
@@ -6,15 +6,20 @@ const AtomicOrder = builtin.AtomicOrder;
const Lock = std.event.Lock;
const Loop = std.event.Loop;
-/// This is a value that starts out unavailable, until a value is put().
+/// This is a value that starts out unavailable, until resolve() is called
/// While it is unavailable, coroutines suspend when they try to get() it,
-/// and then are resumed when the value is put().
-/// At this point the value remains forever available, and another put() is not allowed.
+/// and then are resumed when resolve() is called.
+/// At this point the value remains forever available, and another resolve() is not allowed.
pub fn Future(comptime T: type) type {
return struct {
lock: Lock,
data: T,
- available: u8, // TODO make this a bool
+
+ /// TODO make this an enum
+ /// 0 - not started
+ /// 1 - started
+ /// 2 - finished
+ available: u8,
const Self = this;
const Queue = std.atomic.Queue(promise);
@@ -31,7 +36,7 @@ pub fn Future(comptime T: type) type {
/// available.
/// Thread-safe.
pub async fn get(self: *Self) *T {
- if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) {
+ if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
return &self.data;
}
const held = await (async self.lock.acquire() catch unreachable);
@@ -43,18 +48,36 @@ pub fn Future(comptime T: type) type {
/// Gets the data without waiting for it. If it's available, a pointer is
/// returned. Otherwise, null is returned.
pub fn getOrNull(self: *Self) ?*T {
- if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) {
+ if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
return &self.data;
} else {
return null;
}
}
+ /// If someone else has started working on the data, wait for them to complete
+ /// and return a pointer to the data. Otherwise, return null, and the caller
+ /// should start working on the data.
+ /// It's not required to call start() before resolve() but it can be useful since
+ /// this method is thread-safe.
+ pub async fn start(self: *Self) ?*T {
+ const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
+ switch (state) {
+ 1 => {
+ const held = await (async self.lock.acquire() catch unreachable);
+ held.release();
+ return &self.data;
+ },
+ 2 => return &self.data,
+ else => unreachable,
+ }
+ }
+
/// Make the data become available. May be called only once.
/// Before calling this, modify the `data` property.
pub fn resolve(self: *Self) void {
- const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
- assert(prev == 0); // put() called twice
+ const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
+ assert(prev == 0 or prev == 1); // resolve() called twice
Lock.Held.release(Lock.Held{ .lock = &self.lock });
}
};
diff --git a/std/index.zig b/std/index.zig
index 3b523f519f..2f4cfb7553 100644
--- a/std/index.zig
+++ b/std/index.zig
@@ -36,6 +36,8 @@ pub const sort = @import("sort.zig");
pub const unicode = @import("unicode.zig");
pub const zig = @import("zig/index.zig");
+pub const lazyInit = @import("lazy_init.zig").lazyInit;
+
test "std" {
// run tests from these
_ = @import("atomic/index.zig");
@@ -71,4 +73,5 @@ test "std" {
_ = @import("sort.zig");
_ = @import("unicode.zig");
_ = @import("zig/index.zig");
+ _ = @import("lazy_init.zig");
}
diff --git a/std/lazy_init.zig b/std/lazy_init.zig
new file mode 100644
index 0000000000..c46c067810
--- /dev/null
+++ b/std/lazy_init.zig
@@ -0,0 +1,85 @@
+const std = @import("index.zig");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+const AtomicRmwOp = builtin.AtomicRmwOp;
+const AtomicOrder = builtin.AtomicOrder;
+
+/// Thread-safe initialization of global data.
+/// TODO use a mutex instead of a spinlock
+pub fn lazyInit(comptime T: type) LazyInit(T) {
+ return LazyInit(T){
+ .data = undefined,
+ .state = 0,
+ };
+}
+
+fn LazyInit(comptime T: type) type {
+ return struct {
+ state: u8, // TODO make this an enum
+ data: Data,
+
+ const Self = this;
+
+ // TODO this isn't working for void, investigate and then remove this special case
+ const Data = if (@sizeOf(T) == 0) u8 else T;
+ const Ptr = if (T == void) void else *T;
+
+ /// Returns a usable pointer to the initialized data,
+ /// or returns null, indicating that the caller should
+ /// perform the initialization and then call resolve().
+ pub fn get(self: *Self) ?Ptr {
+ while (true) {
+ var state = @cmpxchgWeak(u8, &self.state, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
+ switch (state) {
+ 0 => continue,
+ 1 => {
+ // TODO mutex instead of a spinlock
+ continue;
+ },
+ 2 => {
+ if (@sizeOf(T) == 0) {
+ return T(undefined);
+ } else {
+ return &self.data;
+ }
+ },
+ else => unreachable,
+ }
+ }
+ }
+
+ pub fn resolve(self: *Self) void {
+ const prev = @atomicRmw(u8, &self.state, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
+ assert(prev == 1); // resolve() called twice
+ }
+ };
+}
+
+var global_number = lazyInit(i32);
+
+test "std.lazyInit" {
+ if (global_number.get()) |_| @panic("bad") else {
+ global_number.data = 1234;
+ global_number.resolve();
+ }
+ if (global_number.get()) |x| {
+ assert(x.* == 1234);
+ } else {
+ @panic("bad");
+ }
+ if (global_number.get()) |x| {
+ assert(x.* == 1234);
+ } else {
+ @panic("bad");
+ }
+}
+
+var global_void = lazyInit(void);
+
+test "std.lazyInit(void)" {
+ if (global_void.get()) |_| @panic("bad") else {
+ global_void.resolve();
+ }
+ assert(global_void.get() != null);
+ assert(global_void.get() != null);
+}