authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-09 09:09:04+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-09 09:09:04+01:00
log3b515fbede945a2927d5aba59212553a8b26b944
tree76f7583b67d1e817efb0d2f401836d9a229aaf83
parent6be202f46633d02e20d0f068a32296113ecb95ca
parent80625990d5ce82b781de54c4587b489cbd2cd55f

Merge pull request 'std.Io: move netReceive to become an Operation' (#31089) from net-receive into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31089

45 files changed, 517 insertions(+), 487 deletions(-)

lib/compiler/test_runner.zig+1-1
...@@ -17,7 +17,7 @@ var fba: std.heap.FixedBufferAllocator = .init(&fba_buffer);...@@ -17,7 +17,7 @@ var fba: std.heap.FixedBufferAllocator = .init(&fba_buffer);
17var fba_buffer: [8192]u8 = undefined;17var fba_buffer: [8192]u8 = undefined;
18var stdin_buffer: [4096]u8 = undefined;18var stdin_buffer: [4096]u8 = undefined;
19var stdout_buffer: [4096]u8 = undefined;19var stdout_buffer: [4096]u8 = undefined;
20const runner_threaded_io: Io = Io.Threaded.global_single_threaded.ioBasic();20const runner_threaded_io: Io = Io.Threaded.global_single_threaded.io();
2121
22/// Keep in sync with logic in `std.Build.addRunArtifact` which decides whether22/// Keep in sync with logic in `std.Build.addRunArtifact` which decides whether
23/// the test runner will communicate with the build runner via `std.zig.Server`.23/// the test runner will communicate with the build runner via `std.zig.Server`.
lib/compiler_rt.zig+1-1
...@@ -17,7 +17,7 @@ else...@@ -17,7 +17,7 @@ else
17 null;17 null;
1818
19pub const std_options_debug_io: std.Io = if (builtin.is_test)19pub const std_options_debug_io: std.Io = if (builtin.is_test)
20 std.Io.Threaded.global_single_threaded.ioBasic()20 std.Io.Threaded.global_single_threaded.io()
21else21else
22 unreachable;22 unreachable;
2323
lib/fuzzer.zig+1-1
...@@ -13,7 +13,7 @@ pub const std_options = std.Options{...@@ -13,7 +13,7 @@ pub const std_options = std.Options{
13 .logFn = logOverride,13 .logFn = logOverride,
14};14};
1515
16const io = std.Io.Threaded.global_single_threaded.ioBasic();16const io = std.Io.Threaded.global_single_threaded.io();
1717
18fn logOverride(18fn logOverride(
19 comptime level: std.log.Level,19 comptime level: std.log.Level,
lib/std/Io.zig+44-2
...@@ -243,7 +243,6 @@ pub const VTable = struct {...@@ -243,7 +243,6 @@ pub const VTable = struct {
243 netConnectUnix: *const fn (?*anyopaque, *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle,243 netConnectUnix: *const fn (?*anyopaque, *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle,
244 netSocketCreatePair: *const fn (?*anyopaque, net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket,244 netSocketCreatePair: *const fn (?*anyopaque, net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket,
245 netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) struct { ?net.Socket.SendError, usize },245 netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) struct { ?net.Socket.SendError, usize },
246 netReceive: *const fn (?*anyopaque, net.Socket.Handle, message_buffer: []net.IncomingMessage, data_buffer: []u8, net.ReceiveFlags, Timeout) struct { ?net.Socket.ReceiveTimeoutError, usize },
247 /// Returns 0 on end of stream.246 /// Returns 0 on end of stream.
248 netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,247 netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,
249 netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,248 netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
...@@ -261,6 +260,7 @@ pub const Operation = union(enum) {...@@ -261,6 +260,7 @@ pub const Operation = union(enum) {
261 /// On Windows this is NtDeviceIoControlFile. On POSIX this is ioctl. On260 /// On Windows this is NtDeviceIoControlFile. On POSIX this is ioctl. On
262 /// other systems this tag is unreachable.261 /// other systems this tag is unreachable.
263 device_io_control: DeviceIoControl,262 device_io_control: DeviceIoControl,
263 net_receive: NetReceive,
264264
265 pub const Tag = @typeInfo(Operation).@"union".tag_type.?;265 pub const Tag = @typeInfo(Operation).@"union".tag_type.?;
266266
...@@ -350,6 +350,35 @@ pub const Operation = union(enum) {...@@ -350,6 +350,35 @@ pub const Operation = union(enum) {
350 },350 },
351 };351 };
352352
353 pub const NetReceive = struct {
354 socket_handle: net.Socket.Handle,
355 message_buffer: []net.IncomingMessage,
356 data_buffer: []u8,
357 flags: net.ReceiveFlags,
358
359 pub const Error = error{
360 /// Insufficient memory or other resource internal to the operating system.
361 SystemResources,
362 /// Per-process limit on the number of open file descriptors has been reached.
363 ProcessFdQuotaExceeded,
364 /// System-wide limit on the total number of open files has been reached.
365 SystemFdQuotaExceeded,
366 /// Local end has been shut down on a connection-oriented socket, or
367 /// the socket was never connected.
368 SocketUnconnected,
369 /// The socket type requires that message be sent atomically, and the
370 /// size of the message to be sent made this impossible. The message
371 /// was not transmitted, or was partially transmitted.
372 MessageOversize,
373 /// Network connection was unexpectedly closed by sender.
374 ConnectionResetByPeer,
375 /// The local network interface used to reach the destination is offline.
376 NetworkDown,
377 } || Io.UnexpectedError;
378
379 pub const Result = struct { ?net.Socket.ReceiveError, usize };
380 };
381
353 pub const Result = Result: {382 pub const Result = Result: {
354 const operation_fields = @typeInfo(Operation).@"union".fields;383 const operation_fields = @typeInfo(Operation).@"union".fields;
355 var field_names: [operation_fields.len][]const u8 = undefined;384 var field_names: [operation_fields.len][]const u8 = undefined;
...@@ -417,6 +446,19 @@ pub fn operate(io: Io, operation: Operation) Cancelable!Operation.Result {...@@ -417,6 +446,19 @@ pub fn operate(io: Io, operation: Operation) Cancelable!Operation.Result {
417 return io.vtable.operate(io.userdata, operation);446 return io.vtable.operate(io.userdata, operation);
418}447}
419448
449pub const OperateTimeoutError = Cancelable || Timeout.Error || ConcurrentError;
450
451/// Performs one `Operation` with provided `timeout`.
452pub fn operateTimeout(io: Io, operation: Operation, timeout: Timeout) OperateTimeoutError!Operation.Result {
453 var storage: [1]Operation.Storage = undefined;
454 var batch: Batch = .init(&storage);
455 batch.addAt(0, operation);
456 try batch.awaitConcurrent(io, timeout);
457 const completion = batch.next().?;
458 assert(completion.index == 0);
459 return completion.result;
460}
461
420/// Submits many operations together without waiting for all of them to462/// Submits many operations together without waiting for all of them to
421/// complete.463/// complete.
422///464///
...@@ -1716,7 +1758,7 @@ pub const Event = enum(u32) {...@@ -1716,7 +1758,7 @@ pub const Event = enum(u32) {
1716 }1758 }
17171759
1718 /// Blocks until the logical boolean is `true`.1760 /// Blocks until the logical boolean is `true`.
1719 pub fn wait(event: *Event, io: Io) Io.Cancelable!void {1761 pub fn wait(event: *Event, io: Io) Cancelable!void {
1720 if (@cmpxchgStrong(Event, event, .unset, .waiting, .acquire, .acquire)) |prev| switch (prev) {1762 if (@cmpxchgStrong(Event, event, .unset, .waiting, .acquire, .acquire)) |prev| switch (prev) {
1721 .unset => unreachable,1763 .unset => unreachable,
1722 .waiting => {},1764 .waiting => {},
lib/std/Io/Dispatch.zig+3-19
...@@ -459,7 +459,6 @@ pub fn io(ev: *Evented) Io {...@@ -459,7 +459,6 @@ pub fn io(ev: *Evented) Io {
459 .netConnectUnix = netConnectUnixUnavailable,459 .netConnectUnix = netConnectUnixUnavailable,
460 .netSocketCreatePair = netSocketCreatePairUnavailable,460 .netSocketCreatePair = netSocketCreatePairUnavailable,
461 .netSend = netSendUnavailable,461 .netSend = netSendUnavailable,
462 .netReceive = netReceiveUnavailable,
463 .netRead = netReadUnavailable,462 .netRead = netReadUnavailable,
464 .netWrite = netWriteUnavailable,463 .netWrite = netWriteUnavailable,
465 .netWriteFile = netWriteFileUnavailable,464 .netWriteFile = netWriteFileUnavailable,
...@@ -1714,6 +1713,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -1714,6 +1713,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
1714 },1713 },
1715 },1714 },
1716 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },1715 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },
1716 .net_receive => @panic("TODO implement net_receive operation"),
1717 }1717 }
1718}1718}
17191719
...@@ -2134,6 +2134,7 @@ fn batchDrainSubmitted(...@@ -2134,6 +2134,7 @@ fn batchDrainSubmitted(
2134 break :result null;2134 break :result null;
2135 },2135 },
2136 .device_io_control => {},2136 .device_io_control => {},
2137 .net_receive => @panic("TODO implement batched net_receive"),
2137 };2138 };
2138 if (concurrency) return error.ConcurrencyUnavailable;2139 if (concurrency) return error.ConcurrencyUnavailable;
2139 break :result try operate(ev, storage.submission.operation);2140 break :result try operate(ev, storage.submission.operation);
...@@ -2192,6 +2193,7 @@ fn batchSourceEvent(context: ?*anyopaque) callconv(.c) void {...@@ -2192,6 +2193,7 @@ fn batchSourceEvent(context: ?*anyopaque) callconv(.c) void {
2192 } };2193 } };
2193 },2194 },
2194 .device_io_control => unreachable,2195 .device_io_control => unreachable,
2196 .net_receive => @panic("TODO implement batched net_receive"),
2195 };2197 };
21962198
2197 switch (pending.node.prev) {2199 switch (pending.node.prev) {
...@@ -4872,24 +4874,6 @@ fn netSendUnavailable(...@@ -4872,24 +4874,6 @@ fn netSendUnavailable(
4872 return .{ error.NetworkDown, 0 };4874 return .{ error.NetworkDown, 0 };
4873}4875}
48744876
4875fn netReceiveUnavailable(
4876 userdata: ?*anyopaque,
4877 handle: net.Socket.Handle,
4878 message_buffer: []net.IncomingMessage,
4879 data_buffer: []u8,
4880 flags: net.ReceiveFlags,
4881 timeout: Io.Timeout,
4882) struct { ?net.Socket.ReceiveTimeoutError, usize } {
4883 const ev: *Evented = @ptrCast(@alignCast(userdata));
4884 _ = ev;
4885 _ = handle;
4886 _ = message_buffer;
4887 _ = data_buffer;
4888 _ = flags;
4889 _ = timeout;
4890 return .{ error.NetworkDown, 0 };
4891}
4892
4893fn netReadUnavailable(4877fn netReadUnavailable(
4894 userdata: ?*anyopaque,4878 userdata: ?*anyopaque,
4895 fd: net.Socket.Handle,4879 fd: net.Socket.Handle,
lib/std/Io/Threaded.zig+309-295
...@@ -61,7 +61,7 @@ disable_memory_mapping: bool,...@@ -61,7 +61,7 @@ disable_memory_mapping: bool,
6161
62stderr_writer: File.Writer = .{62stderr_writer: File.Writer = .{
63 .io = undefined,63 .io = undefined,
64 .interface = Io.File.Writer.initInterface(&.{}),64 .interface = File.Writer.initInterface(&.{}),
65 .file = if (is_windows) undefined else .stderr(),65 .file = if (is_windows) undefined else .stderr(),
66 .mode = .streaming,66 .mode = .streaming,
67},67},
...@@ -160,7 +160,7 @@ pub const Environ = struct {...@@ -160,7 +160,7 @@ pub const Environ = struct {
160 },160 },
161 };161 };
162162
163 pub fn scan(environ: *Environ, allocator: std.mem.Allocator) void {163 pub fn scan(environ: *Environ, allocator: Allocator) void {
164 if (is_windows) {164 if (is_windows) {
165 // This value expires with any call that modifies the environment,165 // This value expires with any call that modifies the environment,
166 // which is outside of this Io implementation's control, so references166 // which is outside of this Io implementation's control, so references
...@@ -1901,10 +1901,6 @@ pub fn io(t: *Threaded) Io {...@@ -1901,10 +1901,6 @@ pub fn io(t: *Threaded) Io {
1901 .windows => netSendWindows,1901 .windows => netSendWindows,
1902 else => netSendPosix,1902 else => netSendPosix,
1903 },1903 },
1904 .netReceive = switch (native_os) {
1905 .windows => netReceiveWindows,
1906 else => netReceivePosix,
1907 },
1908 .netInterfaceNameResolve = netInterfaceNameResolve,1904 .netInterfaceNameResolve = netInterfaceNameResolve,
1909 .netInterfaceName = netInterfaceName,1905 .netInterfaceName = netInterfaceName,
1910 .netLookup = netLookup,1906 .netLookup = netLookup,
...@@ -1912,143 +1908,10 @@ pub fn io(t: *Threaded) Io {...@@ -1912,143 +1908,10 @@ pub fn io(t: *Threaded) Io {
1912 };1908 };
1913}1909}
19141910
1915/// Same as `io` but disables all networking functionality, which has
1916/// an additional dependency on Windows (ws2_32).
1917pub fn ioBasic(t: *Threaded) Io {
1918 return .{
1919 .userdata = t,
1920 .vtable = &.{
1921 .crashHandler = crashHandler,
1922
1923 .async = async,
1924 .concurrent = concurrent,
1925 .await = await,
1926 .cancel = cancel,
1927
1928 .groupAsync = groupAsync,
1929 .groupConcurrent = groupConcurrent,
1930 .groupAwait = groupAwait,
1931 .groupCancel = groupCancel,
1932
1933 .recancel = recancel,
1934 .swapCancelProtection = swapCancelProtection,
1935 .checkCancel = checkCancel,
1936
1937 .futexWait = futexWait,
1938 .futexWaitUncancelable = futexWaitUncancelable,
1939 .futexWake = futexWake,
1940
1941 .operate = operate,
1942 .batchAwaitAsync = batchAwaitAsync,
1943 .batchAwaitConcurrent = batchAwaitConcurrent,
1944 .batchCancel = batchCancel,
1945
1946 .dirCreateDir = dirCreateDir,
1947 .dirCreateDirPath = dirCreateDirPath,
1948 .dirCreateDirPathOpen = dirCreateDirPathOpen,
1949 .dirStat = dirStat,
1950 .dirStatFile = dirStatFile,
1951 .dirAccess = dirAccess,
1952 .dirCreateFile = dirCreateFile,
1953 .dirCreateFileAtomic = dirCreateFileAtomic,
1954 .dirOpenFile = dirOpenFile,
1955 .dirOpenDir = dirOpenDir,
1956 .dirClose = dirClose,
1957 .dirRead = dirRead,
1958 .dirRealPath = dirRealPath,
1959 .dirRealPathFile = dirRealPathFile,
1960 .dirDeleteFile = dirDeleteFile,
1961 .dirDeleteDir = dirDeleteDir,
1962 .dirRename = dirRename,
1963 .dirRenamePreserve = dirRenamePreserve,
1964 .dirSymLink = dirSymLink,
1965 .dirReadLink = dirReadLink,
1966 .dirSetOwner = dirSetOwner,
1967 .dirSetFileOwner = dirSetFileOwner,
1968 .dirSetPermissions = dirSetPermissions,
1969 .dirSetFilePermissions = dirSetFilePermissions,
1970 .dirSetTimestamps = dirSetTimestamps,
1971 .dirHardLink = dirHardLink,
1972
1973 .fileStat = fileStat,
1974 .fileLength = fileLength,
1975 .fileClose = fileClose,
1976 .fileWritePositional = fileWritePositional,
1977 .fileWriteFileStreaming = fileWriteFileStreaming,
1978 .fileWriteFilePositional = fileWriteFilePositional,
1979 .fileReadPositional = fileReadPositional,
1980 .fileSeekBy = fileSeekBy,
1981 .fileSeekTo = fileSeekTo,
1982 .fileSync = fileSync,
1983 .fileIsTty = fileIsTty,
1984 .fileEnableAnsiEscapeCodes = fileEnableAnsiEscapeCodes,
1985 .fileSupportsAnsiEscapeCodes = fileSupportsAnsiEscapeCodes,
1986 .fileSetLength = fileSetLength,
1987 .fileSetOwner = fileSetOwner,
1988 .fileSetPermissions = fileSetPermissions,
1989 .fileSetTimestamps = fileSetTimestamps,
1990 .fileLock = fileLock,
1991 .fileTryLock = fileTryLock,
1992 .fileUnlock = fileUnlock,
1993 .fileDowngradeLock = fileDowngradeLock,
1994 .fileRealPath = fileRealPath,
1995 .fileHardLink = fileHardLink,
1996
1997 .fileMemoryMapCreate = fileMemoryMapCreate,
1998 .fileMemoryMapDestroy = fileMemoryMapDestroy,
1999 .fileMemoryMapSetLength = fileMemoryMapSetLength,
2000 .fileMemoryMapRead = fileMemoryMapRead,
2001 .fileMemoryMapWrite = fileMemoryMapWrite,
2002
2003 .processExecutableOpen = processExecutableOpen,
2004 .processExecutablePath = processExecutablePath,
2005 .lockStderr = lockStderr,
2006 .tryLockStderr = tryLockStderr,
2007 .unlockStderr = unlockStderr,
2008 .processCurrentPath = processCurrentPath,
2009 .processSetCurrentDir = processSetCurrentDir,
2010 .processSetCurrentPath = processSetCurrentPath,
2011 .processReplace = processReplace,
2012 .processReplacePath = processReplacePath,
2013 .processSpawn = processSpawn,
2014 .processSpawnPath = processSpawnPath,
2015 .childWait = childWait,
2016 .childKill = childKill,
2017
2018 .progressParentFile = progressParentFile,
2019
2020 .now = now,
2021 .clockResolution = clockResolution,
2022 .sleep = sleep,
2023
2024 .random = random,
2025 .randomSecure = randomSecure,
2026
2027 .netListenIp = netListenIpUnavailable,
2028 .netListenUnix = netListenUnixUnavailable,
2029 .netAccept = netAcceptUnavailable,
2030 .netBindIp = netBindIpUnavailable,
2031 .netConnectIp = netConnectIpUnavailable,
2032 .netSocketCreatePair = netSocketCreatePairUnavailable,
2033 .netConnectUnix = netConnectUnixUnavailable,
2034 .netClose = netCloseUnavailable,
2035 .netShutdown = netShutdownUnavailable,
2036 .netRead = netReadUnavailable,
2037 .netWrite = netWriteUnavailable,
2038 .netWriteFile = netWriteFileUnavailable,
2039 .netSend = netSendUnavailable,
2040 .netReceive = netReceiveUnavailable,
2041 .netInterfaceNameResolve = netInterfaceNameResolveUnavailable,
2042 .netInterfaceName = netInterfaceNameUnavailable,
2043 .netLookup = netLookupUnavailable,
2044 },
2045 };
2046}
2047
2048pub const socket_flags_unsupported = is_darwin or native_os == .haiku;1911pub const socket_flags_unsupported = is_darwin or native_os == .haiku;
2049const have_accept4 = !socket_flags_unsupported;1912const have_accept4 = !socket_flags_unsupported;
2050const have_flock_open_flags = @hasField(posix.O, "EXLOCK");1913const have_flock_open_flags = @hasField(posix.O, "EXLOCK");
2051const have_networking = native_os != .wasi;1914const have_networking = std.options.networking and native_os != .wasi;
2052const have_flock = @TypeOf(posix.system.flock) != void;1915const have_flock = @TypeOf(posix.system.flock) != void;
2053const have_sendmmsg = native_os == .linux;1916const have_sendmmsg = native_os == .linux;
2054const have_futex = switch (builtin.cpu.arch) {1917const have_futex = switch (builtin.cpu.arch) {
...@@ -2600,7 +2463,7 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io....@@ -2600,7 +2463,7 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.
2600 return;2463 return;
2601 }2464 }
2602 const t: *Threaded = @ptrCast(@alignCast(userdata));2465 const t: *Threaded = @ptrCast(@alignCast(userdata));
2603 const t_io = ioBasic(t);2466 const t_io = io(t);
2604 const timeout_ns: ?u64 = ns: {2467 const timeout_ns: ?u64 = ns: {
2605 const d = timeout.toDurationFromNow(t_io) orelse break :ns null;2468 const d = timeout.toDurationFromNow(t_io) orelse break :ns null;
2606 break :ns std.math.lossyCast(u64, d.raw.toNanoseconds());2469 break :ns std.math.lossyCast(u64, d.raw.toNanoseconds());
...@@ -2638,13 +2501,23 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2638,13 +2501,23 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2638 },2501 },
2639 },2502 },
2640 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },2503 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },
2504 .net_receive => |*o| return .{ .net_receive = o: {
2505 if (!have_networking) break :o .{ error.NetworkDown, 0 };
2506 if (is_windows) break :o netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags);
2507 netReceivePosix(o.socket_handle, &o.message_buffer[0], o.data_buffer, o.flags, false) catch |err| switch (err) {
2508 error.Canceled => |e| return e,
2509 error.WouldBlock => unreachable,
2510 else => |e| break :o .{ e, 0 },
2511 };
2512 break :o .{ null, 1 };
2513 } },
2641 }2514 }
2642}2515}
26432516
2644fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {2517fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2645 const t: *Threaded = @ptrCast(@alignCast(userdata));2518 const t: *Threaded = @ptrCast(@alignCast(userdata));
2646 if (is_windows) {2519 if (is_windows) {
2647 batchDrainSubmittedWindows(b, false) catch |err| switch (err) {2520 batchDrainSubmittedWindows(t, b, false) catch |err| switch (err) {
2648 error.ConcurrencyUnavailable => unreachable, // passed concurrency=false2521 error.ConcurrencyUnavailable => unreachable, // passed concurrency=false
2649 else => |e| return e,2522 else => |e| return e,
2650 };2523 };
...@@ -2662,11 +2535,19 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {...@@ -2662,11 +2535,19 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2662 const submission = &b.storage[index.toIndex()].submission;2535 const submission = &b.storage[index.toIndex()].submission;
2663 switch (submission.operation) {2536 switch (submission.operation) {
2664 .file_read_streaming => |o| {2537 .file_read_streaming => |o| {
2665 poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.IN, .revents = 0 };2538 poll_buffer[poll_len] = .{
2539 .fd = o.file.handle,
2540 .events = posix.POLL.IN | posix.POLL.ERR,
2541 .revents = 0,
2542 };
2666 poll_len += 1;2543 poll_len += 1;
2667 },2544 },
2668 .file_write_streaming => |o| {2545 .file_write_streaming => |o| {
2669 poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.OUT, .revents = 0 };2546 poll_buffer[poll_len] = .{
2547 .fd = o.file.handle,
2548 .events = posix.POLL.OUT | posix.POLL.ERR,
2549 .revents = 0,
2550 };
2670 poll_len += 1;2551 poll_len += 1;
2671 },2552 },
2672 .device_io_control => |o| {2553 .device_io_control => |o| {
...@@ -2677,6 +2558,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {...@@ -2677,6 +2558,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2677 };2558 };
2678 poll_len += 1;2559 poll_len += 1;
2679 },2560 },
2561 .net_receive => |*o| {
2562 poll_buffer[poll_len] = .{
2563 .fd = o.socket_handle,
2564 .events = posix.POLL.IN | posix.POLL.ERR,
2565 .revents = 0,
2566 };
2567 poll_len += 1;
2568 },
2680 }2569 }
2681 index = submission.node.next;2570 index = submission.node.next;
2682 }2571 }
...@@ -2767,8 +2656,8 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {...@@ -2767,8 +2656,8 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2767fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.AwaitConcurrentError!void {2656fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.AwaitConcurrentError!void {
2768 const t: *Threaded = @ptrCast(@alignCast(userdata));2657 const t: *Threaded = @ptrCast(@alignCast(userdata));
2769 if (is_windows) {2658 if (is_windows) {
2770 const deadline: ?Io.Clock.Timestamp = timeout.toTimestamp(ioBasic(t));2659 const deadline: ?Io.Clock.Timestamp = timeout.toTimestamp(io(t));
2771 try batchDrainSubmittedWindows(b, true);2660 try batchDrainSubmittedWindows(t, b, true);
2772 while (b.pending.head != .none and b.completed.head == .none) {2661 while (b.pending.head != .none and b.completed.head == .none) {
2773 var delay_interval: windows.LARGE_INTEGER = interval: {2662 var delay_interval: windows.LARGE_INTEGER = interval: {
2774 const d = deadline orelse break :interval std.math.minInt(windows.LARGE_INTEGER);2663 const d = deadline orelse break :interval std.math.minInt(windows.LARGE_INTEGER);
...@@ -2796,12 +2685,12 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2796,12 +2685,12 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2796 if (!have_poll) return error.ConcurrencyUnavailable;2685 if (!have_poll) return error.ConcurrencyUnavailable;
2797 var poll_buffer: [poll_buffer_len]posix.pollfd = undefined;2686 var poll_buffer: [poll_buffer_len]posix.pollfd = undefined;
2798 var poll_storage: struct {2687 var poll_storage: struct {
2799 gpa: std.mem.Allocator,2688 gpa: Allocator,
2800 batch: *Io.Batch,2689 batch: *Io.Batch,
2801 slice: []posix.pollfd,2690 slice: []posix.pollfd,
2802 len: u32,2691 len: u32,
28032692
2804 fn add(storage: *@This(), file: Io.File, events: @FieldType(posix.pollfd, "events")) Io.ConcurrentError!void {2693 fn add(storage: *@This(), fd: File.Handle, events: @FieldType(posix.pollfd, "events")) Io.ConcurrentError!void {
2805 const len = storage.len;2694 const len = storage.len;
2806 if (len == poll_buffer_len) {2695 if (len == poll_buffer_len) {
2807 const slice: []posix.pollfd = if (storage.batch.userdata) |batch_userdata|2696 const slice: []posix.pollfd = if (storage.batch.userdata) |batch_userdata|
...@@ -2816,7 +2705,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2816,7 +2705,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2816 storage.slice = slice;2705 storage.slice = slice;
2817 }2706 }
2818 storage.slice[len] = .{2707 storage.slice[len] = .{
2819 .fd = file.handle,2708 .fd = fd,
2820 .events = events,2709 .events = events,
2821 .revents = 0,2710 .revents = 0,
2822 };2711 };
...@@ -2826,18 +2715,41 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2826,18 +2715,41 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2826 {2715 {
2827 var index = b.submitted.head;2716 var index = b.submitted.head;
2828 while (index != .none) {2717 while (index != .none) {
2829 const submission = &b.storage[index.toIndex()].submission;2718 const storage = &b.storage[index.toIndex()];
2719 const submission = storage.submission;
2830 switch (submission.operation) {2720 switch (submission.operation) {
2831 .file_read_streaming => |o| try poll_storage.add(o.file, posix.POLL.IN),2721 .file_read_streaming => |o| try poll_storage.add(o.file.handle, posix.POLL.IN | posix.POLL.ERR),
2832 .file_write_streaming => |o| try poll_storage.add(o.file, posix.POLL.OUT),2722 .file_write_streaming => |o| try poll_storage.add(o.file.handle, posix.POLL.OUT | posix.POLL.ERR),
2833 .device_io_control => |o| try poll_storage.add(o.file, posix.POLL.IN | posix.POLL.OUT | posix.POLL.ERR),2723 .device_io_control => |o| try poll_storage.add(o.file.handle, posix.POLL.IN | posix.POLL.OUT | posix.POLL.ERR),
2724 .net_receive => |*o| nb: {
2725 var data_i: usize = 0;
2726 const result: Io.Operation.Result = .{ .net_receive = for (o.message_buffer, 0..) |*msg, msg_i| {
2727 const remaining_data_buffer = o.data_buffer[data_i..];
2728 netReceivePosix(o.socket_handle, msg, remaining_data_buffer, o.flags, true) catch |err| switch (err) {
2729 error.Canceled => |e| return e,
2730 error.WouldBlock => {
2731 if (msg_i != 0) break .{ null, msg_i };
2732 try poll_storage.add(o.socket_handle, posix.POLL.IN | posix.POLL.ERR);
2733 break :nb;
2734 },
2735 else => |e| break .{ e, 0 },
2736 };
2737 data_i += msg.data.len;
2738 } else .{ null, o.message_buffer.len } };
2739 switch (b.completed.tail) {
2740 .none => b.completed.head = index,
2741 else => |tail_index| b.storage[tail_index.toIndex()].completion.node.next = index,
2742 }
2743 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2744 b.completed.tail = index;
2745 },
2834 }2746 }
2835 index = submission.node.next;2747 index = submission.node.next;
2836 }2748 }
2837 }2749 }
2838 switch (poll_storage.len) {2750 switch (poll_storage.len) {
2839 0 => return,2751 0 => return,
2840 1 => if (timeout == .none) {2752 1 => if (timeout == .none and b.completed.head == .none) {
2841 const index = b.submitted.head;2753 const index = b.submitted.head;
2842 const storage = &b.storage[index.toIndex()];2754 const storage = &b.storage[index.toIndex()];
2843 const result = try operate(t, storage.submission.operation);2755 const result = try operate(t, storage.submission.operation);
...@@ -2854,7 +2766,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2854,7 +2766,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2854 },2766 },
2855 else => {},2767 else => {},
2856 }2768 }
2857 const t_io = ioBasic(t);2769 const t_io = io(t);
2858 const deadline = timeout.toTimestamp(t_io);2770 const deadline = timeout.toTimestamp(t_io);
2859 while (true) {2771 while (true) {
2860 const timeout_ms: i32 = t: {2772 const timeout_ms: i32 = t: {
...@@ -2961,6 +2873,31 @@ fn batchCancel(userdata: ?*anyopaque, b: *Io.Batch) void {...@@ -2961,6 +2873,31 @@ fn batchCancel(userdata: ?*anyopaque, b: *Io.Batch) void {
2961 }2873 }
2962}2874}
29632875
2876fn batchCompleteBlockingWindows(
2877 b: *Io.Batch,
2878 operation_userdata: *WindowsBatchOperationUserdata,
2879 result: Io.Operation.Result,
2880) void {
2881 const erased_userdata = operation_userdata.toErased();
2882 const pending: *Io.Operation.Storage.Pending = @fieldParentPtr("userdata", erased_userdata);
2883 switch (pending.node.prev) {
2884 .none => b.pending.head = pending.node.next,
2885 else => |prev_index| b.storage[prev_index.toIndex()].pending.node.next = pending.node.next,
2886 }
2887 switch (pending.node.next) {
2888 .none => b.pending.tail = pending.node.prev,
2889 else => |next_index| b.storage[next_index.toIndex()].pending.node.prev = pending.node.prev,
2890 }
2891 const storage: *Io.Operation.Storage = @fieldParentPtr("pending", pending);
2892 const index: Io.Operation.OptionalIndex = .fromIndex(storage - b.storage.ptr);
2893 switch (b.completed.tail) {
2894 .none => b.completed.head = index,
2895 else => |tail_index| b.storage[tail_index.toIndex()].completion.node.next = index,
2896 }
2897 b.completed.tail = index;
2898 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2899}
2900
2964fn batchApc(2901fn batchApc(
2965 apc_context: ?*anyopaque,2902 apc_context: ?*anyopaque,
2966 iosb: *windows.IO_STATUS_BLOCK,2903 iosb: *windows.IO_STATUS_BLOCK,
...@@ -3000,6 +2937,7 @@ fn batchApc(...@@ -3000,6 +2937,7 @@ fn batchApc(
3000 .file_read_streaming => .{ .file_read_streaming = ntReadFileResult(iosb) },2937 .file_read_streaming => .{ .file_read_streaming = ntReadFileResult(iosb) },
3001 .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) },2938 .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) },
3002 .device_io_control => .{ .device_io_control = iosb.* },2939 .device_io_control => .{ .device_io_control = iosb.* },
2940 .net_receive => unreachable,
3003 };2941 };
3004 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };2942 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
3005 },2943 },
...@@ -3007,7 +2945,7 @@ fn batchApc(...@@ -3007,7 +2945,7 @@ fn batchApc(
3007}2945}
30082946
3009/// If `concurrency` is false, `error.ConcurrencyUnavailable` is unreachable.2947/// If `concurrency` is false, `error.ConcurrencyUnavailable` is unreachable.
3010fn batchDrainSubmittedWindows(b: *Io.Batch, concurrency: bool) (Io.ConcurrentError || Io.Cancelable)!void {2948fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io.ConcurrentError || Io.Cancelable)!void {
3011 var index = b.submitted.head;2949 var index = b.submitted.head;
3012 errdefer b.submitted.head = index;2950 errdefer b.submitted.head = index;
3013 while (index != .none) {2951 while (index != .none) {
...@@ -3201,6 +3139,13 @@ fn batchDrainSubmittedWindows(b: *Io.Batch, concurrency: bool) (Io.ConcurrentErr...@@ -3201,6 +3139,13 @@ fn batchDrainSubmittedWindows(b: *Io.Batch, concurrency: bool) (Io.ConcurrentErr
3201 };3139 };
3202 }3140 }
3203 },3141 },
3142 .net_receive => |*o| {
3143 // TODO integrate with overlapped I/O or equivalent to avoid this error
3144 if (concurrency) return error.ConcurrencyUnavailable;
3145 batchCompleteBlockingWindows(b, operation_userdata, .{
3146 .net_receive = netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags),
3147 });
3148 },
3204 }3149 }
3205 index = submission.node.next;3150 index = submission.node.next;
3206 }3151 }
...@@ -3459,7 +3404,7 @@ fn dirCreateDirPathOpenPosix(...@@ -3459,7 +3404,7 @@ fn dirCreateDirPathOpenPosix(
3459 options: Dir.OpenOptions,3404 options: Dir.OpenOptions,
3460) Dir.CreateDirPathOpenError!Dir {3405) Dir.CreateDirPathOpenError!Dir {
3461 const t: *Threaded = @ptrCast(@alignCast(userdata));3406 const t: *Threaded = @ptrCast(@alignCast(userdata));
3462 const t_io = ioBasic(t);3407 const t_io = io(t);
3463 return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) {3408 return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) {
3464 error.FileNotFound => {3409 error.FileNotFound => {
3465 _ = try dir.createDirPathStatus(t_io, sub_path, permissions);3410 _ = try dir.createDirPathStatus(t_io, sub_path, permissions);
...@@ -3580,7 +3525,7 @@ fn dirCreateDirPathOpenWasi(...@@ -3580,7 +3525,7 @@ fn dirCreateDirPathOpenWasi(
3580 options: Dir.OpenOptions,3525 options: Dir.OpenOptions,
3581) Dir.CreateDirPathOpenError!Dir {3526) Dir.CreateDirPathOpenError!Dir {
3582 const t: *Threaded = @ptrCast(@alignCast(userdata));3527 const t: *Threaded = @ptrCast(@alignCast(userdata));
3583 const t_io = ioBasic(t);3528 const t_io = io(t);
3584 return dirOpenDirWasi(t, dir, sub_path, options) catch |err| switch (err) {3529 return dirOpenDirWasi(t, dir, sub_path, options) catch |err| switch (err) {
3585 error.FileNotFound => {3530 error.FileNotFound => {
3586 _ = try dir.createDirPathStatus(t_io, sub_path, permissions);3531 _ = try dir.createDirPathStatus(t_io, sub_path, permissions);
...@@ -4621,7 +4566,7 @@ fn dirCreateFileAtomic(...@@ -4621,7 +4566,7 @@ fn dirCreateFileAtomic(
4621 options: Dir.CreateFileAtomicOptions,4566 options: Dir.CreateFileAtomicOptions,
4622) Dir.CreateFileAtomicError!File.Atomic {4567) Dir.CreateFileAtomicError!File.Atomic {
4623 const t: *Threaded = @ptrCast(@alignCast(userdata));4568 const t: *Threaded = @ptrCast(@alignCast(userdata));
4624 const t_io = ioBasic(t);4569 const t_io = io(t);
46254570
4626 // Linux has O_TMPFILE, but linkat() does not support AT_REPLACE, so it's4571 // Linux has O_TMPFILE, but linkat() does not support AT_REPLACE, so it's
4627 // useless when we have to make up a bogus path name to do the rename()4572 // useless when we have to make up a bogus path name to do the rename()
...@@ -10249,19 +10194,19 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut...@@ -10249,19 +10194,19 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
10249 const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &n);10194 const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &n);
10250 if (rc != 0) return error.NameTooLong;10195 if (rc != 0) return error.NameTooLong;
10251 const symlink_path = std.mem.sliceTo(&symlink_path_buf, 0);10196 const symlink_path = std.mem.sliceTo(&symlink_path_buf, 0);
10252 return Io.Dir.realPathFileAbsolute(ioBasic(t), symlink_path, out_buffer) catch |err| switch (err) {10197 return Io.Dir.realPathFileAbsolute(io(t), symlink_path, out_buffer) catch |err| switch (err) {
10253 error.NetworkNotFound => unreachable, // Windows-only10198 error.NetworkNotFound => unreachable, // Windows-only
10254 error.FileBusy => unreachable, // Windows-only10199 error.FileBusy => unreachable, // Windows-only
10255 else => |e| return e,10200 else => |e| return e,
10256 };10201 };
10257 },10202 },
10258 .linux, .serenity => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {10203 .linux, .serenity => return Io.Dir.readLinkAbsolute(io(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {
10259 error.UnsupportedReparsePointType => unreachable, // Windows-only10204 error.UnsupportedReparsePointType => unreachable, // Windows-only
10260 error.NetworkNotFound => unreachable, // Windows-only10205 error.NetworkNotFound => unreachable, // Windows-only
10261 error.FileBusy => unreachable, // Windows-only10206 error.FileBusy => unreachable, // Windows-only
10262 else => |e| return e,10207 else => |e| return e,
10263 },10208 },
10264 .illumos => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {10209 .illumos => return Io.Dir.readLinkAbsolute(io(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
10265 error.UnsupportedReparsePointType => unreachable, // Windows-only10210 error.UnsupportedReparsePointType => unreachable, // Windows-only
10266 error.NetworkNotFound => unreachable, // Windows-only10211 error.NetworkNotFound => unreachable, // Windows-only
10267 error.FileBusy => unreachable, // Windows-only10212 error.FileBusy => unreachable, // Windows-only
...@@ -11623,7 +11568,7 @@ fn sleepPosix(timeout: Io.Timeout) Io.Cancelable!void {...@@ -11623,7 +11568,7 @@ fn sleepPosix(timeout: Io.Timeout) Io.Cancelable!void {
11623}11568}
1162411569
11625fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {11570fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
11626 const t_io = ioBasic(t);11571 const t_io = io(t);
11627 const w = std.os.wasi;11572 const w = std.os.wasi;
1162811573
11629 const clock: w.subscription_clock_t = if (timeout.toDurationFromNow(t_io)) |d| .{11574 const clock: w.subscription_clock_t = if (timeout.toDurationFromNow(t_io)) |d| .{
...@@ -11652,7 +11597,7 @@ fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {...@@ -11652,7 +11597,7 @@ fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
11652}11597}
1165311598
11654fn sleepNanosleep(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {11599fn sleepNanosleep(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
11655 const t_io = ioBasic(t);11600 const t_io = io(t);
11656 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;11601 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
11657 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;11602 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
1165811603
...@@ -11884,6 +11829,7 @@ fn netListenUnixWindows(...@@ -11884,6 +11829,7 @@ fn netListenUnixWindows(
11884 options: net.UnixAddress.ListenOptions,11829 options: net.UnixAddress.ListenOptions,
11885) net.UnixAddress.ListenError!net.Socket.Handle {11830) net.UnixAddress.ListenError!net.Socket.Handle {
11886 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;11831 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
11832 if (!have_networking) return error.NetworkDown;
11887 const t: *Threaded = @ptrCast(@alignCast(userdata));11833 const t: *Threaded = @ptrCast(@alignCast(userdata));
1188811834
11889 const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {11835 const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
...@@ -12380,6 +12326,7 @@ fn netConnectUnixWindows(...@@ -12380,6 +12326,7 @@ fn netConnectUnixWindows(
12380 address: *const net.UnixAddress,12326 address: *const net.UnixAddress,
12381) net.UnixAddress.ConnectError!net.Socket.Handle {12327) net.UnixAddress.ConnectError!net.Socket.Handle {
12382 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;12328 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
12329 if (!have_networking) return error.NetworkDown;
12383 const t: *Threaded = @ptrCast(@alignCast(userdata));12330 const t: *Threaded = @ptrCast(@alignCast(userdata));
1238412331
12385 const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });12332 const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });
...@@ -12995,11 +12942,76 @@ fn netSendWindows(...@@ -12995,11 +12942,76 @@ fn netSendWindows(
12995) struct { ?net.Socket.SendError, usize } {12942) struct { ?net.Socket.SendError, usize } {
12996 if (!have_networking) return .{ error.NetworkDown, 0 };12943 if (!have_networking) return .{ error.NetworkDown, 0 };
12997 const t: *Threaded = @ptrCast(@alignCast(userdata));12944 const t: *Threaded = @ptrCast(@alignCast(userdata));
12998 _ = t;12945
12999 _ = handle;12946 // Ignored flags: confirm, eor, fastopen
13000 _ = messages;12947 const windows_flags: u32 =
13001 _ = flags;12948 @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) |
13002 @panic("TODO netSendWindows");12949 @as(u32, if (flags.dont_route) ws2_32.MSG.DONTROUTE else 0);
12950
12951 for (messages, 0..) |*m, i| {
12952 netSendWindowsOne(t, handle, m, windows_flags) catch |err| return .{ err, i };
12953 }
12954 return .{ null, messages.len };
12955}
12956
12957fn netSendWindowsOne(
12958 t: *Threaded,
12959 handle: net.Socket.Handle,
12960 message: *net.OutgoingMessage,
12961 flags: u32,
12962) net.Socket.SendError!void {
12963 var buf: ws2_32.WSABUF = .{
12964 .buf = @constCast(message.data_ptr),
12965 .len = std.math.cast(u32, message.data_len) orelse return error.MessageOversize,
12966 };
12967 var n: u32 = undefined;
12968 var address: WsaAddress = undefined;
12969 const address_size = addressToWsa(message.address, &address);
12970 var syscall: Syscall = try .start();
12971 while (true) {
12972 const rc = ws2_32.WSASendTo(
12973 handle,
12974 (&buf)[0..1],
12975 1,
12976 &n,
12977 flags,
12978 &address.any,
12979 address_size,
12980 null,
12981 null,
12982 );
12983 if (rc != ws2_32.SOCKET_ERROR) {
12984 syscall.finish();
12985 return;
12986 }
12987 switch (ws2_32.WSAGetLastError()) {
12988 .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => {
12989 try syscall.checkCancel();
12990 continue;
12991 },
12992 .NOTINITIALISED => {
12993 syscall.finish();
12994 try initializeWsa(t);
12995 syscall = try .start();
12996 continue;
12997 },
12998
12999 .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer),
13000 .ENETDOWN => return syscall.fail(error.NetworkDown),
13001 .ENETRESET => return syscall.fail(error.ConnectionResetByPeer),
13002 .ENOTCONN => return syscall.fail(error.SocketUnconnected),
13003 .EFAULT => unreachable, // a pointer is not completely contained in user address space.
13004
13005 else => |err| {
13006 syscall.finish();
13007 switch (err) {
13008 .EINVAL => return wsaErrorBug(err),
13009 .EMSGSIZE => return wsaErrorBug(err),
13010 else => return windows.unexpectedWSAError(err),
13011 }
13012 },
13013 }
13014 }
13003}13015}
1300413016
13005fn netSendUnavailable(13017fn netSendUnavailable(
...@@ -13190,70 +13202,44 @@ fn netSendMany(...@@ -13190,70 +13202,44 @@ fn netSendMany(
13190}13202}
1319113203
13192fn netReceivePosix(13204fn netReceivePosix(
13193 userdata: ?*anyopaque,13205 socket_handle: net.Socket.Handle,
13194 handle: net.Socket.Handle,13206 message: *net.IncomingMessage,
13195 message_buffer: []net.IncomingMessage,
13196 data_buffer: []u8,13207 data_buffer: []u8,
13197 flags: net.ReceiveFlags,13208 flags: net.ReceiveFlags,
13198 timeout: Io.Timeout,13209 nonblocking: bool,
13199) struct { ?net.Socket.ReceiveTimeoutError, usize } {13210) (net.Socket.ReceiveError || error{WouldBlock})!void {
13200 if (!have_networking) return .{ error.NetworkDown, 0 };
13201 const t: *Threaded = @ptrCast(@alignCast(userdata));
13202 const t_io = io(t);
13203
13204 // recvmmsg is useless, here's why:13211 // recvmmsg is useless, here's why:
13205 // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371)13212 // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371)
13206 // * it wants iovecs for each message but we have a better API: one data13213 // * it wants iovecs for each message but we have a better API: one data
13207 // buffer to handle all the messages. The better API cannot be lowered to13214 // buffer to handle all the messages. The better API cannot be lowered to
13208 // the split vectors though because reducing the buffer size might make13215 // the split vectors though because reducing the buffer size might make
13209 // some messages unreceivable.13216 // some messages unreceivable.
13210
13211 // So the strategy instead is to use non-blocking recvmsg calls, calling
13212 // poll() with timeout if the first one returns EAGAIN.
13213 const posix_flags: u32 =13217 const posix_flags: u32 =
13214 @as(u32, if (flags.oob) posix.MSG.OOB else 0) |13218 @as(u32, if (flags.oob) posix.MSG.OOB else 0) |
13215 @as(u32, if (flags.peek) posix.MSG.PEEK else 0) |13219 @as(u32, if (flags.peek) posix.MSG.PEEK else 0) |
13216 @as(u32, if (flags.trunc) posix.MSG.TRUNC else 0) |13220 @as(u32, if (flags.trunc) posix.MSG.TRUNC else 0) |
13217 posix.MSG.DONTWAIT | posix.MSG.NOSIGNAL;13221 posix.MSG.NOSIGNAL |
13222 @as(u32, if (nonblocking) posix.MSG.DONTWAIT else 0);
1321813223
13219 var poll_fds: [1]posix.pollfd = .{13224 var storage: PosixAddress = undefined;
13220 .{13225 var iov: posix.iovec = .{ .base = data_buffer.ptr, .len = data_buffer.len };
13221 .fd = handle,13226 var msg: posix.msghdr = .{
13222 .events = posix.POLL.IN,13227 .name = &storage.any,
13223 .revents = undefined,13228 .namelen = @sizeOf(PosixAddress),
13224 },13229 .iov = (&iov)[0..1],
13230 .iovlen = 1,
13231 .control = message.control.ptr,
13232 .controllen = @intCast(message.control.len),
13233 .flags = undefined,
13225 };13234 };
13226 var message_i: usize = 0;
13227 var data_i: usize = 0;
1322813235
13229 const deadline = timeout.toTimestamp(t_io);13236 const syscall = try Syscall.start();
1323013237 while (true) {
13231 recv: while (true) {13238 const rc = posix.system.recvmsg(socket_handle, &msg, posix_flags);
13232 if (message_buffer.len - message_i == 0) return .{ null, message_i };13239 switch (posix.errno(rc)) {
13233 const message = &message_buffer[message_i];
13234 const remaining_data_buffer = data_buffer[data_i..];
13235 var storage: PosixAddress = undefined;
13236 var iov: posix.iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len };
13237 var msg: posix.msghdr = .{
13238 .name = &storage.any,
13239 .namelen = @sizeOf(PosixAddress),
13240 .iov = (&iov)[0..1],
13241 .iovlen = 1,
13242 .control = message.control.ptr,
13243 .controllen = @intCast(message.control.len),
13244 .flags = undefined,
13245 };
13246
13247 const recv_rc = rc: {
13248 const syscall = Syscall.start() catch |err| return .{ err, message_i };
13249 const rc = posix.system.recvmsg(handle, &msg, posix_flags);
13250 syscall.finish();
13251 break :rc rc;
13252 };
13253 switch (posix.errno(recv_rc)) {
13254 .SUCCESS => {13240 .SUCCESS => {
13255 const data = remaining_data_buffer[0..@intCast(recv_rc)];13241 syscall.finish();
13256 data_i += data.len;13242 const data = data_buffer[0..@intCast(rc)];
13257 message.* = .{13243 message.* = .{
13258 .from = addressFromPosix(&storage),13244 .from = addressFromPosix(&storage),
13259 .data = data,13245 .data = data,
...@@ -13266,96 +13252,122 @@ fn netReceivePosix(...@@ -13266,96 +13252,122 @@ fn netReceivePosix(
13266 .errqueue = if (@hasDecl(posix.MSG, "ERRQUEUE")) (msg.flags & posix.MSG.ERRQUEUE) != 0 else false,13252 .errqueue = if (@hasDecl(posix.MSG, "ERRQUEUE")) (msg.flags & posix.MSG.ERRQUEUE) != 0 else false,
13267 },13253 },
13268 };13254 };
13269 message_i += 1;13255 return;
13270 continue;
13271 },13256 },
13272 .AGAIN => while (true) {13257 .INTR => {
13273 if (message_i != 0) return .{ null, message_i };13258 try syscall.checkCancel();
1327413259 continue;
13275 const max_poll_ms = std.math.maxInt(u31);
13276 const timeout_ms: u31 = if (deadline) |d| t: {
13277 const duration = d.durationFromNow(t_io);
13278 if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i };
13279 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
13280 } else max_poll_ms;
13281
13282 const syscall = Syscall.start() catch |err| return .{ err, message_i };
13283 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
13284 syscall.finish();
13285
13286 switch (posix.errno(poll_rc)) {
13287 .SUCCESS => {
13288 if (poll_rc == 0) {
13289 // Although spurious timeouts are OK, when no deadline
13290 // is passed we must not return `error.Timeout`.
13291 if (deadline == null) continue;
13292 return .{ error.Timeout, message_i };
13293 }
13294 continue :recv;
13295 },
13296 .INTR => continue,
13297
13298 .FAULT => |err| return .{ errnoBug(err), message_i },
13299 .INVAL => |err| return .{ errnoBug(err), message_i },
13300 .NOMEM => return .{ error.SystemResources, message_i },
13301 else => |err| return .{ posix.unexpectedErrno(err), message_i },
13302 }
13303 },13260 },
13304 .INTR => continue,13261 .NFILE => return syscall.fail(error.SystemFdQuotaExceeded),
1330513262 .MFILE => return syscall.fail(error.ProcessFdQuotaExceeded),
13306 .BADF => |err| return .{ errnoBug(err), message_i },13263 .NOBUFS => return syscall.fail(error.SystemResources),
13307 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },13264 .NOMEM => return syscall.fail(error.SystemResources),
13308 .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i },13265 .NOTCONN => return syscall.fail(error.SocketUnconnected),
13309 .FAULT => |err| return .{ errnoBug(err), message_i },13266 .MSGSIZE => return syscall.fail(error.MessageOversize),
13310 .INVAL => |err| return .{ errnoBug(err), message_i },13267 .PIPE => return syscall.fail(error.SocketUnconnected),
13311 .NOBUFS => return .{ error.SystemResources, message_i },13268 .CONNRESET => return syscall.fail(error.ConnectionResetByPeer),
13312 .NOMEM => return .{ error.SystemResources, message_i },13269 .NETDOWN => return syscall.fail(error.NetworkDown),
13313 .NOTCONN => return .{ error.SocketUnconnected, message_i },13270 .AGAIN => return syscall.fail(error.WouldBlock),
13314 .NOTSOCK => |err| return .{ errnoBug(err), message_i },13271 .BADF => |err| return syscall.errnoBug(err),
13315 .MSGSIZE => return .{ error.MessageOversize, message_i },13272 .FAULT => |err| return syscall.errnoBug(err),
13316 .PIPE => return .{ error.SocketUnconnected, message_i },13273 .INVAL => |err| return syscall.errnoBug(err),
13317 .OPNOTSUPP => |err| return .{ errnoBug(err), message_i },13274 .NOTSOCK => |err| return syscall.errnoBug(err),
13318 .CONNRESET => return .{ error.ConnectionResetByPeer, message_i },13275 .OPNOTSUPP => |err| return syscall.errnoBug(err),
13319 .NETDOWN => return .{ error.NetworkDown, message_i },13276 else => |err| return syscall.unexpectedErrno(err),
13320 else => |err| return .{ posix.unexpectedErrno(err), message_i },
13321 }13277 }
13322 }13278 }
13323}13279}
1332413280
13325fn netReceiveWindows(13281fn netReceiveWindows(
13326 userdata: ?*anyopaque,13282 t: *Threaded,
13327 handle: net.Socket.Handle,13283 socket_handle: net.Socket.Handle,
13328 message_buffer: []net.IncomingMessage,13284 message_buffer: []net.IncomingMessage,
13329 data_buffer: []u8,13285 data_buffer: []u8,
13330 flags: net.ReceiveFlags,13286 flags: net.ReceiveFlags,
13331 timeout: Io.Timeout,13287) struct { ?net.Socket.ReceiveError, usize } {
13332) struct { ?net.Socket.ReceiveTimeoutError, usize } {13288 netReceiveWindowsOne(t, socket_handle, &message_buffer[0], data_buffer, flags) catch |err| return .{ err, 0 };
13333 if (!have_networking) return .{ error.NetworkDown, 0 };13289 return .{ null, 1 };
13334 const t: *Threaded = @ptrCast(@alignCast(userdata));
13335 _ = t;
13336 _ = handle;
13337 _ = message_buffer;
13338 _ = data_buffer;
13339 _ = flags;
13340 _ = timeout;
13341 @panic("TODO implement netReceiveWindows");
13342}13290}
1334313291
13344fn netReceiveUnavailable(13292fn netReceiveWindowsOne(
13345 userdata: ?*anyopaque,13293 t: *Threaded,
13346 handle: net.Socket.Handle,13294 socket_handle: net.Socket.Handle,
13347 message_buffer: []net.IncomingMessage,13295 message: *net.IncomingMessage,
13348 data_buffer: []u8,13296 data_buffer: []u8,
13349 flags: net.ReceiveFlags,13297 flags: net.ReceiveFlags,
13350 timeout: Io.Timeout,13298) net.Socket.ReceiveError!void {
13351) struct { ?net.Socket.ReceiveTimeoutError, usize } {13299 if (!have_networking) return error.NetworkDown;
13352 _ = userdata;13300
13353 _ = handle;13301 var windows_flags: u32 =
13354 _ = message_buffer;13302 @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) |
13355 _ = data_buffer;13303 @as(u32, if (flags.peek) ws2_32.MSG.PEEK else 0) |
13356 _ = flags;13304 @as(u32, if (flags.trunc) ws2_32.MSG.TRUNC else 0);
13357 _ = timeout;13305
13358 return .{ error.NetworkDown, 0 };13306 var buf: ws2_32.WSABUF = .{
13307 .buf = data_buffer.ptr,
13308 .len = std.math.cast(u32, data_buffer.len) orelse return error.MessageOversize,
13309 };
13310 var n: u32 = undefined;
13311 var syscall: Syscall = try .start();
13312 var from_storage: WsaAddress = undefined;
13313 var from_storage_len: i32 = @sizeOf(WsaAddress);
13314
13315 while (true) {
13316 const rc = ws2_32.WSARecvFrom(
13317 socket_handle,
13318 (&buf)[0..1],
13319 1,
13320 &n,
13321 &windows_flags,
13322 &from_storage.any,
13323 &from_storage_len,
13324 null,
13325 null,
13326 );
13327 if (rc != ws2_32.SOCKET_ERROR) {
13328 syscall.finish();
13329 message.* = .{
13330 .from = addressFromWsa(&from_storage),
13331 .data = data_buffer[0..n],
13332 .control = &.{},
13333 .flags = .{
13334 .eor = false,
13335 .trunc = (windows_flags & ws2_32.MSG.TRUNC) != 0,
13336 .ctrunc = (windows_flags & ws2_32.MSG.CTRUNC) != 0,
13337 .oob = false,
13338 .errqueue = false,
13339 },
13340 };
13341 return;
13342 }
13343 switch (ws2_32.WSAGetLastError()) {
13344 .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => {
13345 try syscall.checkCancel();
13346 continue;
13347 },
13348 .NOTINITIALISED => {
13349 syscall.finish();
13350 try initializeWsa(t);
13351 syscall = try .start();
13352 continue;
13353 },
13354
13355 .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer),
13356 .ENETDOWN => return syscall.fail(error.NetworkDown),
13357 .ENETRESET => return syscall.fail(error.ConnectionResetByPeer),
13358 .ENOTCONN => return syscall.fail(error.SocketUnconnected),
13359 .EFAULT => unreachable, // a pointer is not completely contained in user address space.
13360
13361 else => |err| {
13362 syscall.finish();
13363 switch (err) {
13364 .EINVAL => return wsaErrorBug(err),
13365 .EMSGSIZE => return wsaErrorBug(err),
13366 else => return windows.unexpectedWSAError(err),
13367 }
13368 },
13369 }
13370 }
13359}13371}
1336013372
13361fn netWritePosix(13373fn netWritePosix(
...@@ -13459,6 +13471,7 @@ fn netWriteWindows(...@@ -13459,6 +13471,7 @@ fn netWriteWindows(
13459 data: []const []const u8,13471 data: []const []const u8,
13460 splat: usize,13472 splat: usize,
13461) net.Stream.Writer.Error!usize {13473) net.Stream.Writer.Error!usize {
13474 if (!have_networking) return error.NetworkDown;
13462 const t: *Threaded = @ptrCast(@alignCast(userdata));13475 const t: *Threaded = @ptrCast(@alignCast(userdata));
13463 comptime assert(is_windows);13476 comptime assert(is_windows);
1346413477
...@@ -13581,6 +13594,7 @@ fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void {...@@ -13581,6 +13594,7 @@ fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void {
13581}13594}
1358213595
13583fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {13596fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {
13597 if (!have_networking) unreachable;
13584 const t: *Threaded = @ptrCast(@alignCast(userdata));13598 const t: *Threaded = @ptrCast(@alignCast(userdata));
13585 _ = t;13599 _ = t;
13586 switch (native_os) {13600 switch (native_os) {
...@@ -13789,7 +13803,7 @@ fn netLookupUnavailable(...@@ -13789,7 +13803,7 @@ fn netLookupUnavailable(
13789 _ = host_name;13803 _ = host_name;
13790 _ = options;13804 _ = options;
13791 const t: *Threaded = @ptrCast(@alignCast(userdata));13805 const t: *Threaded = @ptrCast(@alignCast(userdata));
13792 resolved.close(ioBasic(t));13806 resolved.close(io(t));
13793 return error.NetworkDown;13807 return error.NetworkDown;
13794}13808}
1379513809
...@@ -14072,7 +14086,7 @@ fn tryLockStderr(userdata: ?*anyopaque, terminal_mode: ?Io.Terminal.Mode) Io.Can...@@ -14072,7 +14086,7 @@ fn tryLockStderr(userdata: ?*anyopaque, terminal_mode: ?Io.Terminal.Mode) Io.Can
1407214086
14073fn initLockedStderr(t: *Threaded, terminal_mode: ?Io.Terminal.Mode) Io.Cancelable!Io.LockedStderr {14087fn initLockedStderr(t: *Threaded, terminal_mode: ?Io.Terminal.Mode) Io.Cancelable!Io.LockedStderr {
14074 if (!t.stderr_writer_initialized) {14088 if (!t.stderr_writer_initialized) {
14075 const io_t = ioBasic(t);14089 const io_t = io(t);
14076 if (is_windows) t.stderr_writer.file = .stderr();14090 if (is_windows) t.stderr_writer.file = .stderr();
14077 t.stderr_writer.io = io_t;14091 t.stderr_writer.io = io_t;
14078 t.stderr_writer_initialized = true;14092 t.stderr_writer_initialized = true;
lib/std/Io/Uring.zig+22-49
...@@ -777,7 +777,6 @@ pub fn io(ev: *Evented) Io {...@@ -777,7 +777,6 @@ pub fn io(ev: *Evented) Io {
777 .netConnectUnix = netConnectUnixUnavailable,777 .netConnectUnix = netConnectUnixUnavailable,
778 .netSocketCreatePair = netSocketCreatePairUnavailable,778 .netSocketCreatePair = netSocketCreatePairUnavailable,
779 .netSend = netSendUnavailable,779 .netSend = netSendUnavailable,
780 .netReceive = netReceive,
781 .netRead = netReadUnavailable,780 .netRead = netReadUnavailable,
782 .netWrite = netWriteUnavailable,781 .netWrite = netWriteUnavailable,
783 .netWriteFile = netWriteFileUnavailable,782 .netWriteFile = netWriteFileUnavailable,
...@@ -2092,6 +2091,18 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2092,6 +2091,18 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2092 .device_io_control => |o| .{2091 .device_io_control => |o| .{
2093 .device_io_control = try ev.deviceIoControl(try maybe_sync.enterSync(ev), o),2092 .device_io_control = try ev.deviceIoControl(try maybe_sync.enterSync(ev), o),
2094 },2093 },
2094 .net_receive => |o| .{
2095 .net_receive = r: {
2096 const opt_err, const n = ev.netReceive(&maybe_sync.cancel_region, o.socket_handle, o.message_buffer, o.data_buffer, o.flags);
2097 break :r .{
2098 if (opt_err) |err| switch (err) {
2099 error.Canceled => |e| return e,
2100 else => |e| e,
2101 } else null,
2102 n,
2103 };
2104 },
2105 },
2095 };2106 };
2096}2107}
20972108
...@@ -2375,6 +2386,10 @@ fn batchDrainSubmitted(...@@ -2375,6 +2386,10 @@ fn batchDrainSubmitted(
2375 return error.ConcurrencyUnavailable2386 return error.ConcurrencyUnavailable
2376 else2387 else
2377 .{ .device_io_control = try ev.deviceIoControl(try maybe_sync.enterSync(ev), o) },2388 .{ .device_io_control = try ev.deviceIoControl(try maybe_sync.enterSync(ev), o) },
2389 .net_receive => |o| {
2390 _ = o;
2391 @panic("TODO implement batchDrainSubmitted for net_receive");
2392 },
2378 })) |result| {2393 })) |result| {
2379 switch (batch.completed.tail) {2394 switch (batch.completed.tail) {
2380 .none => batch.completed.head = index,2395 .none => batch.completed.head = index,
...@@ -2475,6 +2490,7 @@ fn batchDrainReady(batch: *Io.Batch) Io.Timeout.Error!void {...@@ -2475,6 +2490,7 @@ fn batchDrainReady(batch: *Io.Batch) Io.Timeout.Error!void {
2475 },2490 },
2476 },2491 },
2477 .device_io_control => unreachable,2492 .device_io_control => unreachable,
2493 .net_receive => @panic("TODO"),
2478 })) |result| {2494 })) |result| {
2479 switch (batch.completed.tail) {2495 switch (batch.completed.tail) {
2480 .none => batch.completed.head = index,2496 .none => batch.completed.head = index,
...@@ -5035,37 +5051,16 @@ fn netSendUnavailable(...@@ -5035,37 +5051,16 @@ fn netSendUnavailable(
5035}5051}
50365052
5037fn netReceive(5053fn netReceive(
5038 userdata: ?*anyopaque,5054 ev: *Evented,
5055 cancel_region: *CancelRegion,
5039 handle: net.Socket.Handle,5056 handle: net.Socket.Handle,
5040 message_buffer: []net.IncomingMessage,5057 message_buffer: []net.IncomingMessage,
5041 data_buffer: []u8,5058 data_buffer: []u8,
5042 flags: net.ReceiveFlags,5059 flags: net.ReceiveFlags,
5043 timeout: Io.Timeout,5060) struct { ?net.Socket.ReceiveError, usize } {
5044) struct { ?net.Socket.ReceiveTimeoutError, usize } {
5045 const ev: *Evented = @ptrCast(@alignCast(userdata));
5046 const ev_io = ev.io();
5047
5048 var message_i: usize = 0;5061 var message_i: usize = 0;
5049 var data_i: usize = 0;5062 var data_i: usize = 0;
50505063
5051 const deadline: ?struct {
5052 raw: Io.Timestamp,
5053 timespec: linux.kernel_timespec,
5054 clock: Io.Clock,
5055 } = if (timeout.toTimestamp(ev_io)) |deadline| deadline: {
5056 const ns = deadline.raw.toNanoseconds();
5057 break :deadline .{
5058 .raw = deadline.raw,
5059 .timespec = .{
5060 .sec = @intCast(@divFloor(ns, std.time.ns_per_s)),
5061 .nsec = @intCast(@mod(ns, std.time.ns_per_s)),
5062 },
5063 .clock = deadline.clock,
5064 };
5065 } else null;
5066
5067 var cancel_region: CancelRegion = .init();
5068 defer cancel_region.deinit();
5069 while (true) {5064 while (true) {
5070 if (message_buffer.len - message_i == 0) return .{ null, message_i };5065 if (message_buffer.len - message_i == 0) return .{ null, message_i };
5071 const message = &message_buffer[message_i];5066 const message = &message_buffer[message_i];
...@@ -5085,7 +5080,7 @@ fn netReceive(...@@ -5085,7 +5080,7 @@ fn netReceive(
5085 const thread = cancel_region.awaitIoUring() catch |err| return .{ err, message_i };5080 const thread = cancel_region.awaitIoUring() catch |err| return .{ err, message_i };
5086 thread.enqueue().* = .{5081 thread.enqueue().* = .{
5087 .opcode = .RECVMSG,5082 .opcode = .RECVMSG,
5088 .flags = if (deadline) |_| linux.IOSQE_IO_LINK else 0,5083 .flags = 0,
5089 .ioprio = 0,5084 .ioprio = 0,
5090 .fd = handle,5085 .fd = handle,
5091 .off = 0,5086 .off = 0,
...@@ -5102,26 +5097,6 @@ fn netReceive(...@@ -5102,26 +5097,6 @@ fn netReceive(
5102 .addr3 = 0,5097 .addr3 = 0,
5103 .resv = 0,5098 .resv = 0,
5104 };5099 };
5105 if (deadline) |*deadline_ptr| thread.enqueue().* = .{
5106 .opcode = .LINK_TIMEOUT,
5107 .flags = linux.IOSQE_CQE_SKIP_SUCCESS,
5108 .ioprio = 0,
5109 .fd = 0,
5110 .off = 0,
5111 .addr = @intFromPtr(&deadline_ptr.timespec),
5112 .len = 1,
5113 .rw_flags = linux.IORING_TIMEOUT_ABS | @as(u32, switch (deadline_ptr.clock) {
5114 .real => linux.IORING_TIMEOUT_REALTIME,
5115 else => 0,
5116 .boot => linux.IORING_TIMEOUT_BOOTTIME,
5117 }),
5118 .user_data = @intFromEnum(Completion.Userdata.wakeup),
5119 .buf_index = 0,
5120 .personality = 0,
5121 .splice_fd_in = 0,
5122 .addr3 = 0,
5123 .resv = 0,
5124 };
5125 ev.yield(null, .nothing);5100 ev.yield(null, .nothing);
5126 const completion = cancel_region.completion();5101 const completion = cancel_region.completion();
5127 switch (completion.errno()) {5102 switch (completion.errno()) {
...@@ -5144,9 +5119,7 @@ fn netReceive(...@@ -5144,9 +5119,7 @@ fn netReceive(
5144 continue;5119 continue;
5145 },5120 },
5146 .AGAIN => unreachable,5121 .AGAIN => unreachable,
5147 .INTR, .CANCELED => if (deadline) |d| if (now(ev, d.clock).nanoseconds >= d.raw.nanoseconds)5122 .INTR, .CANCELED => {},
5148 return .{ error.Timeout, message_i },
5149
5150 .BADF => |err| return .{ errnoBug(err), message_i },5123 .BADF => |err| return .{ errnoBug(err), message_i },
5151 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },5124 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },
5152 .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i },5125 .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i },
lib/std/Io/net.zig+22-28
...@@ -1109,25 +1109,7 @@ pub const Socket = struct {...@@ -1109,25 +1109,7 @@ pub const Socket = struct {
1109 if (n != messages.len) return err.?;1109 if (n != messages.len) return err.?;
1110 }1110 }
11111111
1112 pub const ReceiveError = error{1112 pub const ReceiveError = Io.Operation.NetReceive.Error || Io.Cancelable;
1113 /// Insufficient memory or other resource internal to the operating system.
1114 SystemResources,
1115 /// Per-process limit on the number of open file descriptors has been reached.
1116 ProcessFdQuotaExceeded,
1117 /// System-wide limit on the total number of open files has been reached.
1118 SystemFdQuotaExceeded,
1119 /// Local end has been shut down on a connection-oriented socket, or
1120 /// the socket was never connected.
1121 SocketUnconnected,
1122 /// The socket type requires that message be sent atomically, and the
1123 /// size of the message to be sent made this impossible. The message
1124 /// was not transmitted, or was partially transmitted.
1125 MessageOversize,
1126 /// Network connection was unexpectedly closed by sender.
1127 ConnectionResetByPeer,
1128 /// The local network interface used to reach the destination is offline.
1129 NetworkDown,
1130 } || Io.UnexpectedError || Io.Cancelable;
11311113
1132 /// Waits for data. Connectionless.1114 /// Waits for data. Connectionless.
1133 ///1115 ///
...@@ -1135,17 +1117,18 @@ pub const Socket = struct {...@@ -1135,17 +1117,18 @@ pub const Socket = struct {
1135 /// * `receiveTimeout`1117 /// * `receiveTimeout`
1136 pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {1118 pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {
1137 var message: IncomingMessage = .init;1119 var message: IncomingMessage = .init;
1138 const maybe_err, const count = io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, .none);1120 const maybe_err, const count = (try io.operate(.{ .net_receive = .{
1139 if (maybe_err) |err| switch (err) {1121 .socket_handle = s.handle,
1140 // No timeout is passed to `netReceieve`, so it must not return timeout related errors.1122 .message_buffer = (&message)[0..1],
1141 error.Timeout => unreachable,1123 .data_buffer = buffer,
1142 else => |e| return e,1124 .flags = .{},
1143 };1125 } })).net_receive;
1126 if (maybe_err) |err| return err;
1144 assert(1 == count);1127 assert(1 == count);
1145 return message;1128 return message;
1146 }1129 }
11471130
1148 pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error;1131 pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error || Io.ConcurrentError;
11491132
1150 /// Waits for data. Connectionless.1133 /// Waits for data. Connectionless.
1151 ///1134 ///
...@@ -1161,7 +1144,12 @@ pub const Socket = struct {...@@ -1161,7 +1144,12 @@ pub const Socket = struct {
1161 timeout: Io.Timeout,1144 timeout: Io.Timeout,
1162 ) ReceiveTimeoutError!IncomingMessage {1145 ) ReceiveTimeoutError!IncomingMessage {
1163 var message: IncomingMessage = .init;1146 var message: IncomingMessage = .init;
1164 const maybe_err, const count = io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, timeout);1147 const maybe_err, const count = (try io.operateTimeout(.{ .net_receive = .{
1148 .socket_handle = s.handle,
1149 .message_buffer = (&message)[0..1],
1150 .data_buffer = buffer,
1151 .flags = .{},
1152 } }, timeout)).net_receive;
1165 if (maybe_err) |err| return err;1153 if (maybe_err) |err| return err;
1166 assert(1 == count);1154 assert(1 == count);
1167 return message;1155 return message;
...@@ -1186,7 +1174,13 @@ pub const Socket = struct {...@@ -1186,7 +1174,13 @@ pub const Socket = struct {
1186 flags: ReceiveFlags,1174 flags: ReceiveFlags,
1187 timeout: Io.Timeout,1175 timeout: Io.Timeout,
1188 ) struct { ?ReceiveTimeoutError, usize } {1176 ) struct { ?ReceiveTimeoutError, usize } {
1189 return io.vtable.netReceive(io.userdata, s.handle, message_buffer, data_buffer, flags, timeout);1177 const result = io.operateTimeout(.{ .net_receive = .{
1178 .socket_handle = s.handle,
1179 .message_buffer = message_buffer,
1180 .data_buffer = data_buffer,
1181 .flags = flags,
1182 } }, timeout) catch |err| return .{ err, 0 };
1183 return result.net_receive;
1190 }1184 }
11911185
1192 pub const CreatePairError = error{1186 pub const CreatePairError = error{
lib/std/os/windows/ws2_32.zig+14-11
...@@ -661,17 +661,20 @@ pub const IOC_OUT = 1073741824;...@@ -661,17 +661,20 @@ pub const IOC_OUT = 1073741824;
661pub const IOC_IN = 2147483648;661pub const IOC_IN = 2147483648;
662662
663pub const MSG = struct {663pub const MSG = struct {
664 pub const TRUNC = 256;664 pub const OOB = 0x1;
665 pub const CTRUNC = 512;665 pub const PEEK = 0x2;
666 pub const BCAST = 1024;666 pub const DONTROUTE = 0x4;
667 pub const MCAST = 2048;667 pub const WAITALL = 0x8;
668 pub const ERRQUEUE = 4096;668 pub const INTERRUPT = 0x10;
669669 pub const PUSH_IMMEDIATE = 0x20;
670 pub const PEEK = 2;670
671 pub const WAITALL = 8;671 pub const TRUNC = 0x0100;
672 pub const PUSH_IMMEDIATE = 32;672 pub const CTRUNC = 0x0200;
673 pub const PARTIAL = 32768;673 pub const BCAST = 0x0400;
674 pub const INTERRUPT = 16;674 pub const MCAST = 0x0800;
675
676 pub const PARTIAL = 0x8000;
677
675 pub const MAXIOVLEN = 16;678 pub const MAXIOVLEN = 16;
676};679};
677680
lib/std/std.zig+4-1
...@@ -174,6 +174,9 @@ pub const Options = struct {...@@ -174,6 +174,9 @@ pub const Options = struct {
174 /// stack traces will just print an error to the relevant `Io.Writer` and return.174 /// stack traces will just print an error to the relevant `Io.Writer` and return.
175 allow_stack_tracing: bool = !@import("builtin").strip_debug_info,175 allow_stack_tracing: bool = !@import("builtin").strip_debug_info,
176176
177 /// Allows disabling networking in std.Io implementations.
178 networking: bool = true,
179
177 /// TODO This is a separate decl instead of a field as a workaround around180 /// TODO This is a separate decl instead of a field as a workaround around
178 /// compilation errors due to zig not being lazy enough.181 /// compilation errors due to zig not being lazy enough.
179 pub const logTerminalMode: fn () Io.Terminal.Mode = log.defaultTerminalMode;182 pub const logTerminalMode: fn () Io.Terminal.Mode = log.defaultTerminalMode;
...@@ -202,7 +205,7 @@ pub const Options = struct {...@@ -202,7 +205,7 @@ pub const Options = struct {
202 /// implementation based on coroutines, one likely wants `std.debug.print`205 /// implementation based on coroutines, one likely wants `std.debug.print`
203 /// to directly write to stderr without trying to interact with the code206 /// to directly write to stderr without trying to interact with the code
204 /// being debugged.207 /// being debugged.
205 pub const debug_io: Io = if (@hasDecl(root, "std_options_debug_io")) root.std_options_debug_io else debug_threaded_io.?.ioBasic();208 pub const debug_io: Io = if (@hasDecl(root, "std_options_debug_io")) root.std_options_debug_io else debug_threaded_io.?.io();
206209
207 /// Overrides `std.Io.File.Permissions`.210 /// Overrides `std.Io.File.Permissions`.
208 pub const FilePermissions: ?type = if (@hasDecl(root, "std_options_FilePermissions")) root.std_options_FilePermissions else null;211 pub const FilePermissions: ?type = if (@hasDecl(root, "std_options_FilePermissions")) root.std_options_FilePermissions else null;
lib/ubsan_rt.zig+4
...@@ -3,6 +3,10 @@ const builtin = @import("builtin");...@@ -3,6 +3,10 @@ const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const panic = std.debug.panicExtra;4const panic = std.debug.panicExtra;
55
6pub const std_options: std.Options = .{
7 .networking = false,
8};
9
6const SourceLocation = extern struct {10const SourceLocation = extern struct {
7 file_name: ?[*:0]const u8,11 file_name: ?[*:0]const u8,
8 line: u32,12 line: u32,
test/incremental/add_decl+6-6
...@@ -10,7 +10,7 @@ pub fn main() !void {...@@ -10,7 +10,7 @@ pub fn main() !void {
10 try std.Io.File.stdout().writeStreamingAll(io, foo);10 try std.Io.File.stdout().writeStreamingAll(io, foo);
11}11}
12const foo = "good morning\n";12const foo = "good morning\n";
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#expect_stdout="good morning\n"14#expect_stdout="good morning\n"
1515
16#update=add new declaration16#update=add new declaration
...@@ -21,7 +21,7 @@ pub fn main() !void {...@@ -21,7 +21,7 @@ pub fn main() !void {
21}21}
22const foo = "good morning\n";22const foo = "good morning\n";
23const bar = "good evening\n";23const bar = "good evening\n";
24const io = std.Io.Threaded.global_single_threaded.ioBasic();24const io = std.Io.Threaded.global_single_threaded.io();
25#expect_stdout="good morning\n"25#expect_stdout="good morning\n"
2626
27#update=reference new declaration27#update=reference new declaration
...@@ -32,7 +32,7 @@ pub fn main() !void {...@@ -32,7 +32,7 @@ pub fn main() !void {
32}32}
33const foo = "good morning\n";33const foo = "good morning\n";
34const bar = "good evening\n";34const bar = "good evening\n";
35const io = std.Io.Threaded.global_single_threaded.ioBasic();35const io = std.Io.Threaded.global_single_threaded.io();
36#expect_stdout="good evening\n"36#expect_stdout="good evening\n"
3737
38#update=reference missing declaration38#update=reference missing declaration
...@@ -43,7 +43,7 @@ pub fn main() !void {...@@ -43,7 +43,7 @@ pub fn main() !void {
43}43}
44const foo = "good morning\n";44const foo = "good morning\n";
45const bar = "good evening\n";45const bar = "good evening\n";
46const io = std.Io.Threaded.global_single_threaded.ioBasic();46const io = std.Io.Threaded.global_single_threaded.io();
47#expect_error=main.zig:3:52: error: use of undeclared identifier 'qux'47#expect_error=main.zig:3:52: error: use of undeclared identifier 'qux'
4848
49#update=add missing declaration49#update=add missing declaration
...@@ -55,7 +55,7 @@ pub fn main() !void {...@@ -55,7 +55,7 @@ pub fn main() !void {
55const foo = "good morning\n";55const foo = "good morning\n";
56const bar = "good evening\n";56const bar = "good evening\n";
57const qux = "good night\n";57const qux = "good night\n";
58const io = std.Io.Threaded.global_single_threaded.ioBasic();58const io = std.Io.Threaded.global_single_threaded.io();
59#expect_stdout="good night\n"59#expect_stdout="good night\n"
6060
61#update=remove unused declarations61#update=remove unused declarations
...@@ -65,5 +65,5 @@ pub fn main() !void {...@@ -65,5 +65,5 @@ pub fn main() !void {
65 try std.Io.File.stdout().writeStreamingAll(io, qux);65 try std.Io.File.stdout().writeStreamingAll(io, qux);
66}66}
67const qux = "good night\n";67const qux = "good night\n";
68const io = std.Io.Threaded.global_single_threaded.ioBasic();68const io = std.Io.Threaded.global_single_threaded.io();
69#expect_stdout="good night\n"69#expect_stdout="good night\n"
test/incremental/add_decl_namespaced+6-6
...@@ -10,7 +10,7 @@ pub fn main() !void {...@@ -10,7 +10,7 @@ pub fn main() !void {
10 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);10 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);
11}11}
12const foo = "good morning\n";12const foo = "good morning\n";
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#expect_stdout="good morning\n"14#expect_stdout="good morning\n"
1515
16#update=add new declaration16#update=add new declaration
...@@ -21,7 +21,7 @@ pub fn main() !void {...@@ -21,7 +21,7 @@ pub fn main() !void {
21}21}
22const foo = "good morning\n";22const foo = "good morning\n";
23const bar = "good evening\n";23const bar = "good evening\n";
24const io = std.Io.Threaded.global_single_threaded.ioBasic();24const io = std.Io.Threaded.global_single_threaded.io();
25#expect_stdout="good morning\n"25#expect_stdout="good morning\n"
2626
27#update=reference new declaration27#update=reference new declaration
...@@ -32,7 +32,7 @@ pub fn main() !void {...@@ -32,7 +32,7 @@ pub fn main() !void {
32}32}
33const foo = "good morning\n";33const foo = "good morning\n";
34const bar = "good evening\n";34const bar = "good evening\n";
35const io = std.Io.Threaded.global_single_threaded.ioBasic();35const io = std.Io.Threaded.global_single_threaded.io();
36#expect_stdout="good evening\n"36#expect_stdout="good evening\n"
3737
38#update=reference missing declaration38#update=reference missing declaration
...@@ -43,7 +43,7 @@ pub fn main() !void {...@@ -43,7 +43,7 @@ pub fn main() !void {
43}43}
44const foo = "good morning\n";44const foo = "good morning\n";
45const bar = "good evening\n";45const bar = "good evening\n";
46const io = std.Io.Threaded.global_single_threaded.ioBasic();46const io = std.Io.Threaded.global_single_threaded.io();
47#expect_error=main.zig:3:59: error: root source file struct 'main' has no member named 'qux'47#expect_error=main.zig:3:59: error: root source file struct 'main' has no member named 'qux'
48#expect_error=main.zig:1:1: note: struct declared here48#expect_error=main.zig:1:1: note: struct declared here
4949
...@@ -56,7 +56,7 @@ pub fn main() !void {...@@ -56,7 +56,7 @@ pub fn main() !void {
56const foo = "good morning\n";56const foo = "good morning\n";
57const bar = "good evening\n";57const bar = "good evening\n";
58const qux = "good night\n";58const qux = "good night\n";
59const io = std.Io.Threaded.global_single_threaded.ioBasic();59const io = std.Io.Threaded.global_single_threaded.io();
60#expect_stdout="good night\n"60#expect_stdout="good night\n"
6161
62#update=remove unused declarations62#update=remove unused declarations
...@@ -66,5 +66,5 @@ pub fn main() !void {...@@ -66,5 +66,5 @@ pub fn main() !void {
66 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);66 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);
67}67}
68const qux = "good night\n";68const qux = "good night\n";
69const io = std.Io.Threaded.global_single_threaded.ioBasic();69const io = std.Io.Threaded.global_single_threaded.io();
70#expect_stdout="good night\n"70#expect_stdout="good night\n"
test/incremental/bad_import+2-2
...@@ -11,7 +11,7 @@ pub fn main() !void {...@@ -11,7 +11,7 @@ pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, "success\n");11 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
12}12}
13const std = @import("std");13const std = @import("std");
14const io = std.Io.Threaded.global_single_threaded.ioBasic();14const io = std.Io.Threaded.global_single_threaded.io();
15#file=foo.zig15#file=foo.zig
16comptime {16comptime {
17 _ = @import("bad.zig");17 _ = @import("bad.zig");
...@@ -34,5 +34,5 @@ pub fn main() !void {...@@ -34,5 +34,5 @@ pub fn main() !void {
34 try std.Io.File.stdout().writeStreamingAll(io, "success\n");34 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
35}35}
36const std = @import("std");36const std = @import("std");
37const io = std.Io.Threaded.global_single_threaded.ioBasic();37const io = std.Io.Threaded.global_single_threaded.io();
38#expect_stdout="success\n"38#expect_stdout="success\n"
test/incremental/change_embed_file+3-3
...@@ -10,7 +10,7 @@ const string = @embedFile("string.txt");...@@ -10,7 +10,7 @@ const string = @embedFile("string.txt");
10pub fn main() !void {10pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, string);11 try std.Io.File.stdout().writeStreamingAll(io, string);
12}12}
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#file=string.txt14#file=string.txt
15Hello, World!15Hello, World!
16#expect_stdout="Hello, World!\n"16#expect_stdout="Hello, World!\n"
...@@ -31,7 +31,7 @@ const string = @embedFile("string.txt");...@@ -31,7 +31,7 @@ const string = @embedFile("string.txt");
31pub fn main() !void {31pub fn main() !void {
32 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");32 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
33}33}
34const io = std.Io.Threaded.global_single_threaded.ioBasic();34const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="a hardcoded string\n"35#expect_stdout="a hardcoded string\n"
3636
37#update=re-introduce reference to file37#update=re-introduce reference to file
...@@ -41,7 +41,7 @@ const string = @embedFile("string.txt");...@@ -41,7 +41,7 @@ const string = @embedFile("string.txt");
41pub fn main() !void {41pub fn main() !void {
42 try std.Io.File.stdout().writeStreamingAll(io, string);42 try std.Io.File.stdout().writeStreamingAll(io, string);
43}43}
44const io = std.Io.Threaded.global_single_threaded.ioBasic();44const io = std.Io.Threaded.global_single_threaded.io();
45#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound45#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound
4646
47#update=recreate file47#update=recreate file
test/incremental/change_enum_tag_type+3-3
...@@ -19,7 +19,7 @@ pub fn main() !void {...@@ -19,7 +19,7 @@ pub fn main() !void {
19 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});19 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
20}20}
21const std = @import("std");21const std = @import("std");
22const io = std.Io.Threaded.global_single_threaded.ioBasic();22const io = std.Io.Threaded.global_single_threaded.io();
23#expect_stdout="a\n"23#expect_stdout="a\n"
24#update=too many enum fields24#update=too many enum fields
25#file=main.zig25#file=main.zig
...@@ -43,7 +43,7 @@ comptime {...@@ -43,7 +43,7 @@ comptime {
43 std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag);43 std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag);
44}44}
45const std = @import("std");45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.ioBasic();46const io = std.Io.Threaded.global_single_threaded.io();
47#expect_error=main.zig:7:5: error: enumeration value '4' too large for type 'u2'47#expect_error=main.zig:7:5: error: enumeration value '4' too large for type 'u2'
48#update=increase tag size48#update=increase tag size
49#file=main.zig49#file=main.zig
...@@ -62,5 +62,5 @@ pub fn main() !void {...@@ -62,5 +62,5 @@ pub fn main() !void {
62 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});62 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
63}63}
64const std = @import("std");64const std = @import("std");
65const io = std.Io.Threaded.global_single_threaded.ioBasic();65const io = std.Io.Threaded.global_single_threaded.io();
66#expect_stdout="a\n"66#expect_stdout="a\n"
test/incremental/change_exports+6-6
...@@ -21,7 +21,7 @@ pub fn main() !void {...@@ -21,7 +21,7 @@ pub fn main() !void {
21 try stdout_writer.interface.print("{}\n", .{S.bar});21 try stdout_writer.interface.print("{}\n", .{S.bar});
22}22}
23const std = @import("std");23const std = @import("std");
24const io = std.Io.Threaded.global_single_threaded.ioBasic();24const io = std.Io.Threaded.global_single_threaded.io();
25#expect_stdout="123\n"25#expect_stdout="123\n"
2626
27#update=add conflict27#update=add conflict
...@@ -44,7 +44,7 @@ pub fn main() !void {...@@ -44,7 +44,7 @@ pub fn main() !void {
44 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });44 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
45}45}
46const std = @import("std");46const std = @import("std");
47const io = std.Io.Threaded.global_single_threaded.ioBasic();47const io = std.Io.Threaded.global_single_threaded.io();
48#expect_error=main.zig:6:5: error: exported symbol collision: foo48#expect_error=main.zig:6:5: error: exported symbol collision: foo
49#expect_error=main.zig:1:1: note: other symbol here49#expect_error=main.zig:1:1: note: other symbol here
5050
...@@ -68,7 +68,7 @@ pub fn main() !void {...@@ -68,7 +68,7 @@ pub fn main() !void {
68 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });68 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
69}69}
70const std = @import("std");70const std = @import("std");
71const io = std.Io.Threaded.global_single_threaded.ioBasic();71const io = std.Io.Threaded.global_single_threaded.io();
72#expect_stdout="123 456\n"72#expect_stdout="123 456\n"
7373
74#update=put exports in decl74#update=put exports in decl
...@@ -94,7 +94,7 @@ pub fn main() !void {...@@ -94,7 +94,7 @@ pub fn main() !void {
94 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });94 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
95}95}
96const std = @import("std");96const std = @import("std");
97const io = std.Io.Threaded.global_single_threaded.ioBasic();97const io = std.Io.Threaded.global_single_threaded.io();
98#expect_stdout="123 456\n"98#expect_stdout="123 456\n"
9999
100#update=remove reference to exporting decl100#update=remove reference to exporting decl
...@@ -141,7 +141,7 @@ pub fn main() !void {...@@ -141,7 +141,7 @@ pub fn main() !void {
141 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });141 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
142}142}
143const std = @import("std");143const std = @import("std");
144const io = std.Io.Threaded.global_single_threaded.ioBasic();144const io = std.Io.Threaded.global_single_threaded.io();
145#expect_stdout="123 456\n"145#expect_stdout="123 456\n"
146146
147#update=reintroduce reference to exporting decl, introducing conflict147#update=reintroduce reference to exporting decl, introducing conflict
...@@ -167,7 +167,7 @@ pub fn main() !void {...@@ -167,7 +167,7 @@ pub fn main() !void {
167 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });167 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
168}168}
169const std = @import("std");169const std = @import("std");
170const io = std.Io.Threaded.global_single_threaded.ioBasic();170const io = std.Io.Threaded.global_single_threaded.io();
171#expect_error=main.zig:5:5: error: exported symbol collision: bar171#expect_error=main.zig:5:5: error: exported symbol collision: bar
172#expect_error=main.zig:2:1: note: other symbol here172#expect_error=main.zig:2:1: note: other symbol here
173#expect_error=main.zig:6:5: error: exported symbol collision: other173#expect_error=main.zig:6:5: error: exported symbol collision: other
test/incremental/change_fn_type+3-3
...@@ -12,7 +12,7 @@ fn foo(x: u8) !void {...@@ -12,7 +12,7 @@ fn foo(x: u8) !void {
12 return stdout_writer.interface.print("{d}\n", .{x});12 return stdout_writer.interface.print("{d}\n", .{x});
13}13}
14const std = @import("std");14const std = @import("std");
15const io = std.Io.Threaded.global_single_threaded.ioBasic();15const io = std.Io.Threaded.global_single_threaded.io();
16#expect_stdout="123\n"16#expect_stdout="123\n"
1717
18#update=change function type18#update=change function type
...@@ -25,7 +25,7 @@ fn foo(x: i64) !void {...@@ -25,7 +25,7 @@ fn foo(x: i64) !void {
25 return stdout_writer.interface.print("{d}\n", .{x});25 return stdout_writer.interface.print("{d}\n", .{x});
26}26}
27const std = @import("std");27const std = @import("std");
28const io = std.Io.Threaded.global_single_threaded.ioBasic();28const io = std.Io.Threaded.global_single_threaded.io();
29#expect_stdout="123\n"29#expect_stdout="123\n"
3030
31#update=change function argument31#update=change function argument
...@@ -38,5 +38,5 @@ fn foo(x: i64) !void {...@@ -38,5 +38,5 @@ fn foo(x: i64) !void {
38 return stdout_writer.interface.print("{d}\n", .{x});38 return stdout_writer.interface.print("{d}\n", .{x});
39}39}
40const std = @import("std");40const std = @import("std");
41const io = std.Io.Threaded.global_single_threaded.ioBasic();41const io = std.Io.Threaded.global_single_threaded.io();
42#expect_stdout="-42\n"42#expect_stdout="-42\n"
test/incremental/change_generic_line_number+2-2
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4#update=initial version4#update=initial version
5#file=main.zig5#file=main.zig
6const std = @import("std");6const std = @import("std");
7const io = std.Io.Threaded.global_single_threaded.ioBasic();7const io = std.Io.Threaded.global_single_threaded.io();
8fn Printer(message: []const u8) type {8fn Printer(message: []const u8) type {
9 return struct {9 return struct {
10 fn print() !void {10 fn print() !void {
...@@ -20,7 +20,7 @@ pub fn main() !void {...@@ -20,7 +20,7 @@ pub fn main() !void {
20#update=change line number20#update=change line number
21#file=main.zig21#file=main.zig
22const std = @import("std");22const std = @import("std");
23const io = std.Io.Threaded.global_single_threaded.ioBasic();23const io = std.Io.Threaded.global_single_threaded.io();
2424
25fn Printer(message: []const u8) type {25fn Printer(message: []const u8) type {
26 return struct {26 return struct {
test/incremental/change_line_number+2-2
...@@ -7,7 +7,7 @@ const std = @import("std");...@@ -7,7 +7,7 @@ const std = @import("std");
7pub fn main() !void {7pub fn main() !void {
8 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");8 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
9}9}
10const io = std.Io.Threaded.global_single_threaded.ioBasic();10const io = std.Io.Threaded.global_single_threaded.io();
11#expect_stdout="foo\n"11#expect_stdout="foo\n"
12#update=change line number12#update=change line number
13#file=main.zig13#file=main.zig
...@@ -16,5 +16,5 @@ const std = @import("std");...@@ -16,5 +16,5 @@ const std = @import("std");
16pub fn main() !void {16pub fn main() !void {
17 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");17 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
18}18}
19const io = std.Io.Threaded.global_single_threaded.ioBasic();19const io = std.Io.Threaded.global_single_threaded.io();
20#expect_stdout="foo\n"20#expect_stdout="foo\n"
test/incremental/change_panic_handler+3-3
...@@ -17,7 +17,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -17,7 +17,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
17 std.process.exit(0);17 std.process.exit(0);
18}18}
19const std = @import("std");19const std = @import("std");
20const io = std.Io.Threaded.global_single_threaded.ioBasic();20const io = std.Io.Threaded.global_single_threaded.io();
21#expect_stdout="panic message: integer overflow\n"21#expect_stdout="panic message: integer overflow\n"
2222
23#update=change the panic handler body23#update=change the panic handler body
...@@ -35,7 +35,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -35,7 +35,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
35 std.process.exit(0);35 std.process.exit(0);
36}36}
37const std = @import("std");37const std = @import("std");
38const io = std.Io.Threaded.global_single_threaded.ioBasic();38const io = std.Io.Threaded.global_single_threaded.io();
39#expect_stdout="new panic message: integer overflow\n"39#expect_stdout="new panic message: integer overflow\n"
4040
41#update=change the panic handler function value41#update=change the panic handler function value
...@@ -53,5 +53,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {...@@ -53,5 +53,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
53 std.process.exit(0);53 std.process.exit(0);
54}54}
55const std = @import("std");55const std = @import("std");
56const io = std.Io.Threaded.global_single_threaded.ioBasic();56const io = std.Io.Threaded.global_single_threaded.io();
57#expect_stdout="third panic message: integer overflow\n"57#expect_stdout="third panic message: integer overflow\n"
test/incremental/change_panic_handler_explicit+3-3
...@@ -47,7 +47,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -47,7 +47,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
47 std.process.exit(0);47 std.process.exit(0);
48}48}
49const std = @import("std");49const std = @import("std");
50const io = std.Io.Threaded.global_single_threaded.ioBasic();50const io = std.Io.Threaded.global_single_threaded.io();
51#expect_stdout="panic message: integer overflow\n"51#expect_stdout="panic message: integer overflow\n"
5252
53#update=change the panic handler body53#update=change the panic handler body
...@@ -95,7 +95,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -95,7 +95,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
95 std.process.exit(0);95 std.process.exit(0);
96}96}
97const std = @import("std");97const std = @import("std");
98const io = std.Io.Threaded.global_single_threaded.ioBasic();98const io = std.Io.Threaded.global_single_threaded.io();
99#expect_stdout="new panic message: integer overflow\n"99#expect_stdout="new panic message: integer overflow\n"
100100
101#update=change the panic handler function value101#update=change the panic handler function value
...@@ -143,5 +143,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {...@@ -143,5 +143,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
143 std.process.exit(0);143 std.process.exit(0);
144}144}
145const std = @import("std");145const std = @import("std");
146const io = std.Io.Threaded.global_single_threaded.ioBasic();146const io = std.Io.Threaded.global_single_threaded.io();
147#expect_stdout="third panic message: integer overflow\n"147#expect_stdout="third panic message: integer overflow\n"
test/incremental/change_shift_op+2-2
...@@ -13,7 +13,7 @@ fn foo(x: u16) !void {...@@ -13,7 +13,7 @@ fn foo(x: u16) !void {
13 try stdout_writer.interface.print("0x{x}\n", .{x << 4});13 try stdout_writer.interface.print("0x{x}\n", .{x << 4});
14}14}
15const std = @import("std");15const std = @import("std");
16const io = std.Io.Threaded.global_single_threaded.ioBasic();16const io = std.Io.Threaded.global_single_threaded.io();
17#expect_stdout="0x3000\n"17#expect_stdout="0x3000\n"
18#update=change to right shift18#update=change to right shift
19#file=main.zig19#file=main.zig
...@@ -25,5 +25,5 @@ fn foo(x: u16) !void {...@@ -25,5 +25,5 @@ fn foo(x: u16) !void {
25 try stdout_writer.interface.print("0x{x}\n", .{x >> 4});25 try stdout_writer.interface.print("0x{x}\n", .{x >> 4});
26}26}
27const std = @import("std");27const std = @import("std");
28const io = std.Io.Threaded.global_single_threaded.ioBasic();28const io = std.Io.Threaded.global_single_threaded.io();
29#expect_stdout="0x130\n"29#expect_stdout="0x130\n"
test/incremental/change_struct_same_fields+3-3
...@@ -18,7 +18,7 @@ fn foo(val: *const S) !void {...@@ -18,7 +18,7 @@ fn foo(val: *const S) !void {
18 );18 );
19}19}
20const std = @import("std");20const std = @import("std");
21const io = std.Io.Threaded.global_single_threaded.ioBasic();21const io = std.Io.Threaded.global_single_threaded.io();
22#expect_stdout="100 200\n"22#expect_stdout="100 200\n"
2323
24#update=change struct layout24#update=change struct layout
...@@ -36,7 +36,7 @@ fn foo(val: *const S) !void {...@@ -36,7 +36,7 @@ fn foo(val: *const S) !void {
36 );36 );
37}37}
38const std = @import("std");38const std = @import("std");
39const io = std.Io.Threaded.global_single_threaded.ioBasic();39const io = std.Io.Threaded.global_single_threaded.io();
40#expect_stdout="100 200\n"40#expect_stdout="100 200\n"
4141
42#update=change values42#update=change values
...@@ -54,5 +54,5 @@ fn foo(val: *const S) !void {...@@ -54,5 +54,5 @@ fn foo(val: *const S) !void {
54 );54 );
55}55}
56const std = @import("std");56const std = @import("std");
57const io = std.Io.Threaded.global_single_threaded.ioBasic();57const io = std.Io.Threaded.global_single_threaded.io();
58#expect_stdout="1234 5678\n"58#expect_stdout="1234 5678\n"
test/incremental/change_zon_file+3-3
...@@ -10,7 +10,7 @@ const message: []const u8 = @import("message.zon");...@@ -10,7 +10,7 @@ const message: []const u8 = @import("message.zon");
10pub fn main() !void {10pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, message);11 try std.Io.File.stdout().writeStreamingAll(io, message);
12}12}
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#file=message.zon14#file=message.zon
15"Hello, World!\n"15"Hello, World!\n"
16#expect_stdout="Hello, World!\n"16#expect_stdout="Hello, World!\n"
...@@ -32,7 +32,7 @@ const message: []const u8 = @import("message.zon");...@@ -32,7 +32,7 @@ const message: []const u8 = @import("message.zon");
32pub fn main() !void {32pub fn main() !void {
33 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");33 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
34}34}
35const io = std.Io.Threaded.global_single_threaded.ioBasic();35const io = std.Io.Threaded.global_single_threaded.io();
36#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound36#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
37#expect_error=main.zig:2:37: note: file imported here37#expect_error=main.zig:2:37: note: file imported here
3838
...@@ -48,5 +48,5 @@ const message: []const u8 = @import("message.zon");...@@ -48,5 +48,5 @@ const message: []const u8 = @import("message.zon");
48pub fn main() !void {48pub fn main() !void {
49 try std.Io.File.stdout().writeStreamingAll(io, message);49 try std.Io.File.stdout().writeStreamingAll(io, message);
50}50}
51const io = std.Io.Threaded.global_single_threaded.ioBasic();51const io = std.Io.Threaded.global_single_threaded.io();
52#expect_stdout="We're back, World!\n"52#expect_stdout="We're back, World!\n"
test/incremental/change_zon_file_no_result_type+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6#update=initial version6#update=initial version
7#file=main.zig7#file=main.zig
8const std = @import("std");8const std = @import("std");
9const io = std.Io.Threaded.global_single_threaded.ioBasic();9const io = std.Io.Threaded.global_single_threaded.io();
10pub fn main() !void {10pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message);11 try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message);
12}12}
test/incremental/compile_log+3-3
...@@ -10,7 +10,7 @@ const std = @import("std");...@@ -10,7 +10,7 @@ const std = @import("std");
10pub fn main() !void {10pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");11 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
12}12}
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#expect_stdout="Hello, World!\n"14#expect_stdout="Hello, World!\n"
1515
16#update=add compile log16#update=add compile log
...@@ -20,7 +20,7 @@ pub fn main() !void {...@@ -20,7 +20,7 @@ pub fn main() !void {
20 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");20 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
21 @compileLog("this is a log");21 @compileLog("this is a log");
22}22}
23const io = std.Io.Threaded.global_single_threaded.ioBasic();23const io = std.Io.Threaded.global_single_threaded.io();
24#expect_error=main.zig:4:5: error: found compile log statement24#expect_error=main.zig:4:5: error: found compile log statement
25#expect_compile_log=@as(*const [13:0]u8, "this is a log")25#expect_compile_log=@as(*const [13:0]u8, "this is a log")
2626
...@@ -30,5 +30,5 @@ const std = @import("std");...@@ -30,5 +30,5 @@ const std = @import("std");
30pub fn main() !void {30pub fn main() !void {
31 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");31 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
32}32}
33const io = std.Io.Threaded.global_single_threaded.ioBasic();33const io = std.Io.Threaded.global_single_threaded.io();
34#expect_stdout="Hello, World!\n"34#expect_stdout="Hello, World!\n"
test/incremental/fix_astgen_failure+3-3
...@@ -19,7 +19,7 @@ const std = @import("std");...@@ -19,7 +19,7 @@ const std = @import("std");
19pub fn hello() !void {19pub fn hello() !void {
20 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");20 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
21}21}
22const io = std.Io.Threaded.global_single_threaded.ioBasic();22const io = std.Io.Threaded.global_single_threaded.io();
23#expect_stdout="Hello, World!\n"23#expect_stdout="Hello, World!\n"
24#update=add new error24#update=add new error
25#file=foo.zig25#file=foo.zig
...@@ -27,7 +27,7 @@ const std = @import("std");...@@ -27,7 +27,7 @@ const std = @import("std");
27pub fn hello() !void {27pub fn hello() !void {
28 try std.Io.File.stdout().writeStreamingAll(io, hello_str);28 try std.Io.File.stdout().writeStreamingAll(io, hello_str);
29}29}
30const io = std.Io.Threaded.global_single_threaded.ioBasic();30const io = std.Io.Threaded.global_single_threaded.io();
31#expect_error=foo.zig:3:52: error: use of undeclared identifier 'hello_str'31#expect_error=foo.zig:3:52: error: use of undeclared identifier 'hello_str'
32#update=fix the new error32#update=fix the new error
33#file=foo.zig33#file=foo.zig
...@@ -36,5 +36,5 @@ const hello_str = "Hello, World! Again!\n";...@@ -36,5 +36,5 @@ const hello_str = "Hello, World! Again!\n";
36pub fn hello() !void {36pub fn hello() !void {
37 try std.Io.File.stdout().writeStreamingAll(io, hello_str);37 try std.Io.File.stdout().writeStreamingAll(io, hello_str);
38}38}
39const io = std.Io.Threaded.global_single_threaded.ioBasic();39const io = std.Io.Threaded.global_single_threaded.io();
40#expect_stdout="Hello, World! Again!\n"40#expect_stdout="Hello, World! Again!\n"
test/incremental/function_becomes_inline+3-3
...@@ -11,7 +11,7 @@ fn foo() !void {...@@ -11,7 +11,7 @@ fn foo() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");11 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
12}12}
13const std = @import("std");13const std = @import("std");
14const io = std.Io.Threaded.global_single_threaded.ioBasic();14const io = std.Io.Threaded.global_single_threaded.io();
15#expect_stdout="Hello, World!\n"15#expect_stdout="Hello, World!\n"
1616
17#update=make function inline17#update=make function inline
...@@ -23,7 +23,7 @@ inline fn foo() !void {...@@ -23,7 +23,7 @@ inline fn foo() !void {
23 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");23 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
24}24}
25const std = @import("std");25const std = @import("std");
26const io = std.Io.Threaded.global_single_threaded.ioBasic();26const io = std.Io.Threaded.global_single_threaded.io();
27#expect_stdout="Hello, World!\n"27#expect_stdout="Hello, World!\n"
2828
29#update=change string29#update=change string
...@@ -35,5 +35,5 @@ inline fn foo() !void {...@@ -35,5 +35,5 @@ inline fn foo() !void {
35 try std.Io.File.stdout().writeStreamingAll(io, "Hello, `inline` World!\n");35 try std.Io.File.stdout().writeStreamingAll(io, "Hello, `inline` World!\n");
36}36}
37const std = @import("std");37const std = @import("std");
38const io = std.Io.Threaded.global_single_threaded.ioBasic();38const io = std.Io.Threaded.global_single_threaded.io();
39#expect_stdout="Hello, `inline` World!\n"39#expect_stdout="Hello, `inline` World!\n"
test/incremental/hello+2-2
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6#update=initial version6#update=initial version
7#file=main.zig7#file=main.zig
8const std = @import("std");8const std = @import("std");
9const io = std.Io.Threaded.global_single_threaded.ioBasic();9const io = std.Io.Threaded.global_single_threaded.io();
10pub fn main() !void {10pub fn main() !void {
11 try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");11 try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");
12}12}
...@@ -14,7 +14,7 @@ pub fn main() !void {...@@ -14,7 +14,7 @@ pub fn main() !void {
14#update=change the string14#update=change the string
15#file=main.zig15#file=main.zig
16const std = @import("std");16const std = @import("std");
17const io = std.Io.Threaded.global_single_threaded.ioBasic();17const io = std.Io.Threaded.global_single_threaded.io();
18pub fn main() !void {18pub fn main() !void {
19 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");19 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
20}20}
test/incremental/make_decl_pub+2-2
...@@ -14,7 +14,7 @@ const std = @import("std");...@@ -14,7 +14,7 @@ const std = @import("std");
14fn hello() !void {14fn hello() !void {
15 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");15 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
16}16}
17const io = std.Io.Threaded.global_single_threaded.ioBasic();17const io = std.Io.Threaded.global_single_threaded.io();
18#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub'18#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub'
19#expect_error=foo.zig:2:1: note: declared here19#expect_error=foo.zig:2:1: note: declared here
2020
...@@ -24,5 +24,5 @@ const std = @import("std");...@@ -24,5 +24,5 @@ const std = @import("std");
24pub fn hello() !void {24pub fn hello() !void {
25 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");25 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
26}26}
27const io = std.Io.Threaded.global_single_threaded.ioBasic();27const io = std.Io.Threaded.global_single_threaded.io();
28#expect_stdout="Hello, World!\n"28#expect_stdout="Hello, World!\n"
test/incremental/modify_inline_fn+2-2
...@@ -13,7 +13,7 @@ pub fn main() !void {...@@ -13,7 +13,7 @@ pub fn main() !void {
13inline fn getStr() []const u8 {13inline fn getStr() []const u8 {
14 return "foo\n";14 return "foo\n";
15}15}
16const io = std.Io.Threaded.global_single_threaded.ioBasic();16const io = std.Io.Threaded.global_single_threaded.io();
17#expect_stdout="foo\n"17#expect_stdout="foo\n"
18#update=change the string18#update=change the string
19#file=main.zig19#file=main.zig
...@@ -25,5 +25,5 @@ pub fn main() !void {...@@ -25,5 +25,5 @@ pub fn main() !void {
25inline fn getStr() []const u8 {25inline fn getStr() []const u8 {
26 return "bar\n";26 return "bar\n";
27}27}
28const io = std.Io.Threaded.global_single_threaded.ioBasic();28const io = std.Io.Threaded.global_single_threaded.io();
29#expect_stdout="bar\n"29#expect_stdout="bar\n"
test/incremental/move_src+2-2
...@@ -16,7 +16,7 @@ fn foo() u32 {...@@ -16,7 +16,7 @@ fn foo() u32 {
16fn bar() u32 {16fn bar() u32 {
17 return 123;17 return 123;
18}18}
19const io = std.Io.Threaded.global_single_threaded.ioBasic();19const io = std.Io.Threaded.global_single_threaded.io();
20#expect_stdout="7 123\n"20#expect_stdout="7 123\n"
2121
22#update=add newline22#update=add newline
...@@ -33,5 +33,5 @@ fn foo() u32 {...@@ -33,5 +33,5 @@ fn foo() u32 {
33fn bar() u32 {33fn bar() u32 {
34 return 123;34 return 123;
35}35}
36const io = std.Io.Threaded.global_single_threaded.ioBasic();36const io = std.Io.Threaded.global_single_threaded.io();
37#expect_stdout="8 123\n"37#expect_stdout="8 123\n"
test/incremental/no_change_preserves_tag_names+2-2
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
7#file=main.zig7#file=main.zig
8const std = @import("std");8const std = @import("std");
9var some_enum: enum { first, second } = .first;9var some_enum: enum { first, second } = .first;
10const io = std.Io.Threaded.global_single_threaded.ioBasic();10const io = std.Io.Threaded.global_single_threaded.io();
11pub fn main() !void {11pub fn main() !void {
12 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));12 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
13}13}
...@@ -16,7 +16,7 @@ pub fn main() !void {...@@ -16,7 +16,7 @@ pub fn main() !void {
16#file=main.zig16#file=main.zig
17const std = @import("std");17const std = @import("std");
18var some_enum: enum { first, second } = .first;18var some_enum: enum { first, second } = .first;
19const io = std.Io.Threaded.global_single_threaded.ioBasic();19const io = std.Io.Threaded.global_single_threaded.io();
20pub fn main() !void {20pub fn main() !void {
21 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));21 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
22}22}
test/incremental/recursive_function_becomes_non_recursive+2-2
...@@ -14,7 +14,7 @@ fn foo(recurse: bool) !void {...@@ -14,7 +14,7 @@ fn foo(recurse: bool) !void {
14 try stdout.writeStreamingAll(io, "non-recursive path\n");14 try stdout.writeStreamingAll(io, "non-recursive path\n");
15}15}
16const std = @import("std");16const std = @import("std");
17const io = std.Io.Threaded.global_single_threaded.ioBasic();17const io = std.Io.Threaded.global_single_threaded.io();
18#expect_stdout="non-recursive path\n"18#expect_stdout="non-recursive path\n"
1919
20#update=eliminate recursion and change argument20#update=eliminate recursion and change argument
...@@ -28,5 +28,5 @@ fn foo(recurse: bool) !void {...@@ -28,5 +28,5 @@ fn foo(recurse: bool) !void {
28 try stdout.writeStreamingAll(io, "non-recursive path\n");28 try stdout.writeStreamingAll(io, "non-recursive path\n");
29}29}
30const std = @import("std");30const std = @import("std");
31const io = std.Io.Threaded.global_single_threaded.ioBasic();31const io = std.Io.Threaded.global_single_threaded.io();
32#expect_stdout="x==1\n"32#expect_stdout="x==1\n"
test/incremental/remove_enum_field+2-2
...@@ -14,7 +14,7 @@ pub fn main() !void {...@@ -14,7 +14,7 @@ pub fn main() !void {
14 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});14 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
15}15}
16const std = @import("std");16const std = @import("std");
17const io = std.Io.Threaded.global_single_threaded.ioBasic();17const io = std.Io.Threaded.global_single_threaded.io();
18#expect_stdout="1\n"18#expect_stdout="1\n"
19#update=remove enum field19#update=remove enum field
20#file=main.zig20#file=main.zig
...@@ -27,6 +27,6 @@ pub fn main() !void {...@@ -27,6 +27,6 @@ pub fn main() !void {
27 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});27 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
28}28}
29const std = @import("std");29const std = @import("std");
30const io = std.Io.Threaded.global_single_threaded.ioBasic();30const io = std.Io.Threaded.global_single_threaded.io();
31#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo'31#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo'
32#expect_error=main.zig:1:16: note: enum declared here32#expect_error=main.zig:1:16: note: enum declared here
test/incremental/unreferenced_error+4-4
...@@ -10,7 +10,7 @@ pub fn main() !void {...@@ -10,7 +10,7 @@ pub fn main() !void {
10 try std.Io.File.stdout().writeStreamingAll(io, a);10 try std.Io.File.stdout().writeStreamingAll(io, a);
11}11}
12const a = "Hello, World!\n";12const a = "Hello, World!\n";
13const io = std.Io.Threaded.global_single_threaded.ioBasic();13const io = std.Io.Threaded.global_single_threaded.io();
14#expect_stdout="Hello, World!\n"14#expect_stdout="Hello, World!\n"
1515
16#update=introduce compile error16#update=introduce compile error
...@@ -20,7 +20,7 @@ pub fn main() !void {...@@ -20,7 +20,7 @@ pub fn main() !void {
20 try std.Io.File.stdout().writeStreamingAll(io, a);20 try std.Io.File.stdout().writeStreamingAll(io, a);
21}21}
22const a = @compileError("bad a");22const a = @compileError("bad a");
23const io = std.Io.Threaded.global_single_threaded.ioBasic();23const io = std.Io.Threaded.global_single_threaded.io();
24#expect_error=main.zig:5:11: error: bad a24#expect_error=main.zig:5:11: error: bad a
2525
26#update=remove error reference26#update=remove error reference
...@@ -31,7 +31,7 @@ pub fn main() !void {...@@ -31,7 +31,7 @@ pub fn main() !void {
31}31}
32const a = @compileError("bad a");32const a = @compileError("bad a");
33const b = "Hi there!\n";33const b = "Hi there!\n";
34const io = std.Io.Threaded.global_single_threaded.ioBasic();34const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="Hi there!\n"35#expect_stdout="Hi there!\n"
3636
37#update=introduce and remove reference to error37#update=introduce and remove reference to error
...@@ -42,5 +42,5 @@ pub fn main() !void {...@@ -42,5 +42,5 @@ pub fn main() !void {
42}42}
43const a = "Back to a\n";43const a = "Back to a\n";
44const b = @compileError("bad b");44const b = @compileError("bad b");
45const io = std.Io.Threaded.global_single_threaded.ioBasic();45const io = std.Io.Threaded.global_single_threaded.io();
46#expect_stdout="Back to a\n"46#expect_stdout="Back to a\n"
test/standalone/coff_dwarf/build.zig+3
...@@ -46,6 +46,9 @@ pub fn build(b: *std.Build) void {...@@ -46,6 +46,9 @@ pub fn build(b: *std.Build) void {
46 lib.root_module.addCSourceFile(.{ .file = b.path("shared_lib.c"), .flags = &.{"-gdwarf"} });46 lib.root_module.addCSourceFile(.{ .file = b.path("shared_lib.c"), .flags = &.{"-gdwarf"} });
47 exe.root_module.linkLibrary(lib);47 exe.root_module.linkLibrary(lib);
4848
49 if (target.result.os.tag == .windows)
50 exe.root_module.linkSystemLibrary("ws2_32", .{});
51
49 const run = b.addRunArtifact(exe);52 const run = b.addRunArtifact(exe);
50 run.expectExitCode(0);53 run.expectExitCode(0);
51 run.skip_foreign_checks = true;54 run.skip_foreign_checks = true;
test/standalone/dirname/exists_in.zig+1-1
...@@ -26,7 +26,7 @@ pub fn main(init: std.process.Init) !void {...@@ -26,7 +26,7 @@ pub fn main(init: std.process.Init) !void {
26 return error.BadUsage;26 return error.BadUsage;
27 };27 };
2828
29 const io = std.Io.Threaded.global_single_threaded.ioBasic();29 const io = std.Io.Threaded.global_single_threaded.io();
3030
31 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});31 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
32 defer dir.close(io);32 defer dir.close(io);
test/standalone/dirname/touch.zig+1-1
...@@ -21,7 +21,7 @@ pub fn main(init: std.process.Init) !void {...@@ -21,7 +21,7 @@ pub fn main(init: std.process.Init) !void {
21 const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;21 const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;
22 const basename = std.Io.Dir.path.basename(path);22 const basename = std.Io.Dir.path.basename(path);
2323
24 const io = std.Io.Threaded.global_single_threaded.ioBasic();24 const io = std.Io.Threaded.global_single_threaded.io();
2525
26 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});26 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
27 defer dir.close(io);27 defer dir.close(io);
test/standalone/issue_5825/build.zig+1
...@@ -34,6 +34,7 @@ pub fn build(b: *std.Build) void {...@@ -34,6 +34,7 @@ pub fn build(b: *std.Build) void {
34 exe.subsystem = .console;34 exe.subsystem = .console;
35 exe.root_module.linkSystemLibrary("kernel32", .{});35 exe.root_module.linkSystemLibrary("kernel32", .{});
36 exe.root_module.linkSystemLibrary("ntdll", .{});36 exe.root_module.linkSystemLibrary("ntdll", .{});
37 exe.root_module.linkSystemLibrary("ws2_32", .{});
37 exe.root_module.addObject(obj);38 exe.root_module.addObject(obj);
3839
39 // TODO: actually check the output40 // TODO: actually check the output
test/standalone/mix_o_files/build.zig+3
...@@ -16,6 +16,9 @@ pub fn build(b: *std.Build) void {...@@ -16,6 +16,9 @@ pub fn build(b: *std.Build) void {
16 }),16 }),
17 });17 });
1818
19 if (target.result.os.tag == .windows)
20 obj.root_module.linkSystemLibrary("ws2_32", .{});
21
19 const exe = b.addExecutable(.{22 const exe = b.addExecutable(.{
20 .name = "test",23 .name = "test",
21 .root_module = b.createModule(.{24 .root_module = b.createModule(.{
test/standalone/run_cwd/check_file_exists.zig+1-1
...@@ -5,7 +5,7 @@ pub fn main(init: std.process.Init) !void {...@@ -5,7 +5,7 @@ pub fn main(init: std.process.Init) !void {
5 if (args.len != 2) return error.BadUsage;5 if (args.len != 2) return error.BadUsage;
6 const path = args[1];6 const path = args[1];
77
8 const io = std.Io.Threaded.global_single_threaded.ioBasic();8 const io = std.Io.Threaded.global_single_threaded.io();
99
10 std.Io.Dir.cwd().access(io, path, .{}) catch return error.AccessFailed;10 std.Io.Dir.cwd().access(io, path, .{}) catch return error.AccessFailed;
11}11}
test/standalone/shared_library/build.zig+4-1
...@@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void {...@@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void {
5 b.default_step = test_step;5 b.default_step = test_step;
66
7 const optimize: std.builtin.OptimizeMode = .Debug;7 const optimize: std.builtin.OptimizeMode = .Debug;
8 const target = b.graph.host;8 const target = b.standardTargetOptions(.{});
99
10 const exe_names: []const []const u8 = &.{ "test", "test-dync" };10 const exe_names: []const []const u8 = &.{ "test", "test-dync" };
11 const lib_names: []const []const u8 = &.{ "mathtest", "mathtest-dync" };11 const lib_names: []const []const u8 = &.{ "mathtest", "mathtest-dync" };
...@@ -24,6 +24,9 @@ pub fn build(b: *std.Build) void {...@@ -24,6 +24,9 @@ pub fn build(b: *std.Build) void {
24 }),24 }),
25 });25 });
2626
27 if (target.result.os.tag == .windows)
28 lib.root_module.linkSystemLibrary("ws2_32", .{});
29
27 const exe = b.addExecutable(.{30 const exe = b.addExecutable(.{
28 .name = exe_name,31 .name = exe_name,
29 .root_module = b.createModule(.{32 .root_module = b.createModule(.{
test/standalone/windows_argv/build.zig+3
...@@ -20,6 +20,8 @@ pub fn build(b: *std.Build) !void {...@@ -20,6 +20,8 @@ pub fn build(b: *std.Build) !void {
20 .optimize = optimize,20 .optimize = optimize,
21 }),21 }),
22 });22 });
23 lib_gnu.root_module.linkSystemLibrary("ws2_32", .{});
24
23 const verify_gnu = b.addExecutable(.{25 const verify_gnu = b.addExecutable(.{
24 .name = "verify-gnu",26 .name = "verify-gnu",
25 .root_module = b.createModule(.{27 .root_module = b.createModule(.{
...@@ -101,6 +103,7 @@ pub fn build(b: *std.Build) !void {...@@ -101,6 +103,7 @@ pub fn build(b: *std.Build) !void {
101 .flags = &.{ "-DUNICODE", "-D_UNICODE" },103 .flags = &.{ "-DUNICODE", "-D_UNICODE" },
102 });104 });
103 verify_msvc.root_module.linkLibrary(lib_msvc);105 verify_msvc.root_module.linkLibrary(lib_msvc);
106 verify_msvc.root_module.linkSystemLibrary("ws2_32", .{});
104 verify_msvc.root_module.link_libc = true;107 verify_msvc.root_module.link_libc = true;
105108
106 const run_msvc = b.addRunArtifact(fuzz);109 const run_msvc = b.addRunArtifact(fuzz);