aboutsummaryrefslogtreecommitdiff
path: root/std/debug.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-09-10 10:39:27 -0400
committerAndrew Kelley <andrew@ziglang.org>2019-09-10 10:39:27 -0400
commite657b73f30e3380b14caf3a115a4c7a97c510d77 (patch)
tree26c3f3b7a56f215b56c4e92cef5559dd5b1964b2 /std/debug.zig
parenta29ce78651c05029dbd72064752a099885edfd0c (diff)
parentff051f8f5de47f4c5033c61fb70a5c5260f34dff (diff)
downloadzig-e657b73f30e3380b14caf3a115a4c7a97c510d77.tar.gz
zig-e657b73f30e3380b14caf3a115a4c7a97c510d77.zip
Merge branch 'async-std-lib'
This introduces the concept of "IO mode" which is configurable by the root source file (e.g. next to `pub fn main`). Applications can put this in their root source file: ``` pub const io_mode = .evented; ``` This will populate `std.io.mode` to be `std.io.Mode.evented`. When I/O mode is evented, `std.os.read` handles EAGAIN by suspending until the file descriptor becomes available for reading. Although the std lib event loop supports epoll, kqueue, and Windows I/O Completion Ports, this integration with `std.os.read` currently only works on Linux. This integration is currently only hooked up to `std.os.read`, and not, for example, `std.os.write`, child processes, and timers. The fact that we can do this and still have a working master branch is thanks to Zig's lazy analysis, comptime, and inferred async. We can continue to make incremental progress on async std lib features, enabling more and more test cases and coverage. In addition to `std.io.mode` there is `std.io.is_async` which is equal to `std.io.mode == .evented`. In case I/O mode is async, `std.io.InStream` notices this and the read function pointer becomes an async function pointer rather than a blocking function pointer. Even in this case, `std.io.InStream` can *still be used as a blocking input stream*. Users of the API control whether it is blocking or async at runtime by whether or not the read function suspends. In case of file descriptors, for example, this might correspond to whether it was opened with `O_NONBLOCK`. The `noasync` keyword makes a function call or `await` assert that no suspension happens. This assertion has runtime safety enabled. `std.io.InStream`, in the case of async I/O, uses by default a 4 MiB frame size for calling the read function. If this is too large or too small, the application can globally increase the frame size used by declaring `pub const stack_size_std_io_InStream = 1234;` in their root source file. This way, `std.io.InStream` will only be generated once, avoiding bloat, and as long as this number is configured to be high enough, everything works fine. Zig has runtime safety to detect when `@asyncCall` is given too small of a buffer for the frame size. This merge introduces -fstack-report which can help identify large async function frame sizes and explain what is making them so big. Until #3069 is solved, it's recommended to stick with blocking IO mode. -fstack-report outputs JSON format, which can then be viewed in a GUI that represents the tree structure. As an example, Firefox does a decent job of this. One feature that is currently missing is detecting that the call stack upper bound is greater than the default for a given target, and passing this upper bound to the linker. As an example, if Zig detects that 20 MiB stack upper bound is needed - which would be quite reasonable - currently on Linux the application would only be given the default of 16 MiB. Unrelated miscellaneous change: added std.c.readv
Diffstat (limited to 'std/debug.zig')
-rw-r--r--std/debug.zig43
1 files changed, 30 insertions, 13 deletions
diff --git a/std/debug.zig b/std/debug.zig
index 68e6220a72..344396efa7 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -330,14 +330,16 @@ pub fn writeCurrentStackTraceWindows(
}
}
+/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
+/// make this `noasync fn` and remove the individual noasync calls.
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
if (windows.is_the_target) {
- return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color);
+ return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_color);
}
if (os.darwin.is_the_target) {
- return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color);
+ return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color);
}
- return printSourceAtAddressPosix(debug_info, out_stream, address, tty_color);
+ return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_color);
}
fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
@@ -793,7 +795,7 @@ fn printLineInfo(
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
}
} else |err| switch (err) {
- error.EndOfFile, error.FileNotFound => {},
+ error.EndOfFile, error.FileNotFound => {},
else => return err,
}
} else {
@@ -816,16 +818,18 @@ pub const OpenSelfDebugInfoError = error{
UnsupportedOperatingSystem,
};
+/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
+/// make this `noasync fn` and remove the individual noasync calls.
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
if (builtin.strip_debug_info)
return error.MissingDebugInfo;
if (windows.is_the_target) {
- return openSelfDebugInfoWindows(allocator);
+ return noasync openSelfDebugInfoWindows(allocator);
}
if (os.darwin.is_the_target) {
- return openSelfDebugInfoMacOs(allocator);
+ return noasync openSelfDebugInfoMacOs(allocator);
}
- return openSelfDebugInfoPosix(allocator);
+ return noasync openSelfDebugInfoPosix(allocator);
}
fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
@@ -1508,15 +1512,25 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
}
fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
+ // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
+ // `noasync` should be removed from all the function calls once it is fixed.
return FormValue{
.Const = Constant{
.signed = signed,
.payload = switch (size) {
- 1 => try in_stream.readIntLittle(u8),
- 2 => try in_stream.readIntLittle(u16),
- 4 => try in_stream.readIntLittle(u32),
- 8 => try in_stream.readIntLittle(u64),
- -1 => if (signed) @bitCast(u64, try leb.readILEB128(i64, in_stream)) else try leb.readULEB128(u64, in_stream),
+ 1 => try noasync in_stream.readIntLittle(u8),
+ 2 => try noasync in_stream.readIntLittle(u16),
+ 4 => try noasync in_stream.readIntLittle(u32),
+ 8 => try noasync in_stream.readIntLittle(u64),
+ -1 => blk: {
+ if (signed) {
+ const x = try noasync leb.readILEB128(i64, in_stream);
+ break :blk @bitCast(u64, x);
+ } else {
+ const x = try noasync leb.readULEB128(u64, in_stream);
+ break :blk x;
+ }
+ },
else => @compileError("Invalid size"),
},
},
@@ -1584,7 +1598,10 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_indirect => {
const child_form_id = try leb.readULEB128(u64, in_stream);
- return parseFormValue(allocator, in_stream, child_form_id, is_64);
+ const F = @typeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
+ var frame = try allocator.create(F);
+ defer allocator.destroy(frame);
+ return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
},
else => error.InvalidDebugInfo,
};