| ... | @@ -150,7 +150,6 @@ const Thread = struct { | ... | @@ -150,7 +150,6 @@ const Thread = struct { |
| 150 | const Fiber = struct { | 150 | const Fiber = struct { |
| 151 | required_align: void align(4), | 151 | required_align: void align(4), |
| 152 | context: Io.fiber.Context, | 152 | context: Io.fiber.Context, |
| 153 | await_count: i32, | | |
| 154 | link: union { | 153 | link: union { |
| 155 | awaiter: ?*Fiber, | 154 | awaiter: ?*Fiber, |
| 156 | group: struct { prev: ?*Fiber, next: ?*Fiber }, | 155 | group: struct { prev: ?*Fiber, next: ?*Fiber }, |
| ... | @@ -175,7 +174,6 @@ const Fiber = struct { | ... | @@ -175,7 +174,6 @@ const Fiber = struct { |
| 175 | const Awaiting = enum(u31) { | 174 | const Awaiting = enum(u31) { |
| 176 | nothing = std.math.maxInt(u31), | 175 | nothing = std.math.maxInt(u31), |
| 177 | group = std.math.maxInt(u31) - 1, | 176 | group = std.math.maxInt(u31) - 1, |
| 178 | select = std.math.maxInt(u31) - 2, | | |
| 179 | /// An io_uring fd. | 177 | /// An io_uring fd. |
| 180 | _, | 178 | _, |
| 181 | | 179 | |
| ... | @@ -186,14 +184,14 @@ const Fiber = struct { | ... | @@ -186,14 +184,14 @@ const Fiber = struct { |
| 186 | fn fromIoUringFd(fd: fd_t) Awaiting { | 184 | fn fromIoUringFd(fd: fd_t) Awaiting { |
| 187 | const awaiting: Awaiting = @enumFromInt(fd); | 185 | const awaiting: Awaiting = @enumFromInt(fd); |
| 188 | switch (awaiting) { | 186 | switch (awaiting) { |
| 189 | .nothing, .group, .select => unreachable, | 187 | .nothing, .group => unreachable, |
| 190 | _ => return awaiting, | 188 | _ => return awaiting, |
| 191 | } | 189 | } |
| 192 | } | 190 | } |
| 193 | | 191 | |
| 194 | fn toIoUringFd(awaiting: Awaiting) fd_t { | 192 | fn toIoUringFd(awaiting: Awaiting) fd_t { |
| 195 | switch (awaiting) { | 193 | switch (awaiting) { |
| 196 | .nothing, .group, .select => unreachable, | 194 | .nothing, .group => unreachable, |
| 197 | _ => return @intFromEnum(awaiting), | 195 | _ => return @intFromEnum(awaiting), |
| 198 | } | 196 | } |
| 199 | } | 197 | } |
| ... | @@ -376,9 +374,6 @@ const Fiber = struct { | ... | @@ -376,9 +374,6 @@ const Fiber = struct { |
| 376 | _ = ev.schedule(.current(), .{ .head = fiber, .tail = fiber }); | 374 | _ = ev.schedule(.current(), .{ .head = fiber, .tail = fiber }); |
| 377 | } | 375 | } |
| 378 | }, | 376 | }, |
| 379 | .select => if (@atomicRmw(i32, &fiber.await_count, .Add, 1, .monotonic) == -1) { | | |
| 380 | _ = ev.schedule(.current(), .{ .head = fiber, .tail = fiber }); | | |
| 381 | }, | | |
| 382 | _ => |awaiting| { | 377 | _ => |awaiting| { |
| 383 | const awaiting_io_uring_fd = awaiting.toIoUringFd(); | 378 | const awaiting_io_uring_fd = awaiting.toIoUringFd(); |
| 384 | const thread: *Thread = .current(); | 379 | const thread: *Thread = .current(); |
| ... | @@ -684,8 +679,6 @@ pub fn io(ev: *Evented) Io { | ... | @@ -684,8 +679,6 @@ pub fn io(ev: *Evented) Io { |
| 684 | .swapCancelProtection = swapCancelProtection, | 679 | .swapCancelProtection = swapCancelProtection, |
| 685 | .checkCancel = checkCancel, | 680 | .checkCancel = checkCancel, |
| 686 | | 681 | |
| 687 | .select = select, | | |
| 688 | | | |
| 689 | .futexWait = futexWait, | 682 | .futexWait = futexWait, |
| 690 | .futexWaitUncancelable = futexWaitUncancelable, | 683 | .futexWaitUncancelable = futexWaitUncancelable, |
| 691 | .futexWake = futexWake, | 684 | .futexWake = futexWake, |
| ... | @@ -862,7 +855,6 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v | ... | @@ -862,7 +855,6 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v |
| 862 | main_fiber.* = .{ | 855 | main_fiber.* = .{ |
| 863 | .required_align = {}, | 856 | .required_align = {}, |
| 864 | .context = undefined, | 857 | .context = undefined, |
| 865 | .await_count = 0, | | |
| 866 | .link = .{ .awaiter = null }, | 858 | .link = .{ .awaiter = null }, |
| 867 | .status = .{ .queue_next = null }, | 859 | .status = .{ .queue_next = null }, |
| 868 | .cancel_status = .unrequested, | 860 | .cancel_status = .unrequested, |
| ... | @@ -1266,7 +1258,7 @@ const SwitchMessage = struct { | ... | @@ -1266,7 +1258,7 @@ const SwitchMessage = struct { |
| 1266 | const PendingTask = union(enum) { | 1258 | const PendingTask = union(enum) { |
| 1267 | nothing, | 1259 | nothing, |
| 1268 | reschedule, | 1260 | reschedule, |
| 1269 | await: u31, | 1261 | await: *Fiber, |
| 1270 | group_await: Group, | 1262 | group_await: Group, |
| 1271 | group_cancel: Group, | 1263 | group_cancel: Group, |
| 1272 | batch_await: *Io.Batch, | 1264 | batch_await: *Io.Batch, |
| ... | @@ -1290,10 +1282,11 @@ const SwitchMessage = struct { | ... | @@ -1290,10 +1282,11 @@ const SwitchMessage = struct { |
| 1290 | assert(fiber.status.queue_next == null); | 1282 | assert(fiber.status.queue_next == null); |
| 1291 | _ = ev.schedule(thread, .{ .head = fiber, .tail = fiber }); | 1283 | _ = ev.schedule(thread, .{ .head = fiber, .tail = fiber }); |
| 1292 | }, | 1284 | }, |
| 1293 | .await => |count| { | 1285 | .await => |awaiting| { |
| 1294 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); | 1286 | const awaiter: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); |
| 1295 | if (@atomicRmw(i32, &fiber.await_count, .Sub, count, .monotonic) > 0) | 1287 | assert(awaiter.status.queue_next == null); |
| 1296 | _ = ev.schedule(thread, .{ .head = fiber, .tail = fiber }); | 1288 | if (@atomicRmw(?*Fiber, &awaiting.link.awaiter, .Xchg, awaiter, .acq_rel) == |
| | 1289 | Fiber.finished) _ = ev.schedule(thread, .{ .head = awaiter, .tail = awaiter }); |
| 1297 | }, | 1290 | }, |
| 1298 | .group_await => |group| { | 1291 | .group_await => |group| { |
| 1299 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); | 1292 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); |
| ... | @@ -1367,7 +1360,7 @@ fn crashHandler(userdata: ?*anyopaque) void { | ... | @@ -1367,7 +1360,7 @@ fn crashHandler(userdata: ?*anyopaque) void { |
| 1367 | } | 1360 | } |
| 1368 | | 1361 | |
| 1369 | const AsyncClosure = struct { | 1362 | const AsyncClosure = struct { |
| 1370 | ev: *Evented, | 1363 | evented: *Evented, |
| 1371 | fiber: *Fiber, | 1364 | fiber: *Fiber, |
| 1372 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, | 1365 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, |
| 1373 | result_align: Alignment, | 1366 | result_align: Alignment, |
| ... | @@ -1404,16 +1397,11 @@ const AsyncClosure = struct { | ... | @@ -1404,16 +1397,11 @@ const AsyncClosure = struct { |
| 1404 | closure: *AsyncClosure, | 1397 | closure: *AsyncClosure, |
| 1405 | message: *const SwitchMessage, | 1398 | message: *const SwitchMessage, |
| 1406 | ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { | 1399 | ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { |
| 1407 | message.handle(closure.ev); | 1400 | const ev = closure.evented; |
| 1408 | const fiber = closure.fiber; | 1401 | const fiber = closure.fiber; |
| | 1402 | message.handle(ev); |
| 1409 | closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align)); | 1403 | closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align)); |
| 1410 | closure.ev.yield( | 1404 | ev.yield(@atomicRmw(?*Fiber, &fiber.link.awaiter, .Xchg, Fiber.finished, .acq_rel), .nothing); |
| 1411 | if (@atomicRmw(?*Fiber, &fiber.link.awaiter, .Xchg, Fiber.finished, .acq_rel)) |awaiter| | | |
| 1412 | if (@atomicRmw(i32, &awaiter.await_count, .Add, 1, .monotonic) == -1) awaiter else null | | |
| 1413 | else | | |
| 1414 | null, | | |
| 1415 | .nothing, | | |
| 1416 | ); | | |
| 1417 | unreachable; // switched to dead fiber | 1405 | unreachable; // switched to dead fiber |
| 1418 | } | 1406 | } |
| 1419 | }; | 1407 | }; |
| ... | @@ -1467,7 +1455,6 @@ fn concurrent( | ... | @@ -1467,7 +1455,6 @@ fn concurrent( |
| 1467 | }, | 1455 | }, |
| 1468 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), | 1456 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), |
| 1469 | }, | 1457 | }, |
| 1470 | .await_count = 0, | | |
| 1471 | .link = .{ .awaiter = null }, | 1458 | .link = .{ .awaiter = null }, |
| 1472 | .status = .{ .queue_next = null }, | 1459 | .status = .{ .queue_next = null }, |
| 1473 | .cancel_status = .unrequested, | 1460 | .cancel_status = .unrequested, |
| ... | @@ -1485,7 +1472,7 @@ fn concurrent( | ... | @@ -1485,7 +1472,7 @@ fn concurrent( |
| 1485 | }, | 1472 | }, |
| 1486 | }; | 1473 | }; |
| 1487 | closure.* = .{ | 1474 | closure.* = .{ |
| 1488 | .ev = ev, | 1475 | .evented = ev, |
| 1489 | .fiber = fiber, | 1476 | .fiber = fiber, |
| 1490 | .start = start, | 1477 | .start = start, |
| 1491 | .result_align = result_alignment, | 1478 | .result_align = result_alignment, |
| ... | @@ -1504,18 +1491,11 @@ fn await( | ... | @@ -1504,18 +1491,11 @@ fn await( |
| 1504 | result_alignment: Alignment, | 1491 | result_alignment: Alignment, |
| 1505 | ) void { | 1492 | ) void { |
| 1506 | const ev: *Evented = @ptrCast(@alignCast(userdata)); | 1493 | const ev: *Evented = @ptrCast(@alignCast(userdata)); |
| 1507 | const fiber = Thread.current().currentFiber(); | 1494 | const awaiting: *Fiber = @ptrCast(@alignCast(future)); |
| 1508 | const future_fiber: *Fiber = @ptrCast(@alignCast(future)); | 1495 | if (@atomicLoad(?*Fiber, &awaiting.link.awaiter, .acquire) != Fiber.finished) |
| 1509 | if (@atomicRmw(?*Fiber, &future_fiber.link.awaiter, .Xchg, fiber, .acq_rel)) |awaiter| { | 1496 | ev.yield(null, .{ .await = awaiting }); |
| 1510 | assert(awaiter == Fiber.finished); | 1497 | @memcpy(result, awaiting.resultBytes(result_alignment)); |
| 1511 | } else while (true) { | 1498 | awaiting.destroy(); |
| 1512 | ev.yield(null, .{ .await = 1 }); | | |
| 1513 | const awaiter = @atomicLoad(?*Fiber, &future_fiber.link.awaiter, .acquire); | | |
| 1514 | if (awaiter == Fiber.finished) break; | | |
| 1515 | assert(awaiter == fiber); // spurious wakeup | | |
| 1516 | } | | |
| 1517 | @memcpy(result, future_fiber.resultBytes(result_alignment)); | | |
| 1518 | future_fiber.destroy(); | | |
| 1519 | } | 1499 | } |
| 1520 | | 1500 | |
| 1521 | fn cancel( | 1501 | fn cancel( |
| ... | @@ -1732,7 +1712,7 @@ const Group = struct { | ... | @@ -1732,7 +1712,7 @@ const Group = struct { |
| 1732 | } | 1712 | } |
| 1733 | | 1713 | |
| 1734 | const AsyncClosure = struct { | 1714 | const AsyncClosure = struct { |
| 1735 | ev: *Evented, | 1715 | evented: *Evented, |
| 1736 | group: Group, | 1716 | group: Group, |
| 1737 | fiber: *Fiber, | 1717 | fiber: *Fiber, |
| 1738 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, | 1718 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, |
| ... | @@ -1771,19 +1751,16 @@ const Group = struct { | ... | @@ -1771,19 +1751,16 @@ const Group = struct { |
| 1771 | closure: *Group.AsyncClosure, | 1751 | closure: *Group.AsyncClosure, |
| 1772 | message: *const SwitchMessage, | 1752 | message: *const SwitchMessage, |
| 1773 | ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { | 1753 | ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { |
| 1774 | message.handle(closure.ev); | 1754 | const ev = closure.evented; |
| 1775 | assert(closure.fiber.status.queue_next == null); | | |
| 1776 | const result = closure.start(closure.contextPointer()); | | |
| 1777 | const ev = closure.ev; | | |
| 1778 | const group = closure.group; | | |
| 1779 | const fiber = closure.fiber; | 1755 | const fiber = closure.fiber; |
| 1780 | const cancel_acknowledged = fiber.cancel_protection.acknowledged; | 1756 | message.handle(ev); |
| 1781 | if (result) { | 1757 | assert(fiber.status.queue_next == null); |
| 1782 | assert(!cancel_acknowledged); // group task acknowledged cancelation but did not return `error.Canceled` | 1758 | if (closure.start(closure.contextPointer())) { |
| | 1759 | assert(!fiber.cancel_protection.acknowledged); // group task acknowledged cancelation but did not return `error.Canceled` |
| 1783 | } else |err| switch (err) { | 1760 | } else |err| switch (err) { |
| 1784 | error.Canceled => assert(cancel_acknowledged), // group task returned `error.Canceled` but was never canceled | 1761 | error.Canceled => assert(fiber.cancel_protection.acknowledged), // group task returned `error.Canceled` but was never canceled |
| 1785 | } | 1762 | } |
| 1786 | ev.yield(group.removeFiber(ev, fiber), .destroy); | 1763 | ev.yield(closure.group.removeFiber(ev, fiber), .destroy); |
| 1787 | unreachable; // switched to dead fiber | 1764 | unreachable; // switched to dead fiber |
| 1788 | } | 1765 | } |
| 1789 | }; | 1766 | }; |
| ... | @@ -1851,7 +1828,6 @@ fn groupConcurrent( | ... | @@ -1851,7 +1828,6 @@ fn groupConcurrent( |
| 1851 | }, | 1828 | }, |
| 1852 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), | 1829 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), |
| 1853 | }, | 1830 | }, |
| 1854 | .await_count = 0, | | |
| 1855 | .link = .{ .group = .{ .prev = null, .next = null } }, | 1831 | .link = .{ .group = .{ .prev = null, .next = null } }, |
| 1856 | .status = .{ .queue_next = null }, | 1832 | .status = .{ .queue_next = null }, |
| 1857 | .cancel_status = .unrequested, | 1833 | .cancel_status = .unrequested, |
| ... | @@ -1869,7 +1845,7 @@ fn groupConcurrent( | ... | @@ -1869,7 +1845,7 @@ fn groupConcurrent( |
| 1869 | }, | 1845 | }, |
| 1870 | }; | 1846 | }; |
| 1871 | closure.* = .{ | 1847 | closure.* = .{ |
| 1872 | .ev = ev, | 1848 | .evented = ev, |
| 1873 | .group = group, | 1849 | .group = group, |
| 1874 | .fiber = fiber, | 1850 | .fiber = fiber, |
| 1875 | .start = start, | 1851 | .start = start, |
| ... | @@ -1928,57 +1904,6 @@ fn checkCancel(userdata: ?*anyopaque) Io.Cancelable!void { | ... | @@ -1928,57 +1904,6 @@ fn checkCancel(userdata: ?*anyopaque) Io.Cancelable!void { |
| 1928 | } | 1904 | } |
| 1929 | } | 1905 | } |
| 1930 | | 1906 | |
| 1931 | fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Io.Cancelable!usize { | | |
| 1932 | const ev: *Evented = @ptrCast(@alignCast(userdata)); | | |
| 1933 | var cancel_region: CancelRegion = .init(); | | |
| 1934 | defer cancel_region.deinit(); | | |
| 1935 | var await_count: u31, var result = for (futures, 0..) |future, future_index| { | | |
| 1936 | const future_fiber: *Fiber = @ptrCast(@alignCast(future)); | | |
| 1937 | if (@atomicRmw( | | |
| 1938 | ?*Fiber, | | |
| 1939 | &future_fiber.link.awaiter, | | |
| 1940 | .Xchg, | | |
| 1941 | cancel_region.fiber, | | |
| 1942 | .acq_rel, | | |
| 1943 | )) |awaiter| { | | |
| 1944 | assert(awaiter == Fiber.finished); | | |
| 1945 | break .{ @intCast(future_index), future_index }; | | |
| 1946 | } | | |
| 1947 | } else result: { | | |
| 1948 | const await_count: u31 = @intCast(futures.len); | | |
| 1949 | cancel_region.await(.select) catch |err| switch (err) { | | |
| 1950 | error.Canceled => |e| break :result .{ await_count + 1, e }, | | |
| 1951 | }; | | |
| 1952 | ev.yield(null, .{ .await = 1 }); | | |
| 1953 | cancel_region.await(.nothing) catch |err| switch (err) { | | |
| 1954 | error.Canceled => |e| break :result .{ await_count, e }, | | |
| 1955 | }; | | |
| 1956 | break :result .{ await_count - 1, futures.len }; | | |
| 1957 | }; | | |
| 1958 | for (futures[0 .. result catch futures.len], 0..) |future, future_index| { | | |
| 1959 | const future_fiber: *Fiber = @ptrCast(@alignCast(future)); | | |
| 1960 | const awaiter = @atomicRmw(?*Fiber, &future_fiber.link.awaiter, .Xchg, null, .monotonic); | | |
| 1961 | if (awaiter == Fiber.finished) { | | |
| 1962 | @atomicStore(?*Fiber, &future_fiber.link.awaiter, Fiber.finished, .monotonic); | | |
| 1963 | result = if (result) |finished_index| @min(future_index, finished_index) else |e| e; | | |
| 1964 | } else { | | |
| 1965 | assert(awaiter == cancel_region.fiber); | | |
| 1966 | await_count -= 1; | | |
| 1967 | } | | |
| 1968 | } | | |
| 1969 | // Equivalent to `ev.yield(null, .{ .await = await_count });`, | | |
| 1970 | // but avoiding a context switch in the common case. | | |
| 1971 | switch (std.math.order( | | |
| 1972 | @atomicRmw(i32, &cancel_region.fiber.await_count, .Sub, await_count, .monotonic), | | |
| 1973 | await_count, | | |
| 1974 | )) { | | |
| 1975 | .lt => ev.yield(null, .{ .await = 0 }), | | |
| 1976 | .eq => {}, | | |
| 1977 | .gt => unreachable, | | |
| 1978 | } | | |
| 1979 | return result; | | |
| 1980 | } | | |
| 1981 | | | |
| 1982 | fn futexWait( | 1907 | fn futexWait( |
| 1983 | userdata: ?*anyopaque, | 1908 | userdata: ?*anyopaque, |
| 1984 | ptr: *const u32, | 1909 | ptr: *const u32, |
| ... | @@ -2230,7 +2155,7 @@ fn deviceIoControl( | ... | @@ -2230,7 +2155,7 @@ fn deviceIoControl( |
| 2230 | const rc = linux.ioctl(o.file.handle, @bitCast(o.code), @intFromPtr(o.arg)); | 2155 | const rc = linux.ioctl(o.file.handle, @bitCast(o.code), @intFromPtr(o.arg)); |
| 2231 | switch (linux.errno(rc)) { | 2156 | switch (linux.errno(rc)) { |
| 2232 | .SUCCESS => return @bitCast(@as(u32, @truncate(rc))), | 2157 | .SUCCESS => return @bitCast(@as(u32, @truncate(rc))), |
| 2233 | .INTR => continue, | 2158 | .INTR => {}, |
| 2234 | else => |err| return -@as(i32, @intFromEnum(err)), | 2159 | else => |err| return -@as(i32, @intFromEnum(err)), |
| 2235 | } | 2160 | } |
| 2236 | } | 2161 | } |
| ... | @@ -2628,7 +2553,7 @@ fn dirCreateDir( | ... | @@ -2628,7 +2553,7 @@ fn dirCreateDir( |
| 2628 | ev.yield(null, .nothing); | 2553 | ev.yield(null, .nothing); |
| 2629 | switch (cancel_region.errno()) { | 2554 | switch (cancel_region.errno()) { |
| 2630 | .SUCCESS => return, | 2555 | .SUCCESS => return, |
| 2631 | .INTR, .CANCELED => continue, | 2556 | .INTR, .CANCELED => {}, |
| 2632 | .ACCES => return error.AccessDenied, | 2557 | .ACCES => return error.AccessDenied, |
| 2633 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 2558 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 2634 | .PERM => return error.PermissionDenied, | 2559 | .PERM => return error.PermissionDenied, |
| ... | @@ -2711,7 +2636,7 @@ fn filePathKind(ev: *Evented, dir: Dir, sub_path: []const u8) !File.Kind { | ... | @@ -2711,7 +2636,7 @@ fn filePathKind(ev: *Evented, dir: Dir, sub_path: []const u8) !File.Kind { |
| 2711 | if (!statx_buf.mask.TYPE) return error.Unexpected; | 2636 | if (!statx_buf.mask.TYPE) return error.Unexpected; |
| 2712 | return statxKind(statx_buf.mode); | 2637 | return statxKind(statx_buf.mode); |
| 2713 | }, | 2638 | }, |
| 2714 | .INTR, .CANCELED => continue, | 2639 | .INTR, .CANCELED => {}, |
| 2715 | .ACCES => |err| return errnoBug(err), | 2640 | .ACCES => |err| return errnoBug(err), |
| 2716 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 2641 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 2717 | .FAULT => |err| return errnoBug(err), | 2642 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -2824,7 +2749,7 @@ fn dirAccess( | ... | @@ -2824,7 +2749,7 @@ fn dirAccess( |
| 2824 | try sync.cancel_region.await(.nothing); | 2749 | try sync.cancel_region.await(.nothing); |
| 2825 | switch (linux.errno(linux.faccessat(dir.handle, sub_path_posix, mode, flags))) { | 2750 | switch (linux.errno(linux.faccessat(dir.handle, sub_path_posix, mode, flags))) { |
| 2826 | .SUCCESS => return, | 2751 | .SUCCESS => return, |
| 2827 | .INTR => continue, | 2752 | .INTR => {}, |
| 2828 | .ACCES => return error.AccessDenied, | 2753 | .ACCES => return error.AccessDenied, |
| 2829 | .PERM => return error.PermissionDenied, | 2754 | .PERM => return error.PermissionDenied, |
| 2830 | .ROFS => return error.ReadOnlyFileSystem, | 2755 | .ROFS => return error.ReadOnlyFileSystem, |
| ... | @@ -2863,7 +2788,7 @@ fn dirCreateFile( | ... | @@ -2863,7 +2788,7 @@ fn dirCreateFile( |
| 2863 | .EXCL = flags.exclusive, | 2788 | .EXCL = flags.exclusive, |
| 2864 | .CLOEXEC = true, | 2789 | .CLOEXEC = true, |
| 2865 | }, flags.permissions.toMode()); | 2790 | }, flags.permissions.toMode()); |
| 2866 | errdefer ev.close(fd); | 2791 | errdefer ev.closeAsync(fd); |
| 2867 | | 2792 | |
| 2868 | switch (flags.lock) { | 2793 | switch (flags.lock) { |
| 2869 | .none => {}, | 2794 | .none => {}, |
| ... | @@ -3051,7 +2976,7 @@ fn dirOpenFile( | ... | @@ -3051,7 +2976,7 @@ fn dirOpenFile( |
| 3051 | .CLOEXEC = true, | 2976 | .CLOEXEC = true, |
| 3052 | .PATH = flags.path_only, | 2977 | .PATH = flags.path_only, |
| 3053 | }, 0); | 2978 | }, 0); |
| 3054 | errdefer ev.close(fd); | 2979 | errdefer ev.closeAsync(fd); |
| 3055 | | 2980 | |
| 3056 | if (!flags.allow_directory) { | 2981 | if (!flags.allow_directory) { |
| 3057 | const is_dir = is_dir: { | 2982 | const is_dir = is_dir: { |
| ... | @@ -3105,7 +3030,7 @@ fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Read | ... | @@ -3105,7 +3030,7 @@ fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Read |
| 3105 | const rc = linux.getdents64(dr.dir.handle, dr.buffer.ptr, dr.buffer.len); | 3030 | const rc = linux.getdents64(dr.dir.handle, dr.buffer.ptr, dr.buffer.len); |
| 3106 | switch (linux.errno(rc)) { | 3031 | switch (linux.errno(rc)) { |
| 3107 | .SUCCESS => break rc, | 3032 | .SUCCESS => break rc, |
| 3108 | .INTR => continue, | 3033 | .INTR => {}, |
| 3109 | .BADF => |err| return errnoBug(err), // Dir is invalid or was opened without iteration ability. | 3034 | .BADF => |err| return errnoBug(err), // Dir is invalid or was opened without iteration ability. |
| 3110 | .FAULT => |err| return errnoBug(err), | 3035 | .FAULT => |err| return errnoBug(err), |
| 3111 | .NOTDIR => |err| return errnoBug(err), | 3036 | .NOTDIR => |err| return errnoBug(err), |
| ... | @@ -3198,7 +3123,7 @@ fn dirRealPathFile( | ... | @@ -3198,7 +3123,7 @@ fn dirRealPathFile( |
| 3198 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. | 3123 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. |
| 3199 | else => |e| return e, | 3124 | else => |e| return e, |
| 3200 | }; | 3125 | }; |
| 3201 | defer ev.close(fd); | 3126 | defer ev.closeAsync(fd); |
| 3202 | return ev.realPath(try maybe_sync.enterSync(ev), fd, out_buffer); | 3127 | return ev.realPath(try maybe_sync.enterSync(ev), fd, out_buffer); |
| 3203 | } | 3128 | } |
| 3204 | | 3129 | |
| ... | @@ -3231,7 +3156,7 @@ fn dirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Dele | ... | @@ -3231,7 +3156,7 @@ fn dirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Dele |
| 3231 | ev.yield(null, .nothing); | 3156 | ev.yield(null, .nothing); |
| 3232 | switch (cancel_region.errno()) { | 3157 | switch (cancel_region.errno()) { |
| 3233 | .SUCCESS => return, | 3158 | .SUCCESS => return, |
| 3234 | .INTR, .CANCELED => continue, | 3159 | .INTR, .CANCELED => {}, |
| 3235 | .PERM => return error.PermissionDenied, | 3160 | .PERM => return error.PermissionDenied, |
| 3236 | .ACCES => return error.AccessDenied, | 3161 | .ACCES => return error.AccessDenied, |
| 3237 | .BUSY => return error.FileBusy, | 3162 | .BUSY => return error.FileBusy, |
| ... | @@ -3283,7 +3208,7 @@ fn dirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Delet | ... | @@ -3283,7 +3208,7 @@ fn dirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Delet |
| 3283 | ev.yield(null, .nothing); | 3208 | ev.yield(null, .nothing); |
| 3284 | switch (cancel_region.errno()) { | 3209 | switch (cancel_region.errno()) { |
| 3285 | .SUCCESS => return, | 3210 | .SUCCESS => return, |
| 3286 | .INTR, .CANCELED => continue, | 3211 | .INTR, .CANCELED => {}, |
| 3287 | .ACCES => return error.AccessDenied, | 3212 | .ACCES => return error.AccessDenied, |
| 3288 | .PERM => return error.PermissionDenied, | 3213 | .PERM => return error.PermissionDenied, |
| 3289 | .BUSY => return error.FileBusy, | 3214 | .BUSY => return error.FileBusy, |
| ... | @@ -3399,7 +3324,7 @@ fn dirSymLink( | ... | @@ -3399,7 +3324,7 @@ fn dirSymLink( |
| 3399 | ev.yield(null, .nothing); | 3324 | ev.yield(null, .nothing); |
| 3400 | switch (cancel_region.errno()) { | 3325 | switch (cancel_region.errno()) { |
| 3401 | .SUCCESS => return, | 3326 | .SUCCESS => return, |
| 3402 | .INTR, .CANCELED => continue, | 3327 | .INTR, .CANCELED => {}, |
| 3403 | .FAULT => |err| return errnoBug(err), | 3328 | .FAULT => |err| return errnoBug(err), |
| 3404 | .INVAL => |err| return errnoBug(err), | 3329 | .INVAL => |err| return errnoBug(err), |
| 3405 | .ACCES => return error.AccessDenied, | 3330 | .ACCES => return error.AccessDenied, |
| ... | @@ -3438,7 +3363,7 @@ fn dirReadLink( | ... | @@ -3438,7 +3363,7 @@ fn dirReadLink( |
| 3438 | const rc = linux.readlinkat(dir.handle, sub_path_posix, buffer.ptr, buffer.len); | 3363 | const rc = linux.readlinkat(dir.handle, sub_path_posix, buffer.ptr, buffer.len); |
| 3439 | switch (linux.errno(rc)) { | 3364 | switch (linux.errno(rc)) { |
| 3440 | .SUCCESS => return @bitCast(rc), | 3365 | .SUCCESS => return @bitCast(rc), |
| 3441 | .INTR => continue, | 3366 | .INTR => {}, |
| 3442 | .ACCES => return error.AccessDenied, | 3367 | .ACCES => return error.AccessDenied, |
| 3443 | .FAULT => |err| return errnoBug(err), | 3368 | .FAULT => |err| return errnoBug(err), |
| 3444 | .INVAL => return error.NotLink, | 3369 | .INVAL => return error.NotLink, |
| ... | @@ -3628,7 +3553,7 @@ fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { | ... | @@ -3628,7 +3553,7 @@ fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { |
| 3628 | if (!statx_buf.mask.SIZE) return error.Unexpected; | 3553 | if (!statx_buf.mask.SIZE) return error.Unexpected; |
| 3629 | return statx_buf.size; | 3554 | return statx_buf.size; |
| 3630 | }, | 3555 | }, |
| 3631 | .INTR, .CANCELED => continue, | 3556 | .INTR, .CANCELED => {}, |
| 3632 | .ACCES => |err| return errnoBug(err), | 3557 | .ACCES => |err| return errnoBug(err), |
| 3633 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 3558 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 3634 | .FAULT => |err| return errnoBug(err), | 3559 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -3811,7 +3736,7 @@ fn fileSync(userdata: ?*anyopaque, file: File) File.SyncError!void { | ... | @@ -3811,7 +3736,7 @@ fn fileSync(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 3811 | ev.yield(null, .nothing); | 3736 | ev.yield(null, .nothing); |
| 3812 | switch (cancel_region.errno()) { | 3737 | switch (cancel_region.errno()) { |
| 3813 | .SUCCESS => return, | 3738 | .SUCCESS => return, |
| 3814 | .INTR, .CANCELED => continue, | 3739 | .INTR, .CANCELED => {}, |
| 3815 | .BADF => |err| return errnoBug(err), | 3740 | .BADF => |err| return errnoBug(err), |
| 3816 | .INVAL => |err| return errnoBug(err), | 3741 | .INVAL => |err| return errnoBug(err), |
| 3817 | .ROFS => |err| return errnoBug(err), | 3742 | .ROFS => |err| return errnoBug(err), |
| ... | @@ -3833,7 +3758,7 @@ fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { | ... | @@ -3833,7 +3758,7 @@ fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 3833 | const rc = linux.ioctl(file.handle, linux.T.IOCGWINSZ, @intFromPtr(&wsz)); | 3758 | const rc = linux.ioctl(file.handle, linux.T.IOCGWINSZ, @intFromPtr(&wsz)); |
| 3834 | switch (linux.errno(rc)) { | 3759 | switch (linux.errno(rc)) { |
| 3835 | .SUCCESS => return true, | 3760 | .SUCCESS => return true, |
| 3836 | .INTR => continue, | 3761 | .INTR => {}, |
| 3837 | else => return false, | 3762 | else => return false, |
| 3838 | } | 3763 | } |
| 3839 | } | 3764 | } |
| ... | @@ -3869,7 +3794,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE | ... | @@ -3869,7 +3794,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE |
| 3869 | ev.yield(null, .nothing); | 3794 | ev.yield(null, .nothing); |
| 3870 | switch (cancel_region.errno()) { | 3795 | switch (cancel_region.errno()) { |
| 3871 | .SUCCESS => return, | 3796 | .SUCCESS => return, |
| 3872 | .INTR, .CANCELED => continue, | 3797 | .INTR, .CANCELED => {}, |
| 3873 | .FBIG => return error.FileTooBig, | 3798 | .FBIG => return error.FileTooBig, |
| 3874 | .IO => return error.InputOutput, | 3799 | .IO => return error.InputOutput, |
| 3875 | .PERM => return error.PermissionDenied, | 3800 | .PERM => return error.PermissionDenied, |
| ... | @@ -4051,7 +3976,7 @@ fn fileMemoryMapCreate( | ... | @@ -4051,7 +3976,7 @@ fn fileMemoryMapCreate( |
| 4051 | const rc = linux.mmap(null, options.len, prot, flags, file.handle, casted_offset); | 3976 | const rc = linux.mmap(null, options.len, prot, flags, file.handle, casted_offset); |
| 4052 | switch (linux.errno(rc)) { | 3977 | switch (linux.errno(rc)) { |
| 4053 | .SUCCESS => break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..options.len], | 3978 | .SUCCESS => break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..options.len], |
| 4054 | .INTR => continue, | 3979 | .INTR => {}, |
| 4055 | .ACCES => return error.AccessDenied, | 3980 | .ACCES => return error.AccessDenied, |
| 4056 | .AGAIN => return error.LockedMemoryLimitExceeded, | 3981 | .AGAIN => return error.LockedMemoryLimitExceeded, |
| 4057 | .MFILE => return error.ProcessFdQuotaExceeded, | 3982 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -4111,7 +4036,7 @@ fn fileMemoryMapSetLength( | ... | @@ -4111,7 +4036,7 @@ fn fileMemoryMapSetLength( |
| 4111 | const rc = linux.mremap(old_memory.ptr, old_memory.len, new_len, flags, addr_hint); | 4036 | const rc = linux.mremap(old_memory.ptr, old_memory.len, new_len, flags, addr_hint); |
| 4112 | switch (linux.errno(rc)) { | 4037 | switch (linux.errno(rc)) { |
| 4113 | .SUCCESS => break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..new_len], | 4038 | .SUCCESS => break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..new_len], |
| 4114 | .INTR => continue, | 4039 | .INTR => {}, |
| 4115 | .AGAIN => return error.LockedMemoryLimitExceeded, | 4040 | .AGAIN => return error.LockedMemoryLimitExceeded, |
| 4116 | .NOMEM => return error.OutOfMemory, | 4041 | .NOMEM => return error.OutOfMemory, |
| 4117 | .INVAL => |err| return errnoBug(err), | 4042 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -4220,7 +4145,7 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr | ... | @@ -4220,7 +4145,7 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr |
| 4220 | try sync.cancel_region.await(.nothing); | 4145 | try sync.cancel_region.await(.nothing); |
| 4221 | switch (linux.errno(linux.getcwd(buffer.ptr, buffer.len))) { | 4146 | switch (linux.errno(linux.getcwd(buffer.ptr, buffer.len))) { |
| 4222 | .SUCCESS => return std.mem.findScalar(u8, buffer, 0).?, | 4147 | .SUCCESS => return std.mem.findScalar(u8, buffer, 0).?, |
| 4223 | .INTR => continue, | 4148 | .INTR => {}, |
| 4224 | .NOENT => return error.CurrentDirUnlinked, | 4149 | .NOENT => return error.CurrentDirUnlinked, |
| 4225 | .RANGE => return error.NameTooLong, | 4150 | .RANGE => return error.NameTooLong, |
| 4226 | .FAULT => |err| return errnoBug(err), | 4151 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -4235,7 +4160,7 @@ fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirEr | ... | @@ -4235,7 +4160,7 @@ fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirEr |
| 4235 | if (dir.handle == linux.AT.FDCWD) return; | 4160 | if (dir.handle == linux.AT.FDCWD) return; |
| 4236 | var sync: CancelRegion.Sync = try .init(ev); | 4161 | var sync: CancelRegion.Sync = try .init(ev); |
| 4237 | defer sync.deinit(ev); | 4162 | defer sync.deinit(ev); |
| 4238 | return ev.fchdir(&sync, dir.handle); | 4163 | return fchdir(&sync, dir.handle); |
| 4239 | } | 4164 | } |
| 4240 | | 4165 | |
| 4241 | fn processSetCurrentPath(userdata: ?*anyopaque, dir_path: []const u8) ChdirError!void { | 4166 | fn processSetCurrentPath(userdata: ?*anyopaque, dir_path: []const u8) ChdirError!void { |
| ... | @@ -4272,7 +4197,7 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces | ... | @@ -4272,7 +4197,7 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces |
| 4272 | | 4197 | |
| 4273 | var sync: CancelRegion.Sync = try .init(ev); | 4198 | var sync: CancelRegion.Sync = try .init(ev); |
| 4274 | defer sync.deinit(ev); | 4199 | defer sync.deinit(ev); |
| 4275 | return ev.execv(&sync, options.expand_arg0, argv_buf.ptr[0].?, argv_buf.ptr, env_block, PATH); | 4200 | return execv(&sync, options.expand_arg0, argv_buf.ptr[0].?, argv_buf.ptr, env_block, PATH); |
| 4276 | } | 4201 | } |
| 4277 | | 4202 | |
| 4278 | fn processReplacePath( | 4203 | fn processReplacePath( |
| ... | @@ -4292,7 +4217,7 @@ fn processSpawn(userdata: ?*anyopaque, options: process.SpawnOptions) process.Sp | ... | @@ -4292,7 +4217,7 @@ fn processSpawn(userdata: ?*anyopaque, options: process.SpawnOptions) process.Sp |
| 4292 | const spawned = try ev.spawn(options); | 4217 | const spawned = try ev.spawn(options); |
| 4293 | var cancel_region: CancelRegion = .initBlocked(); | 4218 | var cancel_region: CancelRegion = .initBlocked(); |
| 4294 | defer cancel_region.deinit(); | 4219 | defer cancel_region.deinit(); |
| 4295 | defer ev.close(spawned.err_fd); | 4220 | defer ev.closeAsync(spawned.err_fd); |
| 4296 | | 4221 | |
| 4297 | // Wait for the child to report any errors in or before `execvpe`. | 4222 | // Wait for the child to report any errors in or before `execvpe`. |
| 4298 | var child_err: ForkBailError = undefined; | 4223 | var child_err: ForkBailError = undefined; |
| ... | @@ -4434,8 +4359,9 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4434,8 +4359,9 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4434 | | 4359 | |
| 4435 | if (pid_result == 0) { | 4360 | if (pid_result == 0) { |
| 4436 | defer comptime unreachable; // We are the child. | 4361 | defer comptime unreachable; // We are the child. |
| | 4362 | // Note that the parent uring is no longer accessible, so we must no longer reference `ev`. |
| 4437 | var sync: CancelRegion.Sync = .{ .cancel_region = .initBlocked() }; | 4363 | var sync: CancelRegion.Sync = .{ .cancel_region = .initBlocked() }; |
| 4438 | const err = ev.setUpChild(&sync, .{ | 4364 | const err = setUpChild(&sync, .{ |
| 4439 | .stdin_pipe = stdin_pipe[0], | 4365 | .stdin_pipe = stdin_pipe[0], |
| 4440 | .stdout_pipe = stdout_pipe[1], | 4366 | .stdout_pipe = stdout_pipe[1], |
| 4441 | .stderr_pipe = stderr_pipe[1], | 4367 | .stderr_pipe = stderr_pipe[1], |
| ... | @@ -4446,7 +4372,7 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4446,7 +4372,7 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4446 | .PATH = PATH, | 4372 | .PATH = PATH, |
| 4447 | .spawn = options, | 4373 | .spawn = options, |
| 4448 | }); | 4374 | }); |
| 4449 | ev.writeAll(&sync.cancel_region, err_pipe[1], @ptrCast(&err)) catch {}; | 4375 | writeAllSync(&sync, err_pipe[1], @ptrCast(&err)) catch {}; |
| 4450 | const exit = if (builtin.single_threaded) linux.exit else linux.exit_group; | 4376 | const exit = if (builtin.single_threaded) linux.exit else linux.exit_group; |
| 4451 | exit(1); | 4377 | exit(1); |
| 4452 | } | 4378 | } |
| ... | @@ -4454,13 +4380,13 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4454,13 +4380,13 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4454 | const pid: pid_t = @intCast(pid_result); // We are the parent. | 4380 | const pid: pid_t = @intCast(pid_result); // We are the parent. |
| 4455 | errdefer comptime unreachable; // The child is forked; we must not error from now on | 4381 | errdefer comptime unreachable; // The child is forked; we must not error from now on |
| 4456 | | 4382 | |
| 4457 | ev.close(err_pipe[1]); // make sure only the child holds the write end open | 4383 | ev.closeAsync(err_pipe[1]); // make sure only the child holds the write end open |
| 4458 | | 4384 | |
| 4459 | if (options.stdin == .pipe) ev.close(stdin_pipe[0]); | 4385 | if (options.stdin == .pipe) ev.closeAsync(stdin_pipe[0]); |
| 4460 | if (options.stdout == .pipe) ev.close(stdout_pipe[1]); | 4386 | if (options.stdout == .pipe) ev.closeAsync(stdout_pipe[1]); |
| 4461 | if (options.stderr == .pipe) ev.close(stderr_pipe[1]); | 4387 | if (options.stderr == .pipe) ev.closeAsync(stderr_pipe[1]); |
| 4462 | | 4388 | |
| 4463 | if (prog_pipe[1] != -1) ev.close(prog_pipe[1]); | 4389 | if (prog_pipe[1] != -1) ev.closeAsync(prog_pipe[1]); |
| 4464 | | 4390 | |
| 4465 | options.progress_node.setIpcFile(ev, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } }); | 4391 | options.progress_node.setIpcFile(ev, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } }); |
| 4466 | | 4392 | |
| ... | @@ -4497,14 +4423,14 @@ pub fn pipe2(flags: linux.O) PipeError![2]fd_t { | ... | @@ -4497,14 +4423,14 @@ pub fn pipe2(flags: linux.O) PipeError![2]fd_t { |
| 4497 | } | 4423 | } |
| 4498 | } | 4424 | } |
| 4499 | fn destroyPipe(ev: *Evented, pipe: [2]fd_t) void { | 4425 | fn destroyPipe(ev: *Evented, pipe: [2]fd_t) void { |
| 4500 | if (pipe[0] != -1) ev.close(pipe[0]); | 4426 | if (pipe[0] != -1) ev.closeAsync(pipe[0]); |
| 4501 | if (pipe[0] != pipe[1]) ev.close(pipe[1]); | 4427 | if (pipe[0] != pipe[1]) ev.closeAsync(pipe[1]); |
| 4502 | } | 4428 | } |
| 4503 | | 4429 | |
| 4504 | /// Errors that can occur between fork() and execv() | 4430 | /// Errors that can occur between fork() and execv() |
| 4505 | const ForkBailError = process.SetCurrentDirError || ChdirError || | 4431 | const ForkBailError = process.SetCurrentDirError || ChdirError || |
| 4506 | process.SpawnError || process.ReplaceError; | 4432 | process.SpawnError || process.ReplaceError; |
| 4507 | fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | 4433 | fn setUpChild(sync: *CancelRegion.Sync, options: struct { |
| 4508 | stdin_pipe: fd_t, | 4434 | stdin_pipe: fd_t, |
| 4509 | stdout_pipe: fd_t, | 4435 | stdout_pipe: fd_t, |
| 4510 | stderr_pipe: fd_t, | 4436 | stderr_pipe: fd_t, |
| ... | @@ -4515,21 +4441,21 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4515,21 +4441,21 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4515 | PATH: []const u8, | 4441 | PATH: []const u8, |
| 4516 | spawn: process.SpawnOptions, | 4442 | spawn: process.SpawnOptions, |
| 4517 | }) ForkBailError { | 4443 | }) ForkBailError { |
| 4518 | try ev.setUpChildIo( | 4444 | try setUpChildIo( |
| 4519 | sync, | 4445 | sync, |
| 4520 | options.spawn.stdin, | 4446 | options.spawn.stdin, |
| 4521 | options.stdin_pipe, | 4447 | options.stdin_pipe, |
| 4522 | linux.STDIN_FILENO, | 4448 | linux.STDIN_FILENO, |
| 4523 | options.dev_null_fd, | 4449 | options.dev_null_fd, |
| 4524 | ); | 4450 | ); |
| 4525 | try ev.setUpChildIo( | 4451 | try setUpChildIo( |
| 4526 | sync, | 4452 | sync, |
| 4527 | options.spawn.stdout, | 4453 | options.spawn.stdout, |
| 4528 | options.stdout_pipe, | 4454 | options.stdout_pipe, |
| 4529 | linux.STDOUT_FILENO, | 4455 | linux.STDOUT_FILENO, |
| 4530 | options.dev_null_fd, | 4456 | options.dev_null_fd, |
| 4531 | ); | 4457 | ); |
| 4532 | try ev.setUpChildIo( | 4458 | try setUpChildIo( |
| 4533 | sync, | 4459 | sync, |
| 4534 | options.spawn.stderr, | 4460 | options.spawn.stderr, |
| 4535 | options.stderr_pipe, | 4461 | options.stderr_pipe, |
| ... | @@ -4539,17 +4465,17 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4539,17 +4465,17 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4539 | | 4465 | |
| 4540 | switch (options.spawn.cwd) { | 4466 | switch (options.spawn.cwd) { |
| 4541 | .inherit => {}, | 4467 | .inherit => {}, |
| 4542 | .dir => |cwd_dir| try ev.fchdir(sync, cwd_dir.handle), | 4468 | .dir => |cwd_dir| try fchdir(sync, cwd_dir.handle), |
| 4543 | .path => |cwd_path| { | 4469 | .path => |cwd_path| { |
| 4544 | var cwd_path_buffer: [PATH_MAX]u8 = undefined; | 4470 | var cwd_path_buffer: [PATH_MAX]u8 = undefined; |
| 4545 | const cwd_path_posix = try pathToPosix(cwd_path, &cwd_path_buffer); | 4471 | const cwd_path_posix = try pathToPosix(cwd_path, &cwd_path_buffer); |
| 4546 | try ev.chdir(sync, cwd_path_posix); | 4472 | try chdir(sync, cwd_path_posix); |
| 4547 | }, | 4473 | }, |
| 4548 | } | 4474 | } |
| 4549 | | 4475 | |
| 4550 | // Must happen after fchdir above, the cwd file descriptor might be | 4476 | // Must happen after fchdir above, the cwd file descriptor might be |
| 4551 | // equal to prog_fileno and be clobbered by this dup2 call. | 4477 | // equal to prog_fileno and be clobbered by this dup2 call. |
| 4552 | if (options.prog_pipe != -1) try ev.dup2(sync, options.prog_pipe, prog_fileno); | 4478 | if (options.prog_pipe != -1) try dup2(sync, options.prog_pipe, prog_fileno); |
| 4553 | | 4479 | |
| 4554 | if (options.spawn.gid) |gid| { | 4480 | if (options.spawn.gid) |gid| { |
| 4555 | switch (linux.errno(linux.setregid(gid, gid))) { | 4481 | switch (linux.errno(linux.setregid(gid, gid))) { |
| ... | @@ -4589,7 +4515,7 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4589,7 +4515,7 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4589 | } | 4515 | } |
| 4590 | } | 4516 | } |
| 4591 | | 4517 | |
| 4592 | return ev.execv( | 4518 | return execv( |
| 4593 | sync, | 4519 | sync, |
| 4594 | options.spawn.expand_arg0, | 4520 | options.spawn.expand_arg0, |
| 4595 | options.argv_buf.ptr[0].?, | 4521 | options.argv_buf.ptr[0].?, |
| ... | @@ -4600,7 +4526,6 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4600,7 +4526,6 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4600 | } | 4526 | } |
| 4601 | | 4527 | |
| 4602 | fn setUpChildIo( | 4528 | fn setUpChildIo( |
| 4603 | ev: *Evented, | | |
| 4604 | sync: *CancelRegion.Sync, | 4529 | sync: *CancelRegion.Sync, |
| 4605 | stdio: process.SpawnOptions.StdIo, | 4530 | stdio: process.SpawnOptions.StdIo, |
| 4606 | pipe_fd: fd_t, | 4531 | pipe_fd: fd_t, |
| ... | @@ -4608,13 +4533,13 @@ fn setUpChildIo( | ... | @@ -4608,13 +4533,13 @@ fn setUpChildIo( |
| 4608 | dev_null_fd: fd_t, | 4533 | dev_null_fd: fd_t, |
| 4609 | ) !void { | 4534 | ) !void { |
| 4610 | switch (stdio) { | 4535 | switch (stdio) { |
| 4611 | .pipe => try ev.dup2(sync, pipe_fd, std_fileno), | 4536 | .pipe => try dup2(sync, pipe_fd, std_fileno), |
| 4612 | .close => _ = linux.close(std_fileno), | 4537 | .close => _ = linux.close(std_fileno), |
| 4613 | .inherit => {}, | 4538 | .inherit => {}, |
| 4614 | .ignore => try ev.dup2(sync, dev_null_fd, std_fileno), | 4539 | .ignore => try dup2(sync, dev_null_fd, std_fileno), |
| 4615 | .file => |file| { | 4540 | .file => |file| { |
| 4616 | if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used"); | 4541 | if (file.flags.nonblocking) @panic("TODO implement setUpChildIo when nonblocking file is used"); |
| 4617 | try ev.dup2(sync, file.handle, std_fileno); | 4542 | try dup2(sync, file.handle, std_fileno); |
| 4618 | }, | 4543 | }, |
| 4619 | } | 4544 | } |
| 4620 | } | 4545 | } |
| ... | @@ -4623,13 +4548,12 @@ pub const DupError = error{ | ... | @@ -4623,13 +4548,12 @@ pub const DupError = error{ |
| 4623 | ProcessFdQuotaExceeded, | 4548 | ProcessFdQuotaExceeded, |
| 4624 | SystemResources, | 4549 | SystemResources, |
| 4625 | } || Io.UnexpectedError || Io.Cancelable; | 4550 | } || Io.UnexpectedError || Io.Cancelable; |
| 4626 | pub fn dup2(ev: *Evented, sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) DupError!void { | 4551 | pub fn dup2(sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) DupError!void { |
| 4627 | _ = ev; | | |
| 4628 | while (true) { | 4552 | while (true) { |
| 4629 | try sync.cancel_region.await(.nothing); | 4553 | try sync.cancel_region.await(.nothing); |
| 4630 | switch (linux.errno(linux.dup2(old_fd, new_fd))) { | 4554 | switch (linux.errno(linux.dup2(old_fd, new_fd))) { |
| 4631 | .SUCCESS => {}, | 4555 | .SUCCESS => {}, |
| 4632 | .BUSY, .INTR => continue, | 4556 | .BUSY, .INTR => {}, |
| 4633 | .INVAL => |err| return errnoBug(err), // invalid parameters | 4557 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 4634 | .BADF => |err| return errnoBug(err), // use after free | 4558 | .BADF => |err| return errnoBug(err), // use after free |
| 4635 | .MFILE => return error.ProcessFdQuotaExceeded, | 4559 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -4640,7 +4564,6 @@ pub fn dup2(ev: *Evented, sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) | ... | @@ -4640,7 +4564,6 @@ pub fn dup2(ev: *Evented, sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) |
| 4640 | } | 4564 | } |
| 4641 | | 4565 | |
| 4642 | fn execv( | 4566 | fn execv( |
| 4643 | ev: *Evented, | | |
| 4644 | sync: *CancelRegion.Sync, | 4567 | sync: *CancelRegion.Sync, |
| 4645 | arg0_expand: process.ArgExpansion, | 4568 | arg0_expand: process.ArgExpansion, |
| 4646 | file: [*:0]const u8, | 4569 | file: [*:0]const u8, |
| ... | @@ -4649,7 +4572,8 @@ fn execv( | ... | @@ -4649,7 +4572,8 @@ fn execv( |
| 4649 | PATH: []const u8, | 4572 | PATH: []const u8, |
| 4650 | ) process.ReplaceError { | 4573 | ) process.ReplaceError { |
| 4651 | const file_slice = std.mem.sliceTo(file, 0); | 4574 | const file_slice = std.mem.sliceTo(file, 0); |
| 4652 | if (std.mem.findScalar(u8, file_slice, '/') != null) return ev.execvPath(sync, file, child_argv, env_block); | 4575 | if (std.mem.findScalar(u8, file_slice, '/') != null) |
| | 4576 | return execvPath(sync, file, child_argv, env_block); |
| 4653 | | 4577 | |
| 4654 | // Use of PATH_MAX here is valid as the path_buf will be passed | 4578 | // Use of PATH_MAX here is valid as the path_buf will be passed |
| 4655 | // directly to the operating system in posixExecvPath. | 4579 | // directly to the operating system in posixExecvPath. |
| ... | @@ -4677,7 +4601,7 @@ fn execv( | ... | @@ -4677,7 +4601,7 @@ fn execv( |
| 4677 | .expand => child_argv[0] = full_path, | 4601 | .expand => child_argv[0] = full_path, |
| 4678 | .no_expand => {}, | 4602 | .no_expand => {}, |
| 4679 | } | 4603 | } |
| 4680 | err = ev.execvPath(sync, full_path, child_argv, env_block); | 4604 | err = execvPath(sync, full_path, child_argv, env_block); |
| 4681 | switch (err) { | 4605 | switch (err) { |
| 4682 | error.AccessDenied => seen_eacces = true, | 4606 | error.AccessDenied => seen_eacces = true, |
| 4683 | error.FileNotFound, error.NotDir => {}, | 4607 | error.FileNotFound, error.NotDir => {}, |
| ... | @@ -4689,13 +4613,11 @@ fn execv( | ... | @@ -4689,13 +4613,11 @@ fn execv( |
| 4689 | } | 4613 | } |
| 4690 | /// This function ignores PATH environment variable. | 4614 | /// This function ignores PATH environment variable. |
| 4691 | pub fn execvPath( | 4615 | pub fn execvPath( |
| 4692 | ev: *Evented, | | |
| 4693 | sync: *CancelRegion.Sync, | 4616 | sync: *CancelRegion.Sync, |
| 4694 | path: [*:0]const u8, | 4617 | path: [*:0]const u8, |
| 4695 | child_argv: [*:null]const ?[*:0]const u8, | 4618 | child_argv: [*:null]const ?[*:0]const u8, |
| 4696 | env_block: process.Environ.PosixBlock, | 4619 | env_block: process.Environ.PosixBlock, |
| 4697 | ) process.ReplaceError { | 4620 | ) process.ReplaceError { |
| 4698 | _ = ev; | | |
| 4699 | try sync.cancel_region.await(.nothing); | 4621 | try sync.cancel_region.await(.nothing); |
| 4700 | switch (linux.errno(linux.execve(path, child_argv, env_block.slice.ptr))) { | 4622 | switch (linux.errno(linux.execve(path, child_argv, env_block.slice.ptr))) { |
| 4701 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. | 4623 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. |
| ... | @@ -4766,7 +4688,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr | ... | @@ -4766,7 +4688,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr |
| 4766 | child.resource_usage_statistics.rusage = rusage; | 4688 | child.resource_usage_statistics.rusage = rusage; |
| 4767 | break; | 4689 | break; |
| 4768 | }, | 4690 | }, |
| 4769 | .INTR, .CANCELED => continue, | 4691 | .INTR, .CANCELED => {}, |
| 4770 | .CHILD => |err| return errnoBug(err), // Double-free. | 4692 | .CHILD => |err| return errnoBug(err), // Double-free. |
| 4771 | else => |err| return unexpectedErrno(err), | 4693 | else => |err| return unexpectedErrno(err), |
| 4772 | } | 4694 | } |
| ... | @@ -4781,7 +4703,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr | ... | @@ -4781,7 +4703,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr |
| 4781 | _, .CONTINUED => .{ .unknown = status }, | 4703 | _, .CONTINUED => .{ .unknown = status }, |
| 4782 | }; | 4704 | }; |
| 4783 | }, | 4705 | }, |
| 4784 | .INTR, .CANCELED => continue, | 4706 | .INTR, .CANCELED => {}, |
| 4785 | .CHILD => |err| return errnoBug(err), // Double-free. | 4707 | .CHILD => |err| return errnoBug(err), // Double-free. |
| 4786 | else => |err| return unexpectedErrno(err), | 4708 | else => |err| return unexpectedErrno(err), |
| 4787 | } | 4709 | } |
| ... | @@ -4798,7 +4720,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4798,7 +4720,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4798 | const pid = child.id.?; | 4720 | const pid = child.id.?; |
| 4799 | while (true) switch (linux.errno(linux.kill(pid, .TERM))) { | 4721 | while (true) switch (linux.errno(linux.kill(pid, .TERM))) { |
| 4800 | .SUCCESS => break, | 4722 | .SUCCESS => break, |
| 4801 | .INTR => continue, | 4723 | .INTR => {}, |
| 4802 | .PERM => return, | 4724 | .PERM => return, |
| 4803 | .INVAL => |err| return errnoBug(err) catch {}, | 4725 | .INVAL => |err| return errnoBug(err) catch {}, |
| 4804 | .SRCH => |err| return errnoBug(err) catch {}, | 4726 | .SRCH => |err| return errnoBug(err) catch {}, |
| ... | @@ -4830,7 +4752,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4830,7 +4752,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4830 | ev.yield(null, .nothing); | 4752 | ev.yield(null, .nothing); |
| 4831 | switch (maybe_sync.cancel_region.errno()) { | 4753 | switch (maybe_sync.cancel_region.errno()) { |
| 4832 | .SUCCESS => return, | 4754 | .SUCCESS => return, |
| 4833 | .INTR, .CANCELED => continue, | 4755 | .INTR, .CANCELED => {}, |
| 4834 | .CHILD => |err| return errnoBug(err) catch {}, // Double-free. | 4756 | .CHILD => |err| return errnoBug(err) catch {}, // Double-free. |
| 4835 | else => |err| return unexpectedErrno(err) catch {}, | 4757 | else => |err| return unexpectedErrno(err) catch {}, |
| 4836 | } | 4758 | } |
| ... | @@ -4839,15 +4761,15 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4839,15 +4761,15 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4839 | | 4761 | |
| 4840 | fn childCleanup(ev: *Evented, child: *process.Child) void { | 4762 | fn childCleanup(ev: *Evented, child: *process.Child) void { |
| 4841 | if (child.stdin) |*stdin| { | 4763 | if (child.stdin) |*stdin| { |
| 4842 | ev.close(stdin.handle); | 4764 | ev.closeAsync(stdin.handle); |
| 4843 | child.stdin = null; | 4765 | child.stdin = null; |
| 4844 | } | 4766 | } |
| 4845 | if (child.stdout) |*stdout| { | 4767 | if (child.stdout) |*stdout| { |
| 4846 | ev.close(stdout.handle); | 4768 | ev.closeAsync(stdout.handle); |
| 4847 | child.stdout = null; | 4769 | child.stdout = null; |
| 4848 | } | 4770 | } |
| 4849 | if (child.stderr) |*stderr| { | 4771 | if (child.stderr) |*stderr| { |
| 4850 | ev.close(stderr.handle); | 4772 | ev.closeAsync(stderr.handle); |
| 4851 | child.stderr = null; | 4773 | child.stderr = null; |
| 4852 | } | 4774 | } |
| 4853 | child.id = null; | 4775 | child.id = null; |
| ... | @@ -4953,14 +4875,10 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { | ... | @@ -4953,14 +4875,10 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { |
| 4953 | .resv = 0, | 4875 | .resv = 0, |
| 4954 | }; | 4876 | }; |
| 4955 | ev.yield(null, .nothing); | 4877 | ev.yield(null, .nothing); |
| 4956 | switch (cancel_region.errno()) { | 4878 | // Handles SUCCESS as well as clock not available and unexpected |
| 4957 | // Handles SUCCESS as well as clock not available and unexpected | 4879 | // errors. The user had a chance to check clock resolution before |
| 4958 | // errors. The user had a chance to check clock resolution before | 4880 | // getting here, which would have reported 0, making this a legal |
| 4959 | // getting here, which would have reported 0, making this a legal | 4881 | // amount of time to sleep. |
| 4960 | // amount of time to sleep. | | |
| 4961 | else => return, | | |
| 4962 | .INTR, .CANCELED => return error.Canceled, | | |
| 4963 | } | | |
| 4964 | } | 4882 | } |
| 4965 | | 4883 | |
| 4966 | fn random(userdata: ?*anyopaque, buffer: []u8) void { | 4884 | fn random(userdata: ?*anyopaque, buffer: []u8) void { |
| ... | @@ -5037,7 +4955,7 @@ fn netBindIp( | ... | @@ -5037,7 +4955,7 @@ fn netBindIp( |
| 5037 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; | 4955 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; |
| 5038 | defer maybe_sync.deinit(ev); | 4956 | defer maybe_sync.deinit(ev); |
| 5039 | const socket_fd = try ev.socket(&maybe_sync.cancel_region, family, options); | 4957 | const socket_fd = try ev.socket(&maybe_sync.cancel_region, family, options); |
| 5040 | errdefer ev.close(socket_fd); | 4958 | errdefer ev.closeAsync(socket_fd); |
| 5041 | var storage: PosixAddress = undefined; | 4959 | var storage: PosixAddress = undefined; |
| 5042 | var addr_len = addressToPosix(address, &storage); | 4960 | var addr_len = addressToPosix(address, &storage); |
| 5043 | try ev.bind(&maybe_sync.cancel_region, socket_fd, &storage.any, addr_len); | 4961 | try ev.bind(&maybe_sync.cancel_region, socket_fd, &storage.any, addr_len); |
| ... | @@ -5204,23 +5122,19 @@ fn netReceive( | ... | @@ -5204,23 +5122,19 @@ fn netReceive( |
| 5204 | .data = data, | 5122 | .data = data, |
| 5205 | .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control, | 5123 | .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control, |
| 5206 | .flags = .{ | 5124 | .flags = .{ |
| 5207 | .eor = (msg.flags & linux.MSG.EOR) != 0, | 5125 | .eor = msg.flags & linux.MSG.EOR != 0, |
| 5208 | .trunc = (msg.flags & linux.MSG.TRUNC) != 0, | 5126 | .trunc = msg.flags & linux.MSG.TRUNC != 0, |
| 5209 | .ctrunc = (msg.flags & linux.MSG.CTRUNC) != 0, | 5127 | .ctrunc = msg.flags & linux.MSG.CTRUNC != 0, |
| 5210 | .oob = (msg.flags & linux.MSG.OOB) != 0, | 5128 | .oob = msg.flags & linux.MSG.OOB != 0, |
| 5211 | .errqueue = if (@hasDecl(linux.MSG, "ERRQUEUE")) (msg.flags & linux.MSG.ERRQUEUE) != 0 else false, | 5129 | .errqueue = msg.flags & linux.MSG.ERRQUEUE != 0, |
| 5212 | }, | 5130 | }, |
| 5213 | }; | 5131 | }; |
| 5214 | message_i += 1; | 5132 | message_i += 1; |
| 5215 | continue; | 5133 | continue; |
| 5216 | }, | 5134 | }, |
| 5217 | .AGAIN => unreachable, | 5135 | .AGAIN => unreachable, |
| 5218 | .INTR, .CANCELED => { | 5136 | .INTR, .CANCELED => if (deadline) |d| if (now(ev, d.clock).nanoseconds >= d.raw.nanoseconds) |
| 5219 | if (deadline) |d| { | 5137 | return .{ error.Timeout, message_i }, |
| 5220 | if (now(ev, d.clock).nanoseconds >= d.raw.nanoseconds) return .{ error.Timeout, message_i }; | | |
| 5221 | } | | |
| 5222 | continue; | | |
| 5223 | }, | | |
| 5224 | | 5138 | |
| 5225 | .BADF => |err| return .{ errnoBug(err), message_i }, | 5139 | .BADF => |err| return .{ errnoBug(err), message_i }, |
| 5226 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, | 5140 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, |
| ... | @@ -5323,7 +5237,7 @@ fn netShutdown( | ... | @@ -5323,7 +5237,7 @@ fn netShutdown( |
| 5323 | ev.yield(null, .nothing); | 5237 | ev.yield(null, .nothing); |
| 5324 | switch (cancel_region.errno()) { | 5238 | switch (cancel_region.errno()) { |
| 5325 | .SUCCESS => return, | 5239 | .SUCCESS => return, |
| 5326 | .INTR, .CANCELED => continue, | 5240 | .INTR, .CANCELED => {}, |
| 5327 | .BADF, .NOTSOCK, .INVAL => |err| return errnoBug(err), | 5241 | .BADF, .NOTSOCK, .INVAL => |err| return errnoBug(err), |
| 5328 | .NOTCONN => return error.SocketUnconnected, | 5242 | .NOTCONN => return error.SocketUnconnected, |
| 5329 | .NOBUFS => return error.SystemResources, | 5243 | .NOBUFS => return error.SystemResources, |
| ... | @@ -5393,7 +5307,7 @@ fn bind( | ... | @@ -5393,7 +5307,7 @@ fn bind( |
| 5393 | ev.yield(null, .nothing); | 5307 | ev.yield(null, .nothing); |
| 5394 | switch (cancel_region.errno()) { | 5308 | switch (cancel_region.errno()) { |
| 5395 | .SUCCESS => return, | 5309 | .SUCCESS => return, |
| 5396 | .INTR, .CANCELED => continue, | 5310 | .INTR, .CANCELED => {}, |
| 5397 | .ADDRINUSE => return error.AddressInUse, | 5311 | .ADDRINUSE => return error.AddressInUse, |
| 5398 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5312 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5399 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5313 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| ... | @@ -5407,13 +5321,12 @@ fn bind( | ... | @@ -5407,13 +5321,12 @@ fn bind( |
| 5407 | } | 5321 | } |
| 5408 | } | 5322 | } |
| 5409 | | 5323 | |
| 5410 | fn chdir(ev: *Evented, sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError!void { | 5324 | fn chdir(sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError!void { |
| 5411 | _ = ev; | | |
| 5412 | while (true) { | 5325 | while (true) { |
| 5413 | try sync.cancel_region.await(.nothing); | 5326 | try sync.cancel_region.await(.nothing); |
| 5414 | switch (linux.errno(linux.chdir(path))) { | 5327 | switch (linux.errno(linux.chdir(path))) { |
| 5415 | .SUCCESS => return, | 5328 | .SUCCESS => return, |
| 5416 | .INTR => continue, | 5329 | .INTR => {}, |
| 5417 | .ACCES => return error.AccessDenied, | 5330 | .ACCES => return error.AccessDenied, |
| 5418 | .IO => return error.FileSystem, | 5331 | .IO => return error.FileSystem, |
| 5419 | .LOOP => return error.SymLinkLoop, | 5332 | .LOOP => return error.SymLinkLoop, |
| ... | @@ -5429,6 +5342,36 @@ fn chdir(ev: *Evented, sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError | ... | @@ -5429,6 +5342,36 @@ fn chdir(ev: *Evented, sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError |
| 5429 | } | 5342 | } |
| 5430 | | 5343 | |
| 5431 | fn close(ev: *Evented, fd: fd_t) void { | 5344 | fn close(ev: *Evented, fd: fd_t) void { |
| | 5345 | var cancel_region: CancelRegion = .initBlocked(); |
| | 5346 | defer cancel_region.deinit(); |
| | 5347 | const thread = cancel_region.awaitIoUring() catch |err| switch (err) { |
| | 5348 | error.Canceled => unreachable, // blocked |
| | 5349 | }; |
| | 5350 | thread.enqueue().* = .{ |
| | 5351 | .opcode = .CLOSE, |
| | 5352 | .flags = 0, |
| | 5353 | .ioprio = 0, |
| | 5354 | .fd = fd, |
| | 5355 | .off = 0, |
| | 5356 | .addr = 0, |
| | 5357 | .len = 0, |
| | 5358 | .rw_flags = 0, |
| | 5359 | .user_data = @intFromPtr(cancel_region.fiber), |
| | 5360 | .buf_index = 0, |
| | 5361 | .personality = 0, |
| | 5362 | .splice_fd_in = 0, |
| | 5363 | .addr3 = 0, |
| | 5364 | .resv = 0, |
| | 5365 | }; |
| | 5366 | ev.yield(null, .nothing); |
| | 5367 | switch (cancel_region.errno()) { |
| | 5368 | .BADF => recoverableOsBugDetected(), // Always a race condition. |
| | 5369 | .INTR => {}, // This is still a success. See https://github.com/ziglang/zig/issues/2425 |
| | 5370 | else => {}, |
| | 5371 | } |
| | 5372 | } |
| | 5373 | |
| | 5374 | fn closeAsync(ev: *Evented, fd: fd_t) void { |
| 5432 | _ = ev; | 5375 | _ = ev; |
| 5433 | const thread: *Thread = .current(); | 5376 | const thread: *Thread = .current(); |
| 5434 | thread.enqueue().* = .{ | 5377 | thread.enqueue().* = .{ |
| ... | @@ -5449,14 +5392,13 @@ fn close(ev: *Evented, fd: fd_t) void { | ... | @@ -5449,14 +5392,13 @@ fn close(ev: *Evented, fd: fd_t) void { |
| 5449 | }; | 5392 | }; |
| 5450 | } | 5393 | } |
| 5451 | | 5394 | |
| 5452 | fn fchdir(ev: *Evented, sync: *CancelRegion.Sync, dir: fd_t) process.SetCurrentDirError!void { | 5395 | fn fchdir(sync: *CancelRegion.Sync, dir: fd_t) process.SetCurrentDirError!void { |
| 5453 | _ = ev; | | |
| 5454 | if (dir == linux.AT.FDCWD) return; | 5396 | if (dir == linux.AT.FDCWD) return; |
| 5455 | while (true) { | 5397 | while (true) { |
| 5456 | try sync.cancel_region.await(.nothing); | 5398 | try sync.cancel_region.await(.nothing); |
| 5457 | switch (linux.errno(linux.fchdir(dir))) { | 5399 | switch (linux.errno(linux.fchdir(dir))) { |
| 5458 | .SUCCESS => return, | 5400 | .SUCCESS => return, |
| 5459 | .INTR => continue, | 5401 | .INTR => {}, |
| 5460 | .ACCES => return error.AccessDenied, | 5402 | .ACCES => return error.AccessDenied, |
| 5461 | .NOTDIR => return error.NotDir, | 5403 | .NOTDIR => return error.NotDir, |
| 5462 | .IO => return error.FileSystem, | 5404 | .IO => return error.FileSystem, |
| ... | @@ -5479,7 +5421,7 @@ fn fchmodat( | ... | @@ -5479,7 +5421,7 @@ fn fchmodat( |
| 5479 | try sync.cancel_region.await(.nothing); | 5421 | try sync.cancel_region.await(.nothing); |
| 5480 | switch (linux.errno(linux.fchmodat2(dir, path, mode, flags))) { | 5422 | switch (linux.errno(linux.fchmodat2(dir, path, mode, flags))) { |
| 5481 | .SUCCESS => return, | 5423 | .SUCCESS => return, |
| 5482 | .INTR => continue, | 5424 | .INTR => {}, |
| 5483 | .BADF => |err| return errnoBug(err), | 5425 | .BADF => |err| return errnoBug(err), |
| 5484 | .FAULT => |err| return errnoBug(err), | 5426 | .FAULT => |err| return errnoBug(err), |
| 5485 | .INVAL => |err| return errnoBug(err), | 5427 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -5511,7 +5453,7 @@ fn fchownat( | ... | @@ -5511,7 +5453,7 @@ fn fchownat( |
| 5511 | try sync.cancel_region.await(.nothing); | 5453 | try sync.cancel_region.await(.nothing); |
| 5512 | switch (linux.errno(linux.fchownat(dir, path, owner, group, flags))) { | 5454 | switch (linux.errno(linux.fchownat(dir, path, owner, group, flags))) { |
| 5513 | .SUCCESS => return, | 5455 | .SUCCESS => return, |
| 5514 | .INTR => continue, | 5456 | .INTR => {}, |
| 5515 | .BADF => |err| return errnoBug(err), // likely fd refers to directory opened without `Dir.OpenOptions.iterate` | 5457 | .BADF => |err| return errnoBug(err), // likely fd refers to directory opened without `Dir.OpenOptions.iterate` |
| 5516 | .FAULT => |err| return errnoBug(err), | 5458 | .FAULT => |err| return errnoBug(err), |
| 5517 | .INVAL => |err| return errnoBug(err), | 5459 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -5543,7 +5485,7 @@ fn flock( | ... | @@ -5543,7 +5485,7 @@ fn flock( |
| 5543 | .exclusive => LOCK.EX, | 5485 | .exclusive => LOCK.EX, |
| 5544 | })))) { | 5486 | })))) { |
| 5545 | .SUCCESS => return, | 5487 | .SUCCESS => return, |
| 5546 | .INTR => continue, | 5488 | .INTR => {}, |
| 5547 | .BADF => |err| return errnoBug(err), | 5489 | .BADF => |err| return errnoBug(err), |
| 5548 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5490 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 5549 | .NOLCK => return error.SystemResources, | 5491 | .NOLCK => return error.SystemResources, |
| ... | @@ -5593,7 +5535,7 @@ fn getsockname( | ... | @@ -5593,7 +5535,7 @@ fn getsockname( |
| 5593 | try sync.cancel_region.await(.nothing); | 5535 | try sync.cancel_region.await(.nothing); |
| 5594 | switch (linux.errno(linux.getsockname(socket_fd, addr, addr_len))) { | 5536 | switch (linux.errno(linux.getsockname(socket_fd, addr, addr_len))) { |
| 5595 | .SUCCESS => return, | 5537 | .SUCCESS => return, |
| 5596 | .INTR => continue, | 5538 | .INTR => {}, |
| 5597 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5539 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5598 | .FAULT => |err| return errnoBug(err), | 5540 | .FAULT => |err| return errnoBug(err), |
| 5599 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5541 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| ... | @@ -5634,7 +5576,7 @@ fn linkat( | ... | @@ -5634,7 +5576,7 @@ fn linkat( |
| 5634 | ev.yield(null, .nothing); | 5576 | ev.yield(null, .nothing); |
| 5635 | switch (cancel_region.errno()) { | 5577 | switch (cancel_region.errno()) { |
| 5636 | .SUCCESS => return, | 5578 | .SUCCESS => return, |
| 5637 | .INTR, .CANCELED => continue, | 5579 | .INTR, .CANCELED => {}, |
| 5638 | .ACCES => return error.AccessDenied, | 5580 | .ACCES => return error.AccessDenied, |
| 5639 | .DQUOT => return error.DiskQuota, | 5581 | .DQUOT => return error.DiskQuota, |
| 5640 | .EXIST => return error.PathAlreadyExists, | 5582 | .EXIST => return error.PathAlreadyExists, |
| ... | @@ -5674,7 +5616,7 @@ fn lseek( | ... | @@ -5674,7 +5616,7 @@ fn lseek( |
| 5674 | 8 => linux.lseek(fd, @bitCast(offset), whence), | 5616 | 8 => linux.lseek(fd, @bitCast(offset), whence), |
| 5675 | })) { | 5617 | })) { |
| 5676 | .SUCCESS => return, | 5618 | .SUCCESS => return, |
| 5677 | .INTR => continue, | 5619 | .INTR => {}, |
| 5678 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5620 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5679 | .INVAL => return error.Unseekable, | 5621 | .INVAL => return error.Unseekable, |
| 5680 | .OVERFLOW => return error.Unseekable, | 5622 | .OVERFLOW => return error.Unseekable, |
| ... | @@ -5717,7 +5659,7 @@ fn openat( | ... | @@ -5717,7 +5659,7 @@ fn openat( |
| 5717 | const completion = cancel_region.completion(); | 5659 | const completion = cancel_region.completion(); |
| 5718 | switch (completion.errno()) { | 5660 | switch (completion.errno()) { |
| 5719 | .SUCCESS => return completion.result, | 5661 | .SUCCESS => return completion.result, |
| 5720 | .INTR, .CANCELED => continue, | 5662 | .INTR, .CANCELED => {}, |
| 5721 | .FAULT => |err| return errnoBug(err), | 5663 | .FAULT => |err| return errnoBug(err), |
| 5722 | .INVAL => return error.BadPathName, | 5664 | .INVAL => return error.BadPathName, |
| 5723 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5665 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| ... | @@ -5779,7 +5721,7 @@ fn preadv( | ... | @@ -5779,7 +5721,7 @@ fn preadv( |
| 5779 | const completion = cancel_region.completion(); | 5721 | const completion = cancel_region.completion(); |
| 5780 | switch (completion.errno()) { | 5722 | switch (completion.errno()) { |
| 5781 | .SUCCESS => return @as(u32, @bitCast(completion.result)), | 5723 | .SUCCESS => return @as(u32, @bitCast(completion.result)), |
| 5782 | .INTR, .CANCELED => continue, | 5724 | .INTR, .CANCELED => {}, |
| 5783 | .INVAL => |err| return errnoBug(err), | 5725 | .INVAL => |err| return errnoBug(err), |
| 5784 | .FAULT => |err| return errnoBug(err), | 5726 | .FAULT => |err| return errnoBug(err), |
| 5785 | .AGAIN => return error.WouldBlock, | 5727 | .AGAIN => return error.WouldBlock, |
| ... | @@ -5826,7 +5768,7 @@ fn pwritev( | ... | @@ -5826,7 +5768,7 @@ fn pwritev( |
| 5826 | const completion = cancel_region.completion(); | 5768 | const completion = cancel_region.completion(); |
| 5827 | switch (completion.errno()) { | 5769 | switch (completion.errno()) { |
| 5828 | .SUCCESS => return @as(u32, @bitCast(completion.result)), | 5770 | .SUCCESS => return @as(u32, @bitCast(completion.result)), |
| 5829 | .INTR, .CANCELED => continue, | 5771 | .INTR, .CANCELED => {}, |
| 5830 | .INVAL => |err| return errnoBug(err), | 5772 | .INVAL => |err| return errnoBug(err), |
| 5831 | .FAULT => |err| return errnoBug(err), | 5773 | .FAULT => |err| return errnoBug(err), |
| 5832 | .AGAIN => return error.WouldBlock, | 5774 | .AGAIN => return error.WouldBlock, |
| ... | @@ -5876,7 +5818,7 @@ fn realPath( | ... | @@ -5876,7 +5818,7 @@ fn realPath( |
| 5876 | const rc = linux.readlink(proc_path, out_buffer.ptr, out_buffer.len); | 5818 | const rc = linux.readlink(proc_path, out_buffer.ptr, out_buffer.len); |
| 5877 | switch (linux.errno(rc)) { | 5819 | switch (linux.errno(rc)) { |
| 5878 | .SUCCESS => return rc, | 5820 | .SUCCESS => return rc, |
| 5879 | .INTR => continue, | 5821 | .INTR => {}, |
| 5880 | .ACCES => return error.AccessDenied, | 5822 | .ACCES => return error.AccessDenied, |
| 5881 | .FAULT => |err| return errnoBug(err), | 5823 | .FAULT => |err| return errnoBug(err), |
| 5882 | .IO => return error.FileSystem, | 5824 | .IO => return error.FileSystem, |
| ... | @@ -5921,7 +5863,7 @@ fn renameat( | ... | @@ -5921,7 +5863,7 @@ fn renameat( |
| 5921 | ev.yield(null, .nothing); | 5863 | ev.yield(null, .nothing); |
| 5922 | switch (cancel_region.errno()) { | 5864 | switch (cancel_region.errno()) { |
| 5923 | .SUCCESS => return, | 5865 | .SUCCESS => return, |
| 5924 | .INTR, .CANCELED => continue, | 5866 | .INTR, .CANCELED => {}, |
| 5925 | .ACCES => return error.AccessDenied, | 5867 | .ACCES => return error.AccessDenied, |
| 5926 | .PERM => return error.PermissionDenied, | 5868 | .PERM => return error.PermissionDenied, |
| 5927 | .BUSY => return error.FileBusy, | 5869 | .BUSY => return error.FileBusy, |
| ... | @@ -5988,7 +5930,7 @@ fn setsockopt( | ... | @@ -5988,7 +5930,7 @@ fn setsockopt( |
| 5988 | ev.yield(null, .nothing); | 5930 | ev.yield(null, .nothing); |
| 5989 | switch (cancel_region.errno()) { | 5931 | switch (cancel_region.errno()) { |
| 5990 | .SUCCESS => return, | 5932 | .SUCCESS => return, |
| 5991 | .INTR, .CANCELED => continue, | 5933 | .INTR, .CANCELED => {}, |
| 5992 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5934 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5993 | .NOTSOCK => |err| return errnoBug(err), | 5935 | .NOTSOCK => |err| return errnoBug(err), |
| 5994 | .INVAL => |err| return errnoBug(err), | 5936 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -6039,7 +5981,7 @@ fn socket( | ... | @@ -6039,7 +5981,7 @@ fn socket( |
| 6039 | const completion = cancel_region.completion(); | 5981 | const completion = cancel_region.completion(); |
| 6040 | switch (completion.errno()) { | 5982 | switch (completion.errno()) { |
| 6041 | .SUCCESS => break completion.result, | 5983 | .SUCCESS => break completion.result, |
| 6042 | .INTR, .CANCELED => continue, | 5984 | .INTR, .CANCELED => {}, |
| 6043 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, | 5985 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 6044 | .INVAL => return error.ProtocolUnsupportedBySystem, | 5986 | .INVAL => return error.ProtocolUnsupportedBySystem, |
| 6045 | .MFILE => return error.ProcessFdQuotaExceeded, | 5987 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -6051,7 +5993,7 @@ fn socket( | ... | @@ -6051,7 +5993,7 @@ fn socket( |
| 6051 | else => |err| return unexpectedErrno(err), | 5993 | else => |err| return unexpectedErrno(err), |
| 6052 | } | 5994 | } |
| 6053 | }; | 5995 | }; |
| 6054 | errdefer ev.close(socket_fd); | 5996 | errdefer ev.closeAsync(socket_fd); |
| 6055 | | 5997 | |
| 6056 | if (options.ip6_only) { | 5998 | if (options.ip6_only) { |
| 6057 | if (linux.IPV6 == void) return error.OptionUnsupported; | 5999 | if (linux.IPV6 == void) return error.OptionUnsupported; |
| ... | @@ -6101,7 +6043,7 @@ fn statx( | ... | @@ -6101,7 +6043,7 @@ fn statx( |
| 6101 | ev.yield(null, .nothing); | 6043 | ev.yield(null, .nothing); |
| 6102 | switch (cancel_region.errno()) { | 6044 | switch (cancel_region.errno()) { |
| 6103 | .SUCCESS => return statFromLinux(&statx_buf), | 6045 | .SUCCESS => return statFromLinux(&statx_buf), |
| 6104 | .INTR, .CANCELED => continue, | 6046 | .INTR, .CANCELED => {}, |
| 6105 | .ACCES => return error.AccessDenied, | 6047 | .ACCES => return error.AccessDenied, |
| 6106 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 6048 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 6107 | .FAULT => |err| return errnoBug(err), | 6049 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -6140,7 +6082,7 @@ fn utimensat( | ... | @@ -6140,7 +6082,7 @@ fn utimensat( |
| 6140 | try sync.cancel_region.await(.nothing); | 6082 | try sync.cancel_region.await(.nothing); |
| 6141 | switch (linux.errno(linux.utimensat(dir, path, times, flags))) { | 6083 | switch (linux.errno(linux.utimensat(dir, path, times, flags))) { |
| 6142 | .SUCCESS => return, | 6084 | .SUCCESS => return, |
| 6143 | .INTR => continue, | 6085 | .INTR => {}, |
| 6144 | .BADF => |err| return errnoBug(err), // always a race condition | 6086 | .BADF => |err| return errnoBug(err), // always a race condition |
| 6145 | .FAULT => |err| return errnoBug(err), | 6087 | .FAULT => |err| return errnoBug(err), |
| 6146 | .INVAL => |err| return errnoBug(err), | 6088 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -6152,19 +6094,33 @@ fn utimensat( | ... | @@ -6152,19 +6094,33 @@ fn utimensat( |
| 6152 | } | 6094 | } |
| 6153 | } | 6095 | } |
| 6154 | | 6096 | |
| 6155 | fn writeAll( | 6097 | fn writeAllSync(sync: *CancelRegion.Sync, fd: fd_t, buffer: []const u8) File.Writer.Error!void { |
| 6156 | ev: *Evented, | | |
| 6157 | cancel_region: *CancelRegion, | | |
| 6158 | fd: fd_t, | | |
| 6159 | buffer: []const u8, | | |
| 6160 | ) (File.Writer.Error || error{EndOfStream})!void { | | |
| 6161 | var index: usize = 0; | 6098 | var index: usize = 0; |
| 6162 | while (buffer.len - index != 0) { | 6099 | while (buffer.len - index != 0) index += try writeSync(sync, fd, buffer[index..]); |
| 6163 | const len = try ev.pwritev(cancel_region, fd, &.{ | 6100 | } |
| 6164 | .{ .base = buffer[index..].ptr, .len = buffer.len - index }, | 6101 | |
| 6165 | }, null); | 6102 | fn writeSync(sync: *CancelRegion.Sync, fd: fd_t, buffer: []const u8) File.Writer.Error!usize { |
| 6166 | if (len == 0) return error.EndOfStream; | 6103 | while (true) { |
| 6167 | index += len; | 6104 | try sync.cancel_region.await(.nothing); |
| | 6105 | const rc = linux.write(fd, buffer.ptr, buffer.len); |
| | 6106 | switch (linux.errno(rc)) { |
| | 6107 | .SUCCESS => return @intCast(rc), |
| | 6108 | .INTR => {}, |
| | 6109 | .INVAL => |err| return errnoBug(err), |
| | 6110 | .FAULT => |err| return errnoBug(err), |
| | 6111 | .AGAIN => return error.WouldBlock, |
| | 6112 | .BADF => return error.NotOpenForWriting, // Can be a race condition. |
| | 6113 | .DESTADDRREQ => |err| return errnoBug(err), // `connect` was never called. |
| | 6114 | .DQUOT => return error.DiskQuota, |
| | 6115 | .FBIG => return error.FileTooBig, |
| | 6116 | .IO => return error.InputOutput, |
| | 6117 | .NOSPC => return error.NoSpaceLeft, |
| | 6118 | .PERM => return error.PermissionDenied, |
| | 6119 | .PIPE => return error.BrokenPipe, |
| | 6120 | .CONNRESET => |err| return errnoBug(err), // Not a socket handle. |
| | 6121 | .BUSY => return error.DeviceBusy, |
| | 6122 | else => |err| return unexpectedErrno(err), |
| | 6123 | } |
| 6168 | } | 6124 | } |
| 6169 | } | 6125 | } |
| 6170 | | 6126 | |