| ... | @@ -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 }, |
| ... | @@ -856,7 +855,6 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v | ... | @@ -856,7 +855,6 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v |
| 856 | main_fiber.* = .{ | 855 | main_fiber.* = .{ |
| 857 | .required_align = {}, | 856 | .required_align = {}, |
| 858 | .context = undefined, | 857 | .context = undefined, |
| 859 | .await_count = 0, | | |
| 860 | .link = .{ .awaiter = null }, | 858 | .link = .{ .awaiter = null }, |
| 861 | .status = .{ .queue_next = null }, | 859 | .status = .{ .queue_next = null }, |
| 862 | .cancel_status = .unrequested, | 860 | .cancel_status = .unrequested, |
| ... | @@ -1260,7 +1258,7 @@ const SwitchMessage = struct { | ... | @@ -1260,7 +1258,7 @@ const SwitchMessage = struct { |
| 1260 | const PendingTask = union(enum) { | 1258 | const PendingTask = union(enum) { |
| 1261 | nothing, | 1259 | nothing, |
| 1262 | reschedule, | 1260 | reschedule, |
| 1263 | await: u31, | 1261 | await: *Fiber, |
| 1264 | group_await: Group, | 1262 | group_await: Group, |
| 1265 | group_cancel: Group, | 1263 | group_cancel: Group, |
| 1266 | batch_await: *Io.Batch, | 1264 | batch_await: *Io.Batch, |
| ... | @@ -1284,10 +1282,11 @@ const SwitchMessage = struct { | ... | @@ -1284,10 +1282,11 @@ const SwitchMessage = struct { |
| 1284 | assert(fiber.status.queue_next == null); | 1282 | assert(fiber.status.queue_next == null); |
| 1285 | _ = ev.schedule(thread, .{ .head = fiber, .tail = fiber }); | 1283 | _ = ev.schedule(thread, .{ .head = fiber, .tail = fiber }); |
| 1286 | }, | 1284 | }, |
| 1287 | .await => |count| { | 1285 | .await => |awaiting| { |
| 1288 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); | 1286 | const awaiter: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); |
| 1289 | if (@atomicRmw(i32, &fiber.await_count, .Sub, count, .monotonic) > 0) | 1287 | assert(awaiter.status.queue_next == null); |
| 1290 | _ = 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 }); |
| 1291 | }, | 1290 | }, |
| 1292 | .group_await => |group| { | 1291 | .group_await => |group| { |
| 1293 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); | 1292 | const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.old)); |
| ... | @@ -1361,7 +1360,7 @@ fn crashHandler(userdata: ?*anyopaque) void { | ... | @@ -1361,7 +1360,7 @@ fn crashHandler(userdata: ?*anyopaque) void { |
| 1361 | } | 1360 | } |
| 1362 | | 1361 | |
| 1363 | const AsyncClosure = struct { | 1362 | const AsyncClosure = struct { |
| 1364 | ev: *Evented, | 1363 | evented: *Evented, |
| 1365 | fiber: *Fiber, | 1364 | fiber: *Fiber, |
| 1366 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, | 1365 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, |
| 1367 | result_align: Alignment, | 1366 | result_align: Alignment, |
| ... | @@ -1398,16 +1397,11 @@ const AsyncClosure = struct { | ... | @@ -1398,16 +1397,11 @@ const AsyncClosure = struct { |
| 1398 | closure: *AsyncClosure, | 1397 | closure: *AsyncClosure, |
| 1399 | message: *const SwitchMessage, | 1398 | message: *const SwitchMessage, |
| 1400 | ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { | 1399 | ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { |
| 1401 | message.handle(closure.ev); | 1400 | const ev = closure.evented; |
| 1402 | const fiber = closure.fiber; | 1401 | const fiber = closure.fiber; |
| | 1402 | message.handle(ev); |
| 1403 | closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align)); | 1403 | closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align)); |
| 1404 | closure.ev.yield( | 1404 | ev.yield(@atomicRmw(?*Fiber, &fiber.link.awaiter, .Xchg, Fiber.finished, .acq_rel), .nothing); |
| 1405 | if (@atomicRmw(?*Fiber, &fiber.link.awaiter, .Xchg, Fiber.finished, .acq_rel)) |awaiter| | | |
| 1406 | if (@atomicRmw(i32, &awaiter.await_count, .Add, 1, .monotonic) == -1) awaiter else null | | |
| 1407 | else | | |
| 1408 | null, | | |
| 1409 | .nothing, | | |
| 1410 | ); | | |
| 1411 | unreachable; // switched to dead fiber | 1405 | unreachable; // switched to dead fiber |
| 1412 | } | 1406 | } |
| 1413 | }; | 1407 | }; |
| ... | @@ -1461,7 +1455,6 @@ fn concurrent( | ... | @@ -1461,7 +1455,6 @@ fn concurrent( |
| 1461 | }, | 1455 | }, |
| 1462 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), | 1456 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), |
| 1463 | }, | 1457 | }, |
| 1464 | .await_count = 0, | | |
| 1465 | .link = .{ .awaiter = null }, | 1458 | .link = .{ .awaiter = null }, |
| 1466 | .status = .{ .queue_next = null }, | 1459 | .status = .{ .queue_next = null }, |
| 1467 | .cancel_status = .unrequested, | 1460 | .cancel_status = .unrequested, |
| ... | @@ -1479,7 +1472,7 @@ fn concurrent( | ... | @@ -1479,7 +1472,7 @@ fn concurrent( |
| 1479 | }, | 1472 | }, |
| 1480 | }; | 1473 | }; |
| 1481 | closure.* = .{ | 1474 | closure.* = .{ |
| 1482 | .ev = ev, | 1475 | .evented = ev, |
| 1483 | .fiber = fiber, | 1476 | .fiber = fiber, |
| 1484 | .start = start, | 1477 | .start = start, |
| 1485 | .result_align = result_alignment, | 1478 | .result_align = result_alignment, |
| ... | @@ -1498,18 +1491,11 @@ fn await( | ... | @@ -1498,18 +1491,11 @@ fn await( |
| 1498 | result_alignment: Alignment, | 1491 | result_alignment: Alignment, |
| 1499 | ) void { | 1492 | ) void { |
| 1500 | const ev: *Evented = @ptrCast(@alignCast(userdata)); | 1493 | const ev: *Evented = @ptrCast(@alignCast(userdata)); |
| 1501 | const fiber = Thread.current().currentFiber(); | 1494 | const awaiting: *Fiber = @ptrCast(@alignCast(future)); |
| 1502 | const future_fiber: *Fiber = @ptrCast(@alignCast(future)); | 1495 | if (@atomicLoad(?*Fiber, &awaiting.link.awaiter, .acquire) != Fiber.finished) |
| 1503 | if (@atomicRmw(?*Fiber, &future_fiber.link.awaiter, .Xchg, fiber, .acq_rel)) |awaiter| { | 1496 | ev.yield(null, .{ .await = awaiting }); |
| 1504 | assert(awaiter == Fiber.finished); | 1497 | @memcpy(result, awaiting.resultBytes(result_alignment)); |
| 1505 | } else while (true) { | 1498 | awaiting.destroy(); |
| 1506 | ev.yield(null, .{ .await = 1 }); | | |
| 1507 | const awaiter = @atomicLoad(?*Fiber, &future_fiber.link.awaiter, .acquire); | | |
| 1508 | if (awaiter == Fiber.finished) break; | | |
| 1509 | assert(awaiter == fiber); // spurious wakeup | | |
| 1510 | } | | |
| 1511 | @memcpy(result, future_fiber.resultBytes(result_alignment)); | | |
| 1512 | future_fiber.destroy(); | | |
| 1513 | } | 1499 | } |
| 1514 | | 1500 | |
| 1515 | fn cancel( | 1501 | fn cancel( |
| ... | @@ -1726,7 +1712,7 @@ const Group = struct { | ... | @@ -1726,7 +1712,7 @@ const Group = struct { |
| 1726 | } | 1712 | } |
| 1727 | | 1713 | |
| 1728 | const AsyncClosure = struct { | 1714 | const AsyncClosure = struct { |
| 1729 | ev: *Evented, | 1715 | evented: *Evented, |
| 1730 | group: Group, | 1716 | group: Group, |
| 1731 | fiber: *Fiber, | 1717 | fiber: *Fiber, |
| 1732 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, | 1718 | start: *const fn (context: *const anyopaque) Io.Cancelable!void, |
| ... | @@ -1765,19 +1751,16 @@ const Group = struct { | ... | @@ -1765,19 +1751,16 @@ const Group = struct { |
| 1765 | closure: *Group.AsyncClosure, | 1751 | closure: *Group.AsyncClosure, |
| 1766 | message: *const SwitchMessage, | 1752 | message: *const SwitchMessage, |
| 1767 | ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { | 1753 | ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { |
| 1768 | message.handle(closure.ev); | 1754 | const ev = closure.evented; |
| 1769 | assert(closure.fiber.status.queue_next == null); | | |
| 1770 | const result = closure.start(closure.contextPointer()); | | |
| 1771 | const ev = closure.ev; | | |
| 1772 | const group = closure.group; | | |
| 1773 | const fiber = closure.fiber; | 1755 | const fiber = closure.fiber; |
| 1774 | const cancel_acknowledged = fiber.cancel_protection.acknowledged; | 1756 | message.handle(ev); |
| 1775 | if (result) { | 1757 | assert(fiber.status.queue_next == null); |
| 1776 | 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` |
| 1777 | } else |err| switch (err) { | 1760 | } else |err| switch (err) { |
| 1778 | 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 |
| 1779 | } | 1762 | } |
| 1780 | ev.yield(group.removeFiber(ev, fiber), .destroy); | 1763 | ev.yield(closure.group.removeFiber(ev, fiber), .destroy); |
| 1781 | unreachable; // switched to dead fiber | 1764 | unreachable; // switched to dead fiber |
| 1782 | } | 1765 | } |
| 1783 | }; | 1766 | }; |
| ... | @@ -1845,7 +1828,6 @@ fn groupConcurrent( | ... | @@ -1845,7 +1828,6 @@ fn groupConcurrent( |
| 1845 | }, | 1828 | }, |
| 1846 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), | 1829 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), |
| 1847 | }, | 1830 | }, |
| 1848 | .await_count = 0, | | |
| 1849 | .link = .{ .group = .{ .prev = null, .next = null } }, | 1831 | .link = .{ .group = .{ .prev = null, .next = null } }, |
| 1850 | .status = .{ .queue_next = null }, | 1832 | .status = .{ .queue_next = null }, |
| 1851 | .cancel_status = .unrequested, | 1833 | .cancel_status = .unrequested, |
| ... | @@ -1863,7 +1845,7 @@ fn groupConcurrent( | ... | @@ -1863,7 +1845,7 @@ fn groupConcurrent( |
| 1863 | }, | 1845 | }, |
| 1864 | }; | 1846 | }; |
| 1865 | closure.* = .{ | 1847 | closure.* = .{ |
| 1866 | .ev = ev, | 1848 | .evented = ev, |
| 1867 | .group = group, | 1849 | .group = group, |
| 1868 | .fiber = fiber, | 1850 | .fiber = fiber, |
| 1869 | .start = start, | 1851 | .start = start, |
| ... | @@ -2173,7 +2155,7 @@ fn deviceIoControl( | ... | @@ -2173,7 +2155,7 @@ fn deviceIoControl( |
| 2173 | 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)); |
| 2174 | switch (linux.errno(rc)) { | 2156 | switch (linux.errno(rc)) { |
| 2175 | .SUCCESS => return @bitCast(@as(u32, @truncate(rc))), | 2157 | .SUCCESS => return @bitCast(@as(u32, @truncate(rc))), |
| 2176 | .INTR => continue, | 2158 | .INTR => {}, |
| 2177 | else => |err| return -@as(i32, @intFromEnum(err)), | 2159 | else => |err| return -@as(i32, @intFromEnum(err)), |
| 2178 | } | 2160 | } |
| 2179 | } | 2161 | } |
| ... | @@ -2571,7 +2553,7 @@ fn dirCreateDir( | ... | @@ -2571,7 +2553,7 @@ fn dirCreateDir( |
| 2571 | ev.yield(null, .nothing); | 2553 | ev.yield(null, .nothing); |
| 2572 | switch (cancel_region.errno()) { | 2554 | switch (cancel_region.errno()) { |
| 2573 | .SUCCESS => return, | 2555 | .SUCCESS => return, |
| 2574 | .INTR, .CANCELED => continue, | 2556 | .INTR, .CANCELED => {}, |
| 2575 | .ACCES => return error.AccessDenied, | 2557 | .ACCES => return error.AccessDenied, |
| 2576 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 2558 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 2577 | .PERM => return error.PermissionDenied, | 2559 | .PERM => return error.PermissionDenied, |
| ... | @@ -2654,7 +2636,7 @@ fn filePathKind(ev: *Evented, dir: Dir, sub_path: []const u8) !File.Kind { | ... | @@ -2654,7 +2636,7 @@ fn filePathKind(ev: *Evented, dir: Dir, sub_path: []const u8) !File.Kind { |
| 2654 | if (!statx_buf.mask.TYPE) return error.Unexpected; | 2636 | if (!statx_buf.mask.TYPE) return error.Unexpected; |
| 2655 | return statxKind(statx_buf.mode); | 2637 | return statxKind(statx_buf.mode); |
| 2656 | }, | 2638 | }, |
| 2657 | .INTR, .CANCELED => continue, | 2639 | .INTR, .CANCELED => {}, |
| 2658 | .ACCES => |err| return errnoBug(err), | 2640 | .ACCES => |err| return errnoBug(err), |
| 2659 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 2641 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 2660 | .FAULT => |err| return errnoBug(err), | 2642 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -2767,7 +2749,7 @@ fn dirAccess( | ... | @@ -2767,7 +2749,7 @@ fn dirAccess( |
| 2767 | try sync.cancel_region.await(.nothing); | 2749 | try sync.cancel_region.await(.nothing); |
| 2768 | 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))) { |
| 2769 | .SUCCESS => return, | 2751 | .SUCCESS => return, |
| 2770 | .INTR => continue, | 2752 | .INTR => {}, |
| 2771 | .ACCES => return error.AccessDenied, | 2753 | .ACCES => return error.AccessDenied, |
| 2772 | .PERM => return error.PermissionDenied, | 2754 | .PERM => return error.PermissionDenied, |
| 2773 | .ROFS => return error.ReadOnlyFileSystem, | 2755 | .ROFS => return error.ReadOnlyFileSystem, |
| ... | @@ -2806,7 +2788,7 @@ fn dirCreateFile( | ... | @@ -2806,7 +2788,7 @@ fn dirCreateFile( |
| 2806 | .EXCL = flags.exclusive, | 2788 | .EXCL = flags.exclusive, |
| 2807 | .CLOEXEC = true, | 2789 | .CLOEXEC = true, |
| 2808 | }, flags.permissions.toMode()); | 2790 | }, flags.permissions.toMode()); |
| 2809 | errdefer ev.close(fd); | 2791 | errdefer ev.closeAsync(fd); |
| 2810 | | 2792 | |
| 2811 | switch (flags.lock) { | 2793 | switch (flags.lock) { |
| 2812 | .none => {}, | 2794 | .none => {}, |
| ... | @@ -2994,7 +2976,7 @@ fn dirOpenFile( | ... | @@ -2994,7 +2976,7 @@ fn dirOpenFile( |
| 2994 | .CLOEXEC = true, | 2976 | .CLOEXEC = true, |
| 2995 | .PATH = flags.path_only, | 2977 | .PATH = flags.path_only, |
| 2996 | }, 0); | 2978 | }, 0); |
| 2997 | errdefer ev.close(fd); | 2979 | errdefer ev.closeAsync(fd); |
| 2998 | | 2980 | |
| 2999 | if (!flags.allow_directory) { | 2981 | if (!flags.allow_directory) { |
| 3000 | const is_dir = is_dir: { | 2982 | const is_dir = is_dir: { |
| ... | @@ -3048,7 +3030,7 @@ fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Read | ... | @@ -3048,7 +3030,7 @@ fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Read |
| 3048 | 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); |
| 3049 | switch (linux.errno(rc)) { | 3031 | switch (linux.errno(rc)) { |
| 3050 | .SUCCESS => break rc, | 3032 | .SUCCESS => break rc, |
| 3051 | .INTR => continue, | 3033 | .INTR => {}, |
| 3052 | .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. |
| 3053 | .FAULT => |err| return errnoBug(err), | 3035 | .FAULT => |err| return errnoBug(err), |
| 3054 | .NOTDIR => |err| return errnoBug(err), | 3036 | .NOTDIR => |err| return errnoBug(err), |
| ... | @@ -3141,7 +3123,7 @@ fn dirRealPathFile( | ... | @@ -3141,7 +3123,7 @@ fn dirRealPathFile( |
| 3141 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. | 3123 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. |
| 3142 | else => |e| return e, | 3124 | else => |e| return e, |
| 3143 | }; | 3125 | }; |
| 3144 | defer ev.close(fd); | 3126 | defer ev.closeAsync(fd); |
| 3145 | return ev.realPath(try maybe_sync.enterSync(ev), fd, out_buffer); | 3127 | return ev.realPath(try maybe_sync.enterSync(ev), fd, out_buffer); |
| 3146 | } | 3128 | } |
| 3147 | | 3129 | |
| ... | @@ -3174,7 +3156,7 @@ fn dirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Dele | ... | @@ -3174,7 +3156,7 @@ fn dirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Dele |
| 3174 | ev.yield(null, .nothing); | 3156 | ev.yield(null, .nothing); |
| 3175 | switch (cancel_region.errno()) { | 3157 | switch (cancel_region.errno()) { |
| 3176 | .SUCCESS => return, | 3158 | .SUCCESS => return, |
| 3177 | .INTR, .CANCELED => continue, | 3159 | .INTR, .CANCELED => {}, |
| 3178 | .PERM => return error.PermissionDenied, | 3160 | .PERM => return error.PermissionDenied, |
| 3179 | .ACCES => return error.AccessDenied, | 3161 | .ACCES => return error.AccessDenied, |
| 3180 | .BUSY => return error.FileBusy, | 3162 | .BUSY => return error.FileBusy, |
| ... | @@ -3226,7 +3208,7 @@ fn dirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Delet | ... | @@ -3226,7 +3208,7 @@ fn dirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.Delet |
| 3226 | ev.yield(null, .nothing); | 3208 | ev.yield(null, .nothing); |
| 3227 | switch (cancel_region.errno()) { | 3209 | switch (cancel_region.errno()) { |
| 3228 | .SUCCESS => return, | 3210 | .SUCCESS => return, |
| 3229 | .INTR, .CANCELED => continue, | 3211 | .INTR, .CANCELED => {}, |
| 3230 | .ACCES => return error.AccessDenied, | 3212 | .ACCES => return error.AccessDenied, |
| 3231 | .PERM => return error.PermissionDenied, | 3213 | .PERM => return error.PermissionDenied, |
| 3232 | .BUSY => return error.FileBusy, | 3214 | .BUSY => return error.FileBusy, |
| ... | @@ -3342,7 +3324,7 @@ fn dirSymLink( | ... | @@ -3342,7 +3324,7 @@ fn dirSymLink( |
| 3342 | ev.yield(null, .nothing); | 3324 | ev.yield(null, .nothing); |
| 3343 | switch (cancel_region.errno()) { | 3325 | switch (cancel_region.errno()) { |
| 3344 | .SUCCESS => return, | 3326 | .SUCCESS => return, |
| 3345 | .INTR, .CANCELED => continue, | 3327 | .INTR, .CANCELED => {}, |
| 3346 | .FAULT => |err| return errnoBug(err), | 3328 | .FAULT => |err| return errnoBug(err), |
| 3347 | .INVAL => |err| return errnoBug(err), | 3329 | .INVAL => |err| return errnoBug(err), |
| 3348 | .ACCES => return error.AccessDenied, | 3330 | .ACCES => return error.AccessDenied, |
| ... | @@ -3381,7 +3363,7 @@ fn dirReadLink( | ... | @@ -3381,7 +3363,7 @@ fn dirReadLink( |
| 3381 | 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); |
| 3382 | switch (linux.errno(rc)) { | 3364 | switch (linux.errno(rc)) { |
| 3383 | .SUCCESS => return @bitCast(rc), | 3365 | .SUCCESS => return @bitCast(rc), |
| 3384 | .INTR => continue, | 3366 | .INTR => {}, |
| 3385 | .ACCES => return error.AccessDenied, | 3367 | .ACCES => return error.AccessDenied, |
| 3386 | .FAULT => |err| return errnoBug(err), | 3368 | .FAULT => |err| return errnoBug(err), |
| 3387 | .INVAL => return error.NotLink, | 3369 | .INVAL => return error.NotLink, |
| ... | @@ -3571,7 +3553,7 @@ fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { | ... | @@ -3571,7 +3553,7 @@ fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { |
| 3571 | if (!statx_buf.mask.SIZE) return error.Unexpected; | 3553 | if (!statx_buf.mask.SIZE) return error.Unexpected; |
| 3572 | return statx_buf.size; | 3554 | return statx_buf.size; |
| 3573 | }, | 3555 | }, |
| 3574 | .INTR, .CANCELED => continue, | 3556 | .INTR, .CANCELED => {}, |
| 3575 | .ACCES => |err| return errnoBug(err), | 3557 | .ACCES => |err| return errnoBug(err), |
| 3576 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 3558 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 3577 | .FAULT => |err| return errnoBug(err), | 3559 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -3754,7 +3736,7 @@ fn fileSync(userdata: ?*anyopaque, file: File) File.SyncError!void { | ... | @@ -3754,7 +3736,7 @@ fn fileSync(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 3754 | ev.yield(null, .nothing); | 3736 | ev.yield(null, .nothing); |
| 3755 | switch (cancel_region.errno()) { | 3737 | switch (cancel_region.errno()) { |
| 3756 | .SUCCESS => return, | 3738 | .SUCCESS => return, |
| 3757 | .INTR, .CANCELED => continue, | 3739 | .INTR, .CANCELED => {}, |
| 3758 | .BADF => |err| return errnoBug(err), | 3740 | .BADF => |err| return errnoBug(err), |
| 3759 | .INVAL => |err| return errnoBug(err), | 3741 | .INVAL => |err| return errnoBug(err), |
| 3760 | .ROFS => |err| return errnoBug(err), | 3742 | .ROFS => |err| return errnoBug(err), |
| ... | @@ -3776,7 +3758,7 @@ fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { | ... | @@ -3776,7 +3758,7 @@ fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 3776 | const rc = linux.ioctl(file.handle, linux.T.IOCGWINSZ, @intFromPtr(&wsz)); | 3758 | const rc = linux.ioctl(file.handle, linux.T.IOCGWINSZ, @intFromPtr(&wsz)); |
| 3777 | switch (linux.errno(rc)) { | 3759 | switch (linux.errno(rc)) { |
| 3778 | .SUCCESS => return true, | 3760 | .SUCCESS => return true, |
| 3779 | .INTR => continue, | 3761 | .INTR => {}, |
| 3780 | else => return false, | 3762 | else => return false, |
| 3781 | } | 3763 | } |
| 3782 | } | 3764 | } |
| ... | @@ -3812,7 +3794,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE | ... | @@ -3812,7 +3794,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE |
| 3812 | ev.yield(null, .nothing); | 3794 | ev.yield(null, .nothing); |
| 3813 | switch (cancel_region.errno()) { | 3795 | switch (cancel_region.errno()) { |
| 3814 | .SUCCESS => return, | 3796 | .SUCCESS => return, |
| 3815 | .INTR, .CANCELED => continue, | 3797 | .INTR, .CANCELED => {}, |
| 3816 | .FBIG => return error.FileTooBig, | 3798 | .FBIG => return error.FileTooBig, |
| 3817 | .IO => return error.InputOutput, | 3799 | .IO => return error.InputOutput, |
| 3818 | .PERM => return error.PermissionDenied, | 3800 | .PERM => return error.PermissionDenied, |
| ... | @@ -3994,7 +3976,7 @@ fn fileMemoryMapCreate( | ... | @@ -3994,7 +3976,7 @@ fn fileMemoryMapCreate( |
| 3994 | 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); |
| 3995 | switch (linux.errno(rc)) { | 3977 | switch (linux.errno(rc)) { |
| 3996 | .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], |
| 3997 | .INTR => continue, | 3979 | .INTR => {}, |
| 3998 | .ACCES => return error.AccessDenied, | 3980 | .ACCES => return error.AccessDenied, |
| 3999 | .AGAIN => return error.LockedMemoryLimitExceeded, | 3981 | .AGAIN => return error.LockedMemoryLimitExceeded, |
| 4000 | .MFILE => return error.ProcessFdQuotaExceeded, | 3982 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -4054,7 +4036,7 @@ fn fileMemoryMapSetLength( | ... | @@ -4054,7 +4036,7 @@ fn fileMemoryMapSetLength( |
| 4054 | 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); |
| 4055 | switch (linux.errno(rc)) { | 4037 | switch (linux.errno(rc)) { |
| 4056 | .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], |
| 4057 | .INTR => continue, | 4039 | .INTR => {}, |
| 4058 | .AGAIN => return error.LockedMemoryLimitExceeded, | 4040 | .AGAIN => return error.LockedMemoryLimitExceeded, |
| 4059 | .NOMEM => return error.OutOfMemory, | 4041 | .NOMEM => return error.OutOfMemory, |
| 4060 | .INVAL => |err| return errnoBug(err), | 4042 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -4163,7 +4145,7 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr | ... | @@ -4163,7 +4145,7 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr |
| 4163 | try sync.cancel_region.await(.nothing); | 4145 | try sync.cancel_region.await(.nothing); |
| 4164 | switch (linux.errno(linux.getcwd(buffer.ptr, buffer.len))) { | 4146 | switch (linux.errno(linux.getcwd(buffer.ptr, buffer.len))) { |
| 4165 | .SUCCESS => return std.mem.findScalar(u8, buffer, 0).?, | 4147 | .SUCCESS => return std.mem.findScalar(u8, buffer, 0).?, |
| 4166 | .INTR => continue, | 4148 | .INTR => {}, |
| 4167 | .NOENT => return error.CurrentDirUnlinked, | 4149 | .NOENT => return error.CurrentDirUnlinked, |
| 4168 | .RANGE => return error.NameTooLong, | 4150 | .RANGE => return error.NameTooLong, |
| 4169 | .FAULT => |err| return errnoBug(err), | 4151 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -4178,7 +4160,7 @@ fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirEr | ... | @@ -4178,7 +4160,7 @@ fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirEr |
| 4178 | if (dir.handle == linux.AT.FDCWD) return; | 4160 | if (dir.handle == linux.AT.FDCWD) return; |
| 4179 | var sync: CancelRegion.Sync = try .init(ev); | 4161 | var sync: CancelRegion.Sync = try .init(ev); |
| 4180 | defer sync.deinit(ev); | 4162 | defer sync.deinit(ev); |
| 4181 | return ev.fchdir(&sync, dir.handle); | 4163 | return fchdir(&sync, dir.handle); |
| 4182 | } | 4164 | } |
| 4183 | | 4165 | |
| 4184 | fn processSetCurrentPath(userdata: ?*anyopaque, dir_path: []const u8) ChdirError!void { | 4166 | fn processSetCurrentPath(userdata: ?*anyopaque, dir_path: []const u8) ChdirError!void { |
| ... | @@ -4215,7 +4197,7 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces | ... | @@ -4215,7 +4197,7 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces |
| 4215 | | 4197 | |
| 4216 | var sync: CancelRegion.Sync = try .init(ev); | 4198 | var sync: CancelRegion.Sync = try .init(ev); |
| 4217 | defer sync.deinit(ev); | 4199 | defer sync.deinit(ev); |
| 4218 | 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); |
| 4219 | } | 4201 | } |
| 4220 | | 4202 | |
| 4221 | fn processReplacePath( | 4203 | fn processReplacePath( |
| ... | @@ -4235,7 +4217,7 @@ fn processSpawn(userdata: ?*anyopaque, options: process.SpawnOptions) process.Sp | ... | @@ -4235,7 +4217,7 @@ fn processSpawn(userdata: ?*anyopaque, options: process.SpawnOptions) process.Sp |
| 4235 | const spawned = try ev.spawn(options); | 4217 | const spawned = try ev.spawn(options); |
| 4236 | var cancel_region: CancelRegion = .initBlocked(); | 4218 | var cancel_region: CancelRegion = .initBlocked(); |
| 4237 | defer cancel_region.deinit(); | 4219 | defer cancel_region.deinit(); |
| 4238 | defer ev.close(spawned.err_fd); | 4220 | defer ev.closeAsync(spawned.err_fd); |
| 4239 | | 4221 | |
| 4240 | // 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`. |
| 4241 | var child_err: ForkBailError = undefined; | 4223 | var child_err: ForkBailError = undefined; |
| ... | @@ -4377,8 +4359,9 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4377,8 +4359,9 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4377 | | 4359 | |
| 4378 | if (pid_result == 0) { | 4360 | if (pid_result == 0) { |
| 4379 | 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`. |
| 4380 | var sync: CancelRegion.Sync = .{ .cancel_region = .initBlocked() }; | 4363 | var sync: CancelRegion.Sync = .{ .cancel_region = .initBlocked() }; |
| 4381 | const err = ev.setUpChild(&sync, .{ | 4364 | const err = setUpChild(&sync, .{ |
| 4382 | .stdin_pipe = stdin_pipe[0], | 4365 | .stdin_pipe = stdin_pipe[0], |
| 4383 | .stdout_pipe = stdout_pipe[1], | 4366 | .stdout_pipe = stdout_pipe[1], |
| 4384 | .stderr_pipe = stderr_pipe[1], | 4367 | .stderr_pipe = stderr_pipe[1], |
| ... | @@ -4389,7 +4372,7 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4389,7 +4372,7 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4389 | .PATH = PATH, | 4372 | .PATH = PATH, |
| 4390 | .spawn = options, | 4373 | .spawn = options, |
| 4391 | }); | 4374 | }); |
| 4392 | ev.writeAll(&sync.cancel_region, err_pipe[1], @ptrCast(&err)) catch {}; | 4375 | writeAllSync(&sync, err_pipe[1], @ptrCast(&err)) catch {}; |
| 4393 | 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; |
| 4394 | exit(1); | 4377 | exit(1); |
| 4395 | } | 4378 | } |
| ... | @@ -4397,13 +4380,13 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned | ... | @@ -4397,13 +4380,13 @@ fn spawn(ev: *Evented, options: process.SpawnOptions) process.SpawnError!Spawned |
| 4397 | const pid: pid_t = @intCast(pid_result); // We are the parent. | 4380 | const pid: pid_t = @intCast(pid_result); // We are the parent. |
| 4398 | 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 |
| 4399 | | 4382 | |
| 4400 | 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 |
| 4401 | | 4384 | |
| 4402 | if (options.stdin == .pipe) ev.close(stdin_pipe[0]); | 4385 | if (options.stdin == .pipe) ev.closeAsync(stdin_pipe[0]); |
| 4403 | if (options.stdout == .pipe) ev.close(stdout_pipe[1]); | 4386 | if (options.stdout == .pipe) ev.closeAsync(stdout_pipe[1]); |
| 4404 | if (options.stderr == .pipe) ev.close(stderr_pipe[1]); | 4387 | if (options.stderr == .pipe) ev.closeAsync(stderr_pipe[1]); |
| 4405 | | 4388 | |
| 4406 | if (prog_pipe[1] != -1) ev.close(prog_pipe[1]); | 4389 | if (prog_pipe[1] != -1) ev.closeAsync(prog_pipe[1]); |
| 4407 | | 4390 | |
| 4408 | 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 } }); |
| 4409 | | 4392 | |
| ... | @@ -4440,14 +4423,14 @@ pub fn pipe2(flags: linux.O) PipeError![2]fd_t { | ... | @@ -4440,14 +4423,14 @@ pub fn pipe2(flags: linux.O) PipeError![2]fd_t { |
| 4440 | } | 4423 | } |
| 4441 | } | 4424 | } |
| 4442 | fn destroyPipe(ev: *Evented, pipe: [2]fd_t) void { | 4425 | fn destroyPipe(ev: *Evented, pipe: [2]fd_t) void { |
| 4443 | if (pipe[0] != -1) ev.close(pipe[0]); | 4426 | if (pipe[0] != -1) ev.closeAsync(pipe[0]); |
| 4444 | if (pipe[0] != pipe[1]) ev.close(pipe[1]); | 4427 | if (pipe[0] != pipe[1]) ev.closeAsync(pipe[1]); |
| 4445 | } | 4428 | } |
| 4446 | | 4429 | |
| 4447 | /// Errors that can occur between fork() and execv() | 4430 | /// Errors that can occur between fork() and execv() |
| 4448 | const ForkBailError = process.SetCurrentDirError || ChdirError || | 4431 | const ForkBailError = process.SetCurrentDirError || ChdirError || |
| 4449 | process.SpawnError || process.ReplaceError; | 4432 | process.SpawnError || process.ReplaceError; |
| 4450 | fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | 4433 | fn setUpChild(sync: *CancelRegion.Sync, options: struct { |
| 4451 | stdin_pipe: fd_t, | 4434 | stdin_pipe: fd_t, |
| 4452 | stdout_pipe: fd_t, | 4435 | stdout_pipe: fd_t, |
| 4453 | stderr_pipe: fd_t, | 4436 | stderr_pipe: fd_t, |
| ... | @@ -4458,21 +4441,21 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4458,21 +4441,21 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4458 | PATH: []const u8, | 4441 | PATH: []const u8, |
| 4459 | spawn: process.SpawnOptions, | 4442 | spawn: process.SpawnOptions, |
| 4460 | }) ForkBailError { | 4443 | }) ForkBailError { |
| 4461 | try ev.setUpChildIo( | 4444 | try setUpChildIo( |
| 4462 | sync, | 4445 | sync, |
| 4463 | options.spawn.stdin, | 4446 | options.spawn.stdin, |
| 4464 | options.stdin_pipe, | 4447 | options.stdin_pipe, |
| 4465 | linux.STDIN_FILENO, | 4448 | linux.STDIN_FILENO, |
| 4466 | options.dev_null_fd, | 4449 | options.dev_null_fd, |
| 4467 | ); | 4450 | ); |
| 4468 | try ev.setUpChildIo( | 4451 | try setUpChildIo( |
| 4469 | sync, | 4452 | sync, |
| 4470 | options.spawn.stdout, | 4453 | options.spawn.stdout, |
| 4471 | options.stdout_pipe, | 4454 | options.stdout_pipe, |
| 4472 | linux.STDOUT_FILENO, | 4455 | linux.STDOUT_FILENO, |
| 4473 | options.dev_null_fd, | 4456 | options.dev_null_fd, |
| 4474 | ); | 4457 | ); |
| 4475 | try ev.setUpChildIo( | 4458 | try setUpChildIo( |
| 4476 | sync, | 4459 | sync, |
| 4477 | options.spawn.stderr, | 4460 | options.spawn.stderr, |
| 4478 | options.stderr_pipe, | 4461 | options.stderr_pipe, |
| ... | @@ -4482,17 +4465,17 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4482,17 +4465,17 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4482 | | 4465 | |
| 4483 | switch (options.spawn.cwd) { | 4466 | switch (options.spawn.cwd) { |
| 4484 | .inherit => {}, | 4467 | .inherit => {}, |
| 4485 | .dir => |cwd_dir| try ev.fchdir(sync, cwd_dir.handle), | 4468 | .dir => |cwd_dir| try fchdir(sync, cwd_dir.handle), |
| 4486 | .path => |cwd_path| { | 4469 | .path => |cwd_path| { |
| 4487 | var cwd_path_buffer: [PATH_MAX]u8 = undefined; | 4470 | var cwd_path_buffer: [PATH_MAX]u8 = undefined; |
| 4488 | const cwd_path_posix = try pathToPosix(cwd_path, &cwd_path_buffer); | 4471 | const cwd_path_posix = try pathToPosix(cwd_path, &cwd_path_buffer); |
| 4489 | try ev.chdir(sync, cwd_path_posix); | 4472 | try chdir(sync, cwd_path_posix); |
| 4490 | }, | 4473 | }, |
| 4491 | } | 4474 | } |
| 4492 | | 4475 | |
| 4493 | // Must happen after fchdir above, the cwd file descriptor might be | 4476 | // Must happen after fchdir above, the cwd file descriptor might be |
| 4494 | // equal to prog_fileno and be clobbered by this dup2 call. | 4477 | // equal to prog_fileno and be clobbered by this dup2 call. |
| 4495 | 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); |
| 4496 | | 4479 | |
| 4497 | if (options.spawn.gid) |gid| { | 4480 | if (options.spawn.gid) |gid| { |
| 4498 | switch (linux.errno(linux.setregid(gid, gid))) { | 4481 | switch (linux.errno(linux.setregid(gid, gid))) { |
| ... | @@ -4532,7 +4515,7 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4532,7 +4515,7 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4532 | } | 4515 | } |
| 4533 | } | 4516 | } |
| 4534 | | 4517 | |
| 4535 | return ev.execv( | 4518 | return execv( |
| 4536 | sync, | 4519 | sync, |
| 4537 | options.spawn.expand_arg0, | 4520 | options.spawn.expand_arg0, |
| 4538 | options.argv_buf.ptr[0].?, | 4521 | options.argv_buf.ptr[0].?, |
| ... | @@ -4543,7 +4526,6 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { | ... | @@ -4543,7 +4526,6 @@ fn setUpChild(ev: *Evented, sync: *CancelRegion.Sync, options: struct { |
| 4543 | } | 4526 | } |
| 4544 | | 4527 | |
| 4545 | fn setUpChildIo( | 4528 | fn setUpChildIo( |
| 4546 | ev: *Evented, | | |
| 4547 | sync: *CancelRegion.Sync, | 4529 | sync: *CancelRegion.Sync, |
| 4548 | stdio: process.SpawnOptions.StdIo, | 4530 | stdio: process.SpawnOptions.StdIo, |
| 4549 | pipe_fd: fd_t, | 4531 | pipe_fd: fd_t, |
| ... | @@ -4551,13 +4533,13 @@ fn setUpChildIo( | ... | @@ -4551,13 +4533,13 @@ fn setUpChildIo( |
| 4551 | dev_null_fd: fd_t, | 4533 | dev_null_fd: fd_t, |
| 4552 | ) !void { | 4534 | ) !void { |
| 4553 | switch (stdio) { | 4535 | switch (stdio) { |
| 4554 | .pipe => try ev.dup2(sync, pipe_fd, std_fileno), | 4536 | .pipe => try dup2(sync, pipe_fd, std_fileno), |
| 4555 | .close => _ = linux.close(std_fileno), | 4537 | .close => _ = linux.close(std_fileno), |
| 4556 | .inherit => {}, | 4538 | .inherit => {}, |
| 4557 | .ignore => try ev.dup2(sync, dev_null_fd, std_fileno), | 4539 | .ignore => try dup2(sync, dev_null_fd, std_fileno), |
| 4558 | .file => |file| { | 4540 | .file => |file| { |
| 4559 | 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"); |
| 4560 | try ev.dup2(sync, file.handle, std_fileno); | 4542 | try dup2(sync, file.handle, std_fileno); |
| 4561 | }, | 4543 | }, |
| 4562 | } | 4544 | } |
| 4563 | } | 4545 | } |
| ... | @@ -4566,13 +4548,12 @@ pub const DupError = error{ | ... | @@ -4566,13 +4548,12 @@ pub const DupError = error{ |
| 4566 | ProcessFdQuotaExceeded, | 4548 | ProcessFdQuotaExceeded, |
| 4567 | SystemResources, | 4549 | SystemResources, |
| 4568 | } || Io.UnexpectedError || Io.Cancelable; | 4550 | } || Io.UnexpectedError || Io.Cancelable; |
| 4569 | 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 { |
| 4570 | _ = ev; | | |
| 4571 | while (true) { | 4552 | while (true) { |
| 4572 | try sync.cancel_region.await(.nothing); | 4553 | try sync.cancel_region.await(.nothing); |
| 4573 | switch (linux.errno(linux.dup2(old_fd, new_fd))) { | 4554 | switch (linux.errno(linux.dup2(old_fd, new_fd))) { |
| 4574 | .SUCCESS => {}, | 4555 | .SUCCESS => {}, |
| 4575 | .BUSY, .INTR => continue, | 4556 | .BUSY, .INTR => {}, |
| 4576 | .INVAL => |err| return errnoBug(err), // invalid parameters | 4557 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 4577 | .BADF => |err| return errnoBug(err), // use after free | 4558 | .BADF => |err| return errnoBug(err), // use after free |
| 4578 | .MFILE => return error.ProcessFdQuotaExceeded, | 4559 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -4583,7 +4564,6 @@ pub fn dup2(ev: *Evented, sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) | ... | @@ -4583,7 +4564,6 @@ pub fn dup2(ev: *Evented, sync: *CancelRegion.Sync, old_fd: fd_t, new_fd: fd_t) |
| 4583 | } | 4564 | } |
| 4584 | | 4565 | |
| 4585 | fn execv( | 4566 | fn execv( |
| 4586 | ev: *Evented, | | |
| 4587 | sync: *CancelRegion.Sync, | 4567 | sync: *CancelRegion.Sync, |
| 4588 | arg0_expand: process.ArgExpansion, | 4568 | arg0_expand: process.ArgExpansion, |
| 4589 | file: [*:0]const u8, | 4569 | file: [*:0]const u8, |
| ... | @@ -4592,7 +4572,8 @@ fn execv( | ... | @@ -4592,7 +4572,8 @@ fn execv( |
| 4592 | PATH: []const u8, | 4572 | PATH: []const u8, |
| 4593 | ) process.ReplaceError { | 4573 | ) process.ReplaceError { |
| 4594 | const file_slice = std.mem.sliceTo(file, 0); | 4574 | const file_slice = std.mem.sliceTo(file, 0); |
| 4595 | 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); |
| 4596 | | 4577 | |
| 4597 | // 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 |
| 4598 | // directly to the operating system in posixExecvPath. | 4579 | // directly to the operating system in posixExecvPath. |
| ... | @@ -4620,7 +4601,7 @@ fn execv( | ... | @@ -4620,7 +4601,7 @@ fn execv( |
| 4620 | .expand => child_argv[0] = full_path, | 4601 | .expand => child_argv[0] = full_path, |
| 4621 | .no_expand => {}, | 4602 | .no_expand => {}, |
| 4622 | } | 4603 | } |
| 4623 | err = ev.execvPath(sync, full_path, child_argv, env_block); | 4604 | err = execvPath(sync, full_path, child_argv, env_block); |
| 4624 | switch (err) { | 4605 | switch (err) { |
| 4625 | error.AccessDenied => seen_eacces = true, | 4606 | error.AccessDenied => seen_eacces = true, |
| 4626 | error.FileNotFound, error.NotDir => {}, | 4607 | error.FileNotFound, error.NotDir => {}, |
| ... | @@ -4632,13 +4613,11 @@ fn execv( | ... | @@ -4632,13 +4613,11 @@ fn execv( |
| 4632 | } | 4613 | } |
| 4633 | /// This function ignores PATH environment variable. | 4614 | /// This function ignores PATH environment variable. |
| 4634 | pub fn execvPath( | 4615 | pub fn execvPath( |
| 4635 | ev: *Evented, | | |
| 4636 | sync: *CancelRegion.Sync, | 4616 | sync: *CancelRegion.Sync, |
| 4637 | path: [*:0]const u8, | 4617 | path: [*:0]const u8, |
| 4638 | child_argv: [*:null]const ?[*:0]const u8, | 4618 | child_argv: [*:null]const ?[*:0]const u8, |
| 4639 | env_block: process.Environ.PosixBlock, | 4619 | env_block: process.Environ.PosixBlock, |
| 4640 | ) process.ReplaceError { | 4620 | ) process.ReplaceError { |
| 4641 | _ = ev; | | |
| 4642 | try sync.cancel_region.await(.nothing); | 4621 | try sync.cancel_region.await(.nothing); |
| 4643 | 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))) { |
| 4644 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. | 4623 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. |
| ... | @@ -4709,7 +4688,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr | ... | @@ -4709,7 +4688,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr |
| 4709 | child.resource_usage_statistics.rusage = rusage; | 4688 | child.resource_usage_statistics.rusage = rusage; |
| 4710 | break; | 4689 | break; |
| 4711 | }, | 4690 | }, |
| 4712 | .INTR, .CANCELED => continue, | 4691 | .INTR, .CANCELED => {}, |
| 4713 | .CHILD => |err| return errnoBug(err), // Double-free. | 4692 | .CHILD => |err| return errnoBug(err), // Double-free. |
| 4714 | else => |err| return unexpectedErrno(err), | 4693 | else => |err| return unexpectedErrno(err), |
| 4715 | } | 4694 | } |
| ... | @@ -4724,7 +4703,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr | ... | @@ -4724,7 +4703,7 @@ fn childWait(userdata: ?*anyopaque, child: *process.Child) process.Child.WaitErr |
| 4724 | _, .CONTINUED => .{ .unknown = status }, | 4703 | _, .CONTINUED => .{ .unknown = status }, |
| 4725 | }; | 4704 | }; |
| 4726 | }, | 4705 | }, |
| 4727 | .INTR, .CANCELED => continue, | 4706 | .INTR, .CANCELED => {}, |
| 4728 | .CHILD => |err| return errnoBug(err), // Double-free. | 4707 | .CHILD => |err| return errnoBug(err), // Double-free. |
| 4729 | else => |err| return unexpectedErrno(err), | 4708 | else => |err| return unexpectedErrno(err), |
| 4730 | } | 4709 | } |
| ... | @@ -4741,7 +4720,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4741,7 +4720,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4741 | const pid = child.id.?; | 4720 | const pid = child.id.?; |
| 4742 | while (true) switch (linux.errno(linux.kill(pid, .TERM))) { | 4721 | while (true) switch (linux.errno(linux.kill(pid, .TERM))) { |
| 4743 | .SUCCESS => break, | 4722 | .SUCCESS => break, |
| 4744 | .INTR => continue, | 4723 | .INTR => {}, |
| 4745 | .PERM => return, | 4724 | .PERM => return, |
| 4746 | .INVAL => |err| return errnoBug(err) catch {}, | 4725 | .INVAL => |err| return errnoBug(err) catch {}, |
| 4747 | .SRCH => |err| return errnoBug(err) catch {}, | 4726 | .SRCH => |err| return errnoBug(err) catch {}, |
| ... | @@ -4773,7 +4752,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4773,7 +4752,7 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4773 | ev.yield(null, .nothing); | 4752 | ev.yield(null, .nothing); |
| 4774 | switch (maybe_sync.cancel_region.errno()) { | 4753 | switch (maybe_sync.cancel_region.errno()) { |
| 4775 | .SUCCESS => return, | 4754 | .SUCCESS => return, |
| 4776 | .INTR, .CANCELED => continue, | 4755 | .INTR, .CANCELED => {}, |
| 4777 | .CHILD => |err| return errnoBug(err) catch {}, // Double-free. | 4756 | .CHILD => |err| return errnoBug(err) catch {}, // Double-free. |
| 4778 | else => |err| return unexpectedErrno(err) catch {}, | 4757 | else => |err| return unexpectedErrno(err) catch {}, |
| 4779 | } | 4758 | } |
| ... | @@ -4782,15 +4761,15 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -4782,15 +4761,15 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 4782 | | 4761 | |
| 4783 | fn childCleanup(ev: *Evented, child: *process.Child) void { | 4762 | fn childCleanup(ev: *Evented, child: *process.Child) void { |
| 4784 | if (child.stdin) |*stdin| { | 4763 | if (child.stdin) |*stdin| { |
| 4785 | ev.close(stdin.handle); | 4764 | ev.closeAsync(stdin.handle); |
| 4786 | child.stdin = null; | 4765 | child.stdin = null; |
| 4787 | } | 4766 | } |
| 4788 | if (child.stdout) |*stdout| { | 4767 | if (child.stdout) |*stdout| { |
| 4789 | ev.close(stdout.handle); | 4768 | ev.closeAsync(stdout.handle); |
| 4790 | child.stdout = null; | 4769 | child.stdout = null; |
| 4791 | } | 4770 | } |
| 4792 | if (child.stderr) |*stderr| { | 4771 | if (child.stderr) |*stderr| { |
| 4793 | ev.close(stderr.handle); | 4772 | ev.closeAsync(stderr.handle); |
| 4794 | child.stderr = null; | 4773 | child.stderr = null; |
| 4795 | } | 4774 | } |
| 4796 | child.id = null; | 4775 | child.id = null; |
| ... | @@ -4896,14 +4875,10 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { | ... | @@ -4896,14 +4875,10 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { |
| 4896 | .resv = 0, | 4875 | .resv = 0, |
| 4897 | }; | 4876 | }; |
| 4898 | ev.yield(null, .nothing); | 4877 | ev.yield(null, .nothing); |
| 4899 | switch (cancel_region.errno()) { | 4878 | // Handles SUCCESS as well as clock not available and unexpected |
| 4900 | // Handles SUCCESS as well as clock not available and unexpected | 4879 | // errors. The user had a chance to check clock resolution before |
| 4901 | // errors. The user had a chance to check clock resolution before | 4880 | // getting here, which would have reported 0, making this a legal |
| 4902 | // getting here, which would have reported 0, making this a legal | 4881 | // amount of time to sleep. |
| 4903 | // amount of time to sleep. | | |
| 4904 | else => return, | | |
| 4905 | .INTR, .CANCELED => return error.Canceled, | | |
| 4906 | } | | |
| 4907 | } | 4882 | } |
| 4908 | | 4883 | |
| 4909 | fn random(userdata: ?*anyopaque, buffer: []u8) void { | 4884 | fn random(userdata: ?*anyopaque, buffer: []u8) void { |
| ... | @@ -4980,7 +4955,7 @@ fn netBindIp( | ... | @@ -4980,7 +4955,7 @@ fn netBindIp( |
| 4980 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; | 4955 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; |
| 4981 | defer maybe_sync.deinit(ev); | 4956 | defer maybe_sync.deinit(ev); |
| 4982 | 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); |
| 4983 | errdefer ev.close(socket_fd); | 4958 | errdefer ev.closeAsync(socket_fd); |
| 4984 | var storage: PosixAddress = undefined; | 4959 | var storage: PosixAddress = undefined; |
| 4985 | var addr_len = addressToPosix(address, &storage); | 4960 | var addr_len = addressToPosix(address, &storage); |
| 4986 | 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); |
| ... | @@ -5147,23 +5122,19 @@ fn netReceive( | ... | @@ -5147,23 +5122,19 @@ fn netReceive( |
| 5147 | .data = data, | 5122 | .data = data, |
| 5148 | .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, |
| 5149 | .flags = .{ | 5124 | .flags = .{ |
| 5150 | .eor = (msg.flags & linux.MSG.EOR) != 0, | 5125 | .eor = msg.flags & linux.MSG.EOR != 0, |
| 5151 | .trunc = (msg.flags & linux.MSG.TRUNC) != 0, | 5126 | .trunc = msg.flags & linux.MSG.TRUNC != 0, |
| 5152 | .ctrunc = (msg.flags & linux.MSG.CTRUNC) != 0, | 5127 | .ctrunc = msg.flags & linux.MSG.CTRUNC != 0, |
| 5153 | .oob = (msg.flags & linux.MSG.OOB) != 0, | 5128 | .oob = msg.flags & linux.MSG.OOB != 0, |
| 5154 | .errqueue = if (@hasDecl(linux.MSG, "ERRQUEUE")) (msg.flags & linux.MSG.ERRQUEUE) != 0 else false, | 5129 | .errqueue = msg.flags & linux.MSG.ERRQUEUE != 0, |
| 5155 | }, | 5130 | }, |
| 5156 | }; | 5131 | }; |
| 5157 | message_i += 1; | 5132 | message_i += 1; |
| 5158 | continue; | 5133 | continue; |
| 5159 | }, | 5134 | }, |
| 5160 | .AGAIN => unreachable, | 5135 | .AGAIN => unreachable, |
| 5161 | .INTR, .CANCELED => { | 5136 | .INTR, .CANCELED => if (deadline) |d| if (now(ev, d.clock).nanoseconds >= d.raw.nanoseconds) |
| 5162 | if (deadline) |d| { | 5137 | return .{ error.Timeout, message_i }, |
| 5163 | if (now(ev, d.clock).nanoseconds >= d.raw.nanoseconds) return .{ error.Timeout, message_i }; | | |
| 5164 | } | | |
| 5165 | continue; | | |
| 5166 | }, | | |
| 5167 | | 5138 | |
| 5168 | .BADF => |err| return .{ errnoBug(err), message_i }, | 5139 | .BADF => |err| return .{ errnoBug(err), message_i }, |
| 5169 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, | 5140 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, |
| ... | @@ -5266,7 +5237,7 @@ fn netShutdown( | ... | @@ -5266,7 +5237,7 @@ fn netShutdown( |
| 5266 | ev.yield(null, .nothing); | 5237 | ev.yield(null, .nothing); |
| 5267 | switch (cancel_region.errno()) { | 5238 | switch (cancel_region.errno()) { |
| 5268 | .SUCCESS => return, | 5239 | .SUCCESS => return, |
| 5269 | .INTR, .CANCELED => continue, | 5240 | .INTR, .CANCELED => {}, |
| 5270 | .BADF, .NOTSOCK, .INVAL => |err| return errnoBug(err), | 5241 | .BADF, .NOTSOCK, .INVAL => |err| return errnoBug(err), |
| 5271 | .NOTCONN => return error.SocketUnconnected, | 5242 | .NOTCONN => return error.SocketUnconnected, |
| 5272 | .NOBUFS => return error.SystemResources, | 5243 | .NOBUFS => return error.SystemResources, |
| ... | @@ -5336,7 +5307,7 @@ fn bind( | ... | @@ -5336,7 +5307,7 @@ fn bind( |
| 5336 | ev.yield(null, .nothing); | 5307 | ev.yield(null, .nothing); |
| 5337 | switch (cancel_region.errno()) { | 5308 | switch (cancel_region.errno()) { |
| 5338 | .SUCCESS => return, | 5309 | .SUCCESS => return, |
| 5339 | .INTR, .CANCELED => continue, | 5310 | .INTR, .CANCELED => {}, |
| 5340 | .ADDRINUSE => return error.AddressInUse, | 5311 | .ADDRINUSE => return error.AddressInUse, |
| 5341 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5312 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5342 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5313 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| ... | @@ -5350,13 +5321,12 @@ fn bind( | ... | @@ -5350,13 +5321,12 @@ fn bind( |
| 5350 | } | 5321 | } |
| 5351 | } | 5322 | } |
| 5352 | | 5323 | |
| 5353 | 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 { |
| 5354 | _ = ev; | | |
| 5355 | while (true) { | 5325 | while (true) { |
| 5356 | try sync.cancel_region.await(.nothing); | 5326 | try sync.cancel_region.await(.nothing); |
| 5357 | switch (linux.errno(linux.chdir(path))) { | 5327 | switch (linux.errno(linux.chdir(path))) { |
| 5358 | .SUCCESS => return, | 5328 | .SUCCESS => return, |
| 5359 | .INTR => continue, | 5329 | .INTR => {}, |
| 5360 | .ACCES => return error.AccessDenied, | 5330 | .ACCES => return error.AccessDenied, |
| 5361 | .IO => return error.FileSystem, | 5331 | .IO => return error.FileSystem, |
| 5362 | .LOOP => return error.SymLinkLoop, | 5332 | .LOOP => return error.SymLinkLoop, |
| ... | @@ -5372,6 +5342,36 @@ fn chdir(ev: *Evented, sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError | ... | @@ -5372,6 +5342,36 @@ fn chdir(ev: *Evented, sync: *CancelRegion.Sync, path: [*:0]const u8) ChdirError |
| 5372 | } | 5342 | } |
| 5373 | | 5343 | |
| 5374 | 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 { |
| 5375 | _ = ev; | 5375 | _ = ev; |
| 5376 | const thread: *Thread = .current(); | 5376 | const thread: *Thread = .current(); |
| 5377 | thread.enqueue().* = .{ | 5377 | thread.enqueue().* = .{ |
| ... | @@ -5392,14 +5392,13 @@ fn close(ev: *Evented, fd: fd_t) void { | ... | @@ -5392,14 +5392,13 @@ fn close(ev: *Evented, fd: fd_t) void { |
| 5392 | }; | 5392 | }; |
| 5393 | } | 5393 | } |
| 5394 | | 5394 | |
| 5395 | 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 { |
| 5396 | _ = ev; | | |
| 5397 | if (dir == linux.AT.FDCWD) return; | 5396 | if (dir == linux.AT.FDCWD) return; |
| 5398 | while (true) { | 5397 | while (true) { |
| 5399 | try sync.cancel_region.await(.nothing); | 5398 | try sync.cancel_region.await(.nothing); |
| 5400 | switch (linux.errno(linux.fchdir(dir))) { | 5399 | switch (linux.errno(linux.fchdir(dir))) { |
| 5401 | .SUCCESS => return, | 5400 | .SUCCESS => return, |
| 5402 | .INTR => continue, | 5401 | .INTR => {}, |
| 5403 | .ACCES => return error.AccessDenied, | 5402 | .ACCES => return error.AccessDenied, |
| 5404 | .NOTDIR => return error.NotDir, | 5403 | .NOTDIR => return error.NotDir, |
| 5405 | .IO => return error.FileSystem, | 5404 | .IO => return error.FileSystem, |
| ... | @@ -5422,7 +5421,7 @@ fn fchmodat( | ... | @@ -5422,7 +5421,7 @@ fn fchmodat( |
| 5422 | try sync.cancel_region.await(.nothing); | 5421 | try sync.cancel_region.await(.nothing); |
| 5423 | switch (linux.errno(linux.fchmodat2(dir, path, mode, flags))) { | 5422 | switch (linux.errno(linux.fchmodat2(dir, path, mode, flags))) { |
| 5424 | .SUCCESS => return, | 5423 | .SUCCESS => return, |
| 5425 | .INTR => continue, | 5424 | .INTR => {}, |
| 5426 | .BADF => |err| return errnoBug(err), | 5425 | .BADF => |err| return errnoBug(err), |
| 5427 | .FAULT => |err| return errnoBug(err), | 5426 | .FAULT => |err| return errnoBug(err), |
| 5428 | .INVAL => |err| return errnoBug(err), | 5427 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -5454,7 +5453,7 @@ fn fchownat( | ... | @@ -5454,7 +5453,7 @@ fn fchownat( |
| 5454 | try sync.cancel_region.await(.nothing); | 5453 | try sync.cancel_region.await(.nothing); |
| 5455 | switch (linux.errno(linux.fchownat(dir, path, owner, group, flags))) { | 5454 | switch (linux.errno(linux.fchownat(dir, path, owner, group, flags))) { |
| 5456 | .SUCCESS => return, | 5455 | .SUCCESS => return, |
| 5457 | .INTR => continue, | 5456 | .INTR => {}, |
| 5458 | .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` |
| 5459 | .FAULT => |err| return errnoBug(err), | 5458 | .FAULT => |err| return errnoBug(err), |
| 5460 | .INVAL => |err| return errnoBug(err), | 5459 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -5486,7 +5485,7 @@ fn flock( | ... | @@ -5486,7 +5485,7 @@ fn flock( |
| 5486 | .exclusive => LOCK.EX, | 5485 | .exclusive => LOCK.EX, |
| 5487 | })))) { | 5486 | })))) { |
| 5488 | .SUCCESS => return, | 5487 | .SUCCESS => return, |
| 5489 | .INTR => continue, | 5488 | .INTR => {}, |
| 5490 | .BADF => |err| return errnoBug(err), | 5489 | .BADF => |err| return errnoBug(err), |
| 5491 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5490 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 5492 | .NOLCK => return error.SystemResources, | 5491 | .NOLCK => return error.SystemResources, |
| ... | @@ -5536,7 +5535,7 @@ fn getsockname( | ... | @@ -5536,7 +5535,7 @@ fn getsockname( |
| 5536 | try sync.cancel_region.await(.nothing); | 5535 | try sync.cancel_region.await(.nothing); |
| 5537 | switch (linux.errno(linux.getsockname(socket_fd, addr, addr_len))) { | 5536 | switch (linux.errno(linux.getsockname(socket_fd, addr, addr_len))) { |
| 5538 | .SUCCESS => return, | 5537 | .SUCCESS => return, |
| 5539 | .INTR => continue, | 5538 | .INTR => {}, |
| 5540 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5539 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5541 | .FAULT => |err| return errnoBug(err), | 5540 | .FAULT => |err| return errnoBug(err), |
| 5542 | .INVAL => |err| return errnoBug(err), // invalid parameters | 5541 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| ... | @@ -5577,7 +5576,7 @@ fn linkat( | ... | @@ -5577,7 +5576,7 @@ fn linkat( |
| 5577 | ev.yield(null, .nothing); | 5576 | ev.yield(null, .nothing); |
| 5578 | switch (cancel_region.errno()) { | 5577 | switch (cancel_region.errno()) { |
| 5579 | .SUCCESS => return, | 5578 | .SUCCESS => return, |
| 5580 | .INTR, .CANCELED => continue, | 5579 | .INTR, .CANCELED => {}, |
| 5581 | .ACCES => return error.AccessDenied, | 5580 | .ACCES => return error.AccessDenied, |
| 5582 | .DQUOT => return error.DiskQuota, | 5581 | .DQUOT => return error.DiskQuota, |
| 5583 | .EXIST => return error.PathAlreadyExists, | 5582 | .EXIST => return error.PathAlreadyExists, |
| ... | @@ -5617,7 +5616,7 @@ fn lseek( | ... | @@ -5617,7 +5616,7 @@ fn lseek( |
| 5617 | 8 => linux.lseek(fd, @bitCast(offset), whence), | 5616 | 8 => linux.lseek(fd, @bitCast(offset), whence), |
| 5618 | })) { | 5617 | })) { |
| 5619 | .SUCCESS => return, | 5618 | .SUCCESS => return, |
| 5620 | .INTR => continue, | 5619 | .INTR => {}, |
| 5621 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5620 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5622 | .INVAL => return error.Unseekable, | 5621 | .INVAL => return error.Unseekable, |
| 5623 | .OVERFLOW => return error.Unseekable, | 5622 | .OVERFLOW => return error.Unseekable, |
| ... | @@ -5660,7 +5659,7 @@ fn openat( | ... | @@ -5660,7 +5659,7 @@ fn openat( |
| 5660 | const completion = cancel_region.completion(); | 5659 | const completion = cancel_region.completion(); |
| 5661 | switch (completion.errno()) { | 5660 | switch (completion.errno()) { |
| 5662 | .SUCCESS => return completion.result, | 5661 | .SUCCESS => return completion.result, |
| 5663 | .INTR, .CANCELED => continue, | 5662 | .INTR, .CANCELED => {}, |
| 5664 | .FAULT => |err| return errnoBug(err), | 5663 | .FAULT => |err| return errnoBug(err), |
| 5665 | .INVAL => return error.BadPathName, | 5664 | .INVAL => return error.BadPathName, |
| 5666 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5665 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| ... | @@ -5722,7 +5721,7 @@ fn preadv( | ... | @@ -5722,7 +5721,7 @@ fn preadv( |
| 5722 | const completion = cancel_region.completion(); | 5721 | const completion = cancel_region.completion(); |
| 5723 | switch (completion.errno()) { | 5722 | switch (completion.errno()) { |
| 5724 | .SUCCESS => return @as(u32, @bitCast(completion.result)), | 5723 | .SUCCESS => return @as(u32, @bitCast(completion.result)), |
| 5725 | .INTR, .CANCELED => continue, | 5724 | .INTR, .CANCELED => {}, |
| 5726 | .INVAL => |err| return errnoBug(err), | 5725 | .INVAL => |err| return errnoBug(err), |
| 5727 | .FAULT => |err| return errnoBug(err), | 5726 | .FAULT => |err| return errnoBug(err), |
| 5728 | .AGAIN => return error.WouldBlock, | 5727 | .AGAIN => return error.WouldBlock, |
| ... | @@ -5769,7 +5768,7 @@ fn pwritev( | ... | @@ -5769,7 +5768,7 @@ fn pwritev( |
| 5769 | const completion = cancel_region.completion(); | 5768 | const completion = cancel_region.completion(); |
| 5770 | switch (completion.errno()) { | 5769 | switch (completion.errno()) { |
| 5771 | .SUCCESS => return @as(u32, @bitCast(completion.result)), | 5770 | .SUCCESS => return @as(u32, @bitCast(completion.result)), |
| 5772 | .INTR, .CANCELED => continue, | 5771 | .INTR, .CANCELED => {}, |
| 5773 | .INVAL => |err| return errnoBug(err), | 5772 | .INVAL => |err| return errnoBug(err), |
| 5774 | .FAULT => |err| return errnoBug(err), | 5773 | .FAULT => |err| return errnoBug(err), |
| 5775 | .AGAIN => return error.WouldBlock, | 5774 | .AGAIN => return error.WouldBlock, |
| ... | @@ -5819,7 +5818,7 @@ fn realPath( | ... | @@ -5819,7 +5818,7 @@ fn realPath( |
| 5819 | 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); |
| 5820 | switch (linux.errno(rc)) { | 5819 | switch (linux.errno(rc)) { |
| 5821 | .SUCCESS => return rc, | 5820 | .SUCCESS => return rc, |
| 5822 | .INTR => continue, | 5821 | .INTR => {}, |
| 5823 | .ACCES => return error.AccessDenied, | 5822 | .ACCES => return error.AccessDenied, |
| 5824 | .FAULT => |err| return errnoBug(err), | 5823 | .FAULT => |err| return errnoBug(err), |
| 5825 | .IO => return error.FileSystem, | 5824 | .IO => return error.FileSystem, |
| ... | @@ -5864,7 +5863,7 @@ fn renameat( | ... | @@ -5864,7 +5863,7 @@ fn renameat( |
| 5864 | ev.yield(null, .nothing); | 5863 | ev.yield(null, .nothing); |
| 5865 | switch (cancel_region.errno()) { | 5864 | switch (cancel_region.errno()) { |
| 5866 | .SUCCESS => return, | 5865 | .SUCCESS => return, |
| 5867 | .INTR, .CANCELED => continue, | 5866 | .INTR, .CANCELED => {}, |
| 5868 | .ACCES => return error.AccessDenied, | 5867 | .ACCES => return error.AccessDenied, |
| 5869 | .PERM => return error.PermissionDenied, | 5868 | .PERM => return error.PermissionDenied, |
| 5870 | .BUSY => return error.FileBusy, | 5869 | .BUSY => return error.FileBusy, |
| ... | @@ -5931,7 +5930,7 @@ fn setsockopt( | ... | @@ -5931,7 +5930,7 @@ fn setsockopt( |
| 5931 | ev.yield(null, .nothing); | 5930 | ev.yield(null, .nothing); |
| 5932 | switch (cancel_region.errno()) { | 5931 | switch (cancel_region.errno()) { |
| 5933 | .SUCCESS => return, | 5932 | .SUCCESS => return, |
| 5934 | .INTR, .CANCELED => continue, | 5933 | .INTR, .CANCELED => {}, |
| 5935 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 5934 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 5936 | .NOTSOCK => |err| return errnoBug(err), | 5935 | .NOTSOCK => |err| return errnoBug(err), |
| 5937 | .INVAL => |err| return errnoBug(err), | 5936 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -5982,7 +5981,7 @@ fn socket( | ... | @@ -5982,7 +5981,7 @@ fn socket( |
| 5982 | const completion = cancel_region.completion(); | 5981 | const completion = cancel_region.completion(); |
| 5983 | switch (completion.errno()) { | 5982 | switch (completion.errno()) { |
| 5984 | .SUCCESS => break completion.result, | 5983 | .SUCCESS => break completion.result, |
| 5985 | .INTR, .CANCELED => continue, | 5984 | .INTR, .CANCELED => {}, |
| 5986 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, | 5985 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 5987 | .INVAL => return error.ProtocolUnsupportedBySystem, | 5986 | .INVAL => return error.ProtocolUnsupportedBySystem, |
| 5988 | .MFILE => return error.ProcessFdQuotaExceeded, | 5987 | .MFILE => return error.ProcessFdQuotaExceeded, |
| ... | @@ -5994,7 +5993,7 @@ fn socket( | ... | @@ -5994,7 +5993,7 @@ fn socket( |
| 5994 | else => |err| return unexpectedErrno(err), | 5993 | else => |err| return unexpectedErrno(err), |
| 5995 | } | 5994 | } |
| 5996 | }; | 5995 | }; |
| 5997 | errdefer ev.close(socket_fd); | 5996 | errdefer ev.closeAsync(socket_fd); |
| 5998 | | 5997 | |
| 5999 | if (options.ip6_only) { | 5998 | if (options.ip6_only) { |
| 6000 | if (linux.IPV6 == void) return error.OptionUnsupported; | 5999 | if (linux.IPV6 == void) return error.OptionUnsupported; |
| ... | @@ -6044,7 +6043,7 @@ fn statx( | ... | @@ -6044,7 +6043,7 @@ fn statx( |
| 6044 | ev.yield(null, .nothing); | 6043 | ev.yield(null, .nothing); |
| 6045 | switch (cancel_region.errno()) { | 6044 | switch (cancel_region.errno()) { |
| 6046 | .SUCCESS => return statFromLinux(&statx_buf), | 6045 | .SUCCESS => return statFromLinux(&statx_buf), |
| 6047 | .INTR, .CANCELED => continue, | 6046 | .INTR, .CANCELED => {}, |
| 6048 | .ACCES => return error.AccessDenied, | 6047 | .ACCES => return error.AccessDenied, |
| 6049 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | 6048 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. |
| 6050 | .FAULT => |err| return errnoBug(err), | 6049 | .FAULT => |err| return errnoBug(err), |
| ... | @@ -6083,7 +6082,7 @@ fn utimensat( | ... | @@ -6083,7 +6082,7 @@ fn utimensat( |
| 6083 | try sync.cancel_region.await(.nothing); | 6082 | try sync.cancel_region.await(.nothing); |
| 6084 | switch (linux.errno(linux.utimensat(dir, path, times, flags))) { | 6083 | switch (linux.errno(linux.utimensat(dir, path, times, flags))) { |
| 6085 | .SUCCESS => return, | 6084 | .SUCCESS => return, |
| 6086 | .INTR => continue, | 6085 | .INTR => {}, |
| 6087 | .BADF => |err| return errnoBug(err), // always a race condition | 6086 | .BADF => |err| return errnoBug(err), // always a race condition |
| 6088 | .FAULT => |err| return errnoBug(err), | 6087 | .FAULT => |err| return errnoBug(err), |
| 6089 | .INVAL => |err| return errnoBug(err), | 6088 | .INVAL => |err| return errnoBug(err), |
| ... | @@ -6095,19 +6094,33 @@ fn utimensat( | ... | @@ -6095,19 +6094,33 @@ fn utimensat( |
| 6095 | } | 6094 | } |
| 6096 | } | 6095 | } |
| 6097 | | 6096 | |
| 6098 | fn writeAll( | 6097 | fn writeAllSync(sync: *CancelRegion.Sync, fd: fd_t, buffer: []const u8) File.Writer.Error!void { |
| 6099 | ev: *Evented, | | |
| 6100 | cancel_region: *CancelRegion, | | |
| 6101 | fd: fd_t, | | |
| 6102 | buffer: []const u8, | | |
| 6103 | ) (File.Writer.Error || error{EndOfStream})!void { | | |
| 6104 | var index: usize = 0; | 6098 | var index: usize = 0; |
| 6105 | while (buffer.len - index != 0) { | 6099 | while (buffer.len - index != 0) index += try writeSync(sync, fd, buffer[index..]); |
| 6106 | const len = try ev.pwritev(cancel_region, fd, &.{ | 6100 | } |
| 6107 | .{ .base = buffer[index..].ptr, .len = buffer.len - index }, | 6101 | |
| 6108 | }, null); | 6102 | fn writeSync(sync: *CancelRegion.Sync, fd: fd_t, buffer: []const u8) File.Writer.Error!usize { |
| 6109 | if (len == 0) return error.EndOfStream; | 6103 | while (true) { |
| 6110 | 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 | } |
| 6111 | } | 6124 | } |
| 6112 | } | 6125 | } |
| 6113 | | 6126 | |