aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-08-04 15:19:03 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-08-04 15:19:03 -0400
commitb48948d6e805cdee7f33243098af9a862c152df1 (patch)
tree8b1b4b37670f7444e8fe12748a8db99ac7498cce /std
parentf804310d9f953c9d78a4271ba8d75133341840e6 (diff)
parent9bd8b01650f9cf21e601117951711b21aa5fd216 (diff)
downloadzig-b48948d6e805cdee7f33243098af9a862c152df1.tar.gz
zig-b48948d6e805cdee7f33243098af9a862c152df1.zip
Merge branch 'master' into llvm7
Diffstat (limited to 'std')
-rw-r--r--std/event/channel.zig8
-rw-r--r--std/event/future.zig12
-rw-r--r--std/event/group.zig4
-rw-r--r--std/event/lock.zig35
-rw-r--r--std/event/loop.zig14
-rw-r--r--std/event/tcp.zig8
-rw-r--r--std/fmt/index.zig9
-rw-r--r--std/os/index.zig26
-rw-r--r--std/os/linux/index.zig2
-rw-r--r--std/os/linux/test.zig4
-rw-r--r--std/os/windows/advapi32.zig5
-rw-r--r--std/os/windows/util.zig2
-rw-r--r--std/rand/index.zig9
-rw-r--r--std/zig/ast.zig12
-rw-r--r--std/zig/parse.zig33
-rw-r--r--std/zig/parser_test.zig8
-rw-r--r--std/zig/render.zig16
17 files changed, 86 insertions, 121 deletions
diff --git a/std/event/channel.zig b/std/event/channel.zig
index 03a036042b..71e97f6e78 100644
--- a/std/event/channel.zig
+++ b/std/event/channel.zig
@@ -71,10 +71,10 @@ pub fn Channel(comptime T: type) type {
/// puts a data item in the channel. The promise completes when the value has been added to the
/// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
pub async fn put(self: *SelfChannel, data: T) void {
- suspend |handle| {
+ suspend {
var my_tick_node = Loop.NextTickNode{
.next = undefined,
- .data = handle,
+ .data = @handle(),
};
var queue_node = std.atomic.Queue(PutNode).Node{
.data = PutNode{
@@ -96,10 +96,10 @@ pub fn Channel(comptime T: type) type {
// TODO integrate this function with named return values
// so we can get rid of this extra result copy
var result: T = undefined;
- suspend |handle| {
+ suspend {
var my_tick_node = Loop.NextTickNode{
.next = undefined,
- .data = handle,
+ .data = @handle(),
};
var queue_node = std.atomic.Queue(GetNode).Node{
.data = GetNode{
diff --git a/std/event/future.zig b/std/event/future.zig
index f5d14d1ca6..8abdce7d02 100644
--- a/std/event/future.zig
+++ b/std/event/future.zig
@@ -100,8 +100,8 @@ test "std.event.Future" {
}
async fn testFuture(loop: *Loop) void {
- suspend |p| {
- resume p;
+ suspend {
+ resume @handle();
}
var future = Future(i32).init(loop);
@@ -115,15 +115,15 @@ async fn testFuture(loop: *Loop) void {
}
async fn waitOnFuture(future: *Future(i32)) i32 {
- suspend |p| {
- resume p;
+ suspend {
+ resume @handle();
}
return (await (async future.get() catch @panic("memory"))).*;
}
async fn resolveFuture(future: *Future(i32)) void {
- suspend |p| {
- resume p;
+ suspend {
+ resume @handle();
}
future.data = 6;
future.resolve();
diff --git a/std/event/group.zig b/std/event/group.zig
index 26c098399e..6c7fc63699 100644
--- a/std/event/group.zig
+++ b/std/event/group.zig
@@ -54,10 +54,10 @@ pub fn Group(comptime ReturnType: type) type {
const S = struct {
async fn asyncFunc(node: **Stack.Node, args2: ...) ReturnType {
// TODO this is a hack to make the memory following be inside the coro frame
- suspend |p| {
+ suspend {
var my_node: Stack.Node = undefined;
node.* = &my_node;
- resume p;
+ resume @handle();
}
// TODO this allocation elision should be guaranteed because we await it in
diff --git a/std/event/lock.zig b/std/event/lock.zig
index 2013b5595f..c4cb1a3f0e 100644
--- a/std/event/lock.zig
+++ b/std/event/lock.zig
@@ -90,10 +90,10 @@ pub const Lock = struct {
}
pub async fn acquire(self: *Lock) Held {
- suspend |handle| {
+ suspend {
// TODO explicitly put this memory in the coroutine frame #1194
var my_tick_node = Loop.NextTickNode{
- .data = handle,
+ .data = @handle(),
.next = undefined,
};
@@ -106,35 +106,12 @@ pub const Lock = struct {
// will attempt to grab the lock.
_ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
- while (true) {
- const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
- if (old_bit != 0) {
- // We did not obtain the lock. Trust that our queue entry will resume us, and allow
- // suspend to complete.
- break;
- }
- // We got the lock. However we might have already been resumed from the queue.
+ const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
+ if (old_bit == 0) {
if (self.queue.get()) |node| {
// Whether this node is us or someone else, we tail resume it.
resume node.data;
- break;
- } else {
- // We already got resumed, and there are none left in the queue, which means that
- // we aren't even supposed to hold the lock right now.
- _ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
- _ = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
-
- // There might be a queue item. If we know the queue is empty, we can be done,
- // because the other actor will try to obtain the lock.
- // But if there's a queue item, we are the actor which must loop and attempt
- // to grab the lock again.
- if (@atomicLoad(u8, &self.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
- break;
- } else {
- continue;
- }
}
- unreachable;
}
}
@@ -164,8 +141,8 @@ test "std.event.Lock" {
async fn testLock(loop: *Loop, lock: *Lock) void {
// TODO explicitly put next tick node memory in the coroutine frame #1194
- suspend |p| {
- resume p;
+ suspend {
+ resume @handle();
}
const handle1 = async lockRunner(lock) catch @panic("out of memory");
var tick_node1 = Loop.NextTickNode{
diff --git a/std/event/loop.zig b/std/event/loop.zig
index 4e219653be..8b1b2e53db 100644
--- a/std/event/loop.zig
+++ b/std/event/loop.zig
@@ -331,11 +331,11 @@ pub const Loop = struct {
pub async fn waitFd(self: *Loop, fd: i32) !void {
defer self.removeFd(fd);
- suspend |p| {
+ suspend {
// TODO explicitly put this memory in the coroutine frame #1194
var resume_node = ResumeNode{
.id = ResumeNode.Id.Basic,
- .handle = p,
+ .handle = @handle(),
};
try self.addFd(fd, &resume_node);
}
@@ -417,11 +417,11 @@ pub const Loop = struct {
pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {
const S = struct {
async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
- suspend |p| {
- handle.* = p;
+ suspend {
+ handle.* = @handle();
var my_tick_node = Loop.NextTickNode{
.next = undefined,
- .data = p,
+ .data = @handle(),
};
loop.onNextTick(&my_tick_node);
}
@@ -439,10 +439,10 @@ pub const Loop = struct {
/// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
/// is performed.
pub async fn yield(self: *Loop) void {
- suspend |p| {
+ suspend {
var my_tick_node = Loop.NextTickNode{
.next = undefined,
- .data = p,
+ .data = @handle(),
};
self.onNextTick(&my_tick_node);
}
diff --git a/std/event/tcp.zig b/std/event/tcp.zig
index 416a8c07dc..ea803a9322 100644
--- a/std/event/tcp.zig
+++ b/std/event/tcp.zig
@@ -88,8 +88,8 @@ pub const Server = struct {
},
error.ProcessFdQuotaExceeded => {
errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
- suspend |p| {
- self.waiting_for_emfile_node = PromiseNode.init(p);
+ suspend {
+ self.waiting_for_emfile_node = PromiseNode.init( @handle() );
std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
}
continue;
@@ -141,8 +141,8 @@ test "listen on a port, send bytes, receive bytes" {
(await next_handler) catch |err| {
std.debug.panic("unable to handle connection: {}\n", err);
};
- suspend |p| {
- cancel p;
+ suspend {
+ cancel @handle();
}
}
async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: *const std.os.File) !void {
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
index 8daec50f17..f4f9efee37 100644
--- a/std/fmt/index.zig
+++ b/std/fmt/index.zig
@@ -248,6 +248,11 @@ pub fn formatIntValue(
return formatAsciiChar(value, context, Errors, output);
}
},
+ 'b' => {
+ radix = 2;
+ uppercase = false;
+ width = 0;
+ },
'd' => {
radix = 10;
uppercase = false;
@@ -875,6 +880,10 @@ test "fmt.format" {
try testFmt("u8: a\n", "u8: {c}\n", value);
}
{
+ const value: u8 = 0b1100;
+ try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
+ }
+ {
const value: [3]u8 = "abc";
try testFmt("array: abc\n", "array: {}\n", value);
try testFmt("array: abc\n", "array: {}\n", &value);
diff --git a/std/os/index.zig b/std/os/index.zig
index 77fd2a78ad..425a900a71 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -130,16 +130,10 @@ pub fn getRandomBytes(buf: []u8) !void {
try posixRead(fd, buf);
},
Os.windows => {
- var hCryptProv: windows.HCRYPTPROV = undefined;
- if (windows.CryptAcquireContextA(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => unexpectedErrorWindows(err),
- };
- }
- defer _ = windows.CryptReleaseContext(hCryptProv, 0);
-
- if (windows.CryptGenRandom(hCryptProv, @intCast(windows.DWORD, buf.len), buf.ptr) == 0) {
+ // Call RtlGenRandom() instead of CryptGetRandom() on Windows
+ // https://github.com/rust-lang-nursery/rand/issues/111
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
+ if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
const err = windows.GetLastError();
return switch (err) {
else => unexpectedErrorWindows(err),
@@ -159,8 +153,14 @@ pub fn getRandomBytes(buf: []u8) !void {
}
test "os.getRandomBytes" {
- var buf: [50]u8 = undefined;
- try getRandomBytes(buf[0..]);
+ var buf_a: [50]u8 = undefined;
+ var buf_b: [50]u8 = undefined;
+ // Call Twice
+ try getRandomBytes(buf_a[0..]);
+ try getRandomBytes(buf_b[0..]);
+
+ // Check if random (not 100% conclusive)
+ assert( !mem.eql(u8, buf_a, buf_b) );
}
/// Raises a signal in the current kernel thread, ending its execution.
@@ -2790,7 +2790,7 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
builtin.Os.macosx => {
var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int);
- const rc = posix.sysctlbyname(c"hw.ncpu", @ptrCast(*c_void, &count), &count_len, null, 0);
+ const rc = posix.sysctlbyname(c"hw.logicalcpu", @ptrCast(*c_void, &count), &count_len, null, 0);
const err = posix.getErrno(rc);
switch (err) {
0 => return @intCast(usize, count),
diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig
index 69bc30bad0..15607ea6c0 100644
--- a/std/os/linux/index.zig
+++ b/std/os/linux/index.zig
@@ -944,7 +944,7 @@ pub fn setgroups(size: usize, list: *const u32) usize {
}
pub fn getpid() i32 {
- return @bitCast(i32, u32(syscall0(SYS_getpid)));
+ return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
}
pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig
index e7dae3a584..4de26012c7 100644
--- a/std/os/linux/test.zig
+++ b/std/os/linux/test.zig
@@ -3,6 +3,10 @@ const builtin = @import("builtin");
const linux = std.os.linux;
const assert = std.debug.assert;
+test "getpid" {
+ assert(linux.getpid() != 0);
+}
+
test "timer" {
const epoll_fd = linux.epoll_create();
var err = linux.getErrno(epoll_fd);
diff --git a/std/os/windows/advapi32.zig b/std/os/windows/advapi32.zig
index dcb5a636ea..2f3195475c 100644
--- a/std/os/windows/advapi32.zig
+++ b/std/os/windows/advapi32.zig
@@ -28,3 +28,8 @@ pub extern "advapi32" stdcallcc fn RegOpenKeyExW(hKey: HKEY, lpSubKey: LPCWSTR,
pub extern "advapi32" stdcallcc fn RegQueryValueExW(hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,
lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,) LSTATUS;
+
+// RtlGenRandom is known as SystemFunction036 under advapi32
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
+pub extern "advapi32" stdcallcc fn SystemFunction036(output: [*]u8, length: usize) BOOL;
+pub const RtlGenRandom = SystemFunction036;
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
index dda9ce7a8b..c9d2c3c3e6 100644
--- a/std/os/windows/util.zig
+++ b/std/os/windows/util.zig
@@ -166,7 +166,7 @@ pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
}
test "InvalidDll" {
- if (builtin.os != builtin.Os.windows) return;
+ if (builtin.os != builtin.Os.windows) return error.SkipZigTest;
const DllName = "asdf.dll";
const allocator = std.debug.global_allocator;
diff --git a/std/rand/index.zig b/std/rand/index.zig
index 7daa558f13..2cbff049ea 100644
--- a/std/rand/index.zig
+++ b/std/rand/index.zig
@@ -30,7 +30,7 @@ pub const DefaultCsprng = Isaac64;
pub const Random = struct {
fillFn: fn (r: *Random, buf: []u8) void,
- /// Read random bytes into the specified buffer until fill.
+ /// Read random bytes into the specified buffer until full.
pub fn bytes(r: *Random, buf: []u8) void {
r.fillFn(r, buf);
}
@@ -48,10 +48,10 @@ pub const Random = struct {
}
}
- /// Get a random unsigned integer with even distribution between `start`
- /// inclusive and `end` exclusive.
+ /// Return a random integer with even distribution between `start`
+ /// inclusive and `end` exclusive. `start` must be less than `end`.
pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
- assert(start <= end);
+ assert(start < end);
if (T.is_signed) {
const uint = @IntType(false, T.bit_count);
if (start >= 0 and end >= 0) {
@@ -664,6 +664,7 @@ test "Random range" {
testRange(&prng.random, -4, 3);
testRange(&prng.random, -4, -1);
testRange(&prng.random, 10, 14);
+ // TODO: test that prng.random.range(1, 1) causes an assertion error
}
fn testRange(r: *Random, start: i32, end: i32) void {
diff --git a/std/zig/ast.zig b/std/zig/ast.zig
index 004f9278b9..95e899fb92 100644
--- a/std/zig/ast.zig
+++ b/std/zig/ast.zig
@@ -1778,19 +1778,12 @@ pub const Node = struct {
pub const Suspend = struct {
base: Node,
- label: ?TokenIndex,
suspend_token: TokenIndex,
- payload: ?*Node,
body: ?*Node,
pub fn iterate(self: *Suspend, index: usize) ?*Node {
var i = index;
- if (self.payload) |payload| {
- if (i < 1) return payload;
- i -= 1;
- }
-
if (self.body) |body| {
if (i < 1) return body;
i -= 1;
@@ -1800,7 +1793,6 @@ pub const Node = struct {
}
pub fn firstToken(self: *Suspend) TokenIndex {
- if (self.label) |label| return label;
return self.suspend_token;
}
@@ -1809,10 +1801,6 @@ pub const Node = struct {
return body.lastToken();
}
- if (self.payload) |payload| {
- return payload.lastToken();
- }
-
return self.suspend_token;
}
};
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
index 73d51e7870..fb49d2a2ba 100644
--- a/std/zig/parse.zig
+++ b/std/zig/parse.zig
@@ -852,19 +852,6 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
}) catch unreachable;
continue;
},
- Token.Id.Keyword_suspend => {
- const node = try arena.create(ast.Node.Suspend{
- .base = ast.Node{ .id = ast.Node.Id.Suspend },
- .label = ctx.label,
- .suspend_token = token_index,
- .payload = null,
- .body = null,
- });
- ctx.opt_ctx.store(&node.base);
- stack.append(State{ .SuspendBody = node }) catch unreachable;
- try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
- continue;
- },
Token.Id.Keyword_inline => {
stack.append(State{
.Inline = InlineCtx{
@@ -1415,10 +1402,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
State.SuspendBody => |suspend_node| {
- if (suspend_node.payload != null) {
- try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
+ const token = nextToken(&tok_it, &tree);
+ switch (token.ptr.id) {
+ Token.Id.Semicolon => {
+ prevToken(&tok_it, &tree);
+ continue;
+ },
+ Token.Id.LBrace => {
+ prevToken(&tok_it, &tree);
+ try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
+ continue;
+ },
+ else => {
+ ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = token.index } };
+ },
}
- continue;
},
State.AsyncAllocator => |async_node| {
if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
@@ -3086,15 +3084,12 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
Token.Id.Keyword_suspend => {
const node = try arena.create(ast.Node.Suspend{
.base = ast.Node{ .id = ast.Node.Id.Suspend },
- .label = null,
.suspend_token = token_index,
- .payload = null,
.body = null,
});
ctx.store(&node.base);
stack.append(State{ .SuspendBody = node }) catch unreachable;
- try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
return true;
},
Token.Id.Keyword_if => {
diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig
index 21259bec3c..582bffdf3d 100644
--- a/std/zig/parser_test.zig
+++ b/std/zig/parser_test.zig
@@ -898,11 +898,11 @@ test "zig fmt: union(enum(u32)) with assigned enum values" {
);
}
-test "zig fmt: labeled suspend" {
+test "zig fmt: resume from suspend block" {
try testCanonical(
\\fn foo() void {
- \\ s: suspend |p| {
- \\ break :s;
+ \\ suspend {
+ \\ resume @handle();
\\ }
\\}
\\
@@ -1784,7 +1784,7 @@ test "zig fmt: coroutines" {
\\ x += 1;
\\ suspend;
\\ x += 1;
- \\ suspend |p| {}
+ \\ suspend;
\\ const p: promise->void = async simpleAsyncFn() catch unreachable;
\\ await p;
\\}
diff --git a/std/zig/render.zig b/std/zig/render.zig
index bc45768fa3..868902a0d1 100644
--- a/std/zig/render.zig
+++ b/std/zig/render.zig
@@ -323,21 +323,7 @@ fn renderExpression(
ast.Node.Id.Suspend => {
const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
- if (suspend_node.label) |label| {
- try renderToken(tree, stream, label, indent, start_col, Space.None);
- try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
- }
-
- if (suspend_node.payload) |payload| {
- if (suspend_node.body) |body| {
- try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
- try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
- return renderExpression(allocator, stream, tree, indent, start_col, body, space);
- } else {
- try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
- return renderExpression(allocator, stream, tree, indent, start_col, payload, space);
- }
- } else if (suspend_node.body) |body| {
+ if (suspend_node.body) |body| {
try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, body, space);
} else {