| ... | ... | @@ -168,80 +168,28 @@ pub fn io(t: *Threaded) Io { |
| 168 | 168 | .conditionWaitUncancelable = conditionWaitUncancelable, |
| 169 | 169 | .conditionWake = conditionWake, |
| 170 | 170 | |
| 171 | | .dirMake = switch (native_os) { |
| 172 | | .windows => dirMakeWindows, |
| 173 | | .wasi => dirMakeWasi, |
| 174 | | else => dirMakePosix, |
| 175 | | }, |
| 176 | | .dirMakePath = switch (native_os) { |
| 177 | | .windows => dirMakePathWindows, |
| 178 | | else => dirMakePathPosix, |
| 179 | | }, |
| 180 | | .dirMakeOpenPath = switch (native_os) { |
| 181 | | .windows => dirMakeOpenPathWindows, |
| 182 | | .wasi => dirMakeOpenPathWasi, |
| 183 | | else => dirMakeOpenPathPosix, |
| 184 | | }, |
| 171 | .dirMake = dirMake, |
| 172 | .dirMakePath = dirMakePath, |
| 173 | .dirMakeOpenPath = dirMakeOpenPath, |
| 185 | 174 | .dirStat = dirStat, |
| 186 | | .dirStatPath = switch (native_os) { |
| 187 | | .linux => dirStatPathLinux, |
| 188 | | .windows => dirStatPathWindows, |
| 189 | | .wasi => dirStatPathWasi, |
| 190 | | else => dirStatPathPosix, |
| 191 | | }, |
| 192 | | .fileStat = switch (native_os) { |
| 193 | | .linux => fileStatLinux, |
| 194 | | .windows => fileStatWindows, |
| 195 | | .wasi => fileStatWasi, |
| 196 | | else => fileStatPosix, |
| 197 | | }, |
| 198 | | .dirAccess = switch (native_os) { |
| 199 | | .windows => dirAccessWindows, |
| 200 | | .wasi => dirAccessWasi, |
| 201 | | else => dirAccessPosix, |
| 202 | | }, |
| 203 | | .dirCreateFile = switch (native_os) { |
| 204 | | .windows => dirCreateFileWindows, |
| 205 | | .wasi => dirCreateFileWasi, |
| 206 | | else => dirCreateFilePosix, |
| 207 | | }, |
| 208 | | .dirOpenFile = switch (native_os) { |
| 209 | | .windows => dirOpenFileWindows, |
| 210 | | .wasi => dirOpenFileWasi, |
| 211 | | else => dirOpenFilePosix, |
| 212 | | }, |
| 213 | | .dirOpenDir = switch (native_os) { |
| 214 | | .wasi => dirOpenDirWasi, |
| 215 | | .haiku => dirOpenDirHaiku, |
| 216 | | else => dirOpenDirPosix, |
| 217 | | }, |
| 175 | .dirStatPath = dirStatPath, |
| 176 | .fileStat = fileStat, |
| 177 | .dirAccess = dirAccess, |
| 178 | .dirCreateFile = dirCreateFile, |
| 179 | .dirOpenFile = dirOpenFile, |
| 180 | .dirOpenDir = dirOpenDir, |
| 218 | 181 | .dirClose = dirClose, |
| 219 | 182 | .fileClose = fileClose, |
| 220 | 183 | .fileWriteStreaming = fileWriteStreaming, |
| 221 | 184 | .fileWritePositional = fileWritePositional, |
| 222 | | .fileReadStreaming = switch (native_os) { |
| 223 | | .windows => fileReadStreamingWindows, |
| 224 | | else => fileReadStreamingPosix, |
| 225 | | }, |
| 226 | | .fileReadPositional = switch (native_os) { |
| 227 | | .windows => fileReadPositionalWindows, |
| 228 | | else => fileReadPositionalPosix, |
| 229 | | }, |
| 185 | .fileReadStreaming = fileReadStreaming, |
| 186 | .fileReadPositional = fileReadPositional, |
| 230 | 187 | .fileSeekBy = fileSeekBy, |
| 231 | 188 | .fileSeekTo = fileSeekTo, |
| 232 | 189 | .openSelfExe = openSelfExe, |
| 233 | 190 | |
| 234 | | .now = switch (native_os) { |
| 235 | | .windows => nowWindows, |
| 236 | | .wasi => nowWasi, |
| 237 | | else => nowPosix, |
| 238 | | }, |
| 239 | | .sleep = switch (native_os) { |
| 240 | | .windows => sleepWindows, |
| 241 | | .wasi => sleepWasi, |
| 242 | | .linux => sleepLinux, |
| 243 | | else => sleepPosix, |
| 244 | | }, |
| 191 | .now = now, |
| 192 | .sleep = sleep, |
| 245 | 193 | |
| 246 | 194 | .netListenIp = switch (native_os) { |
| 247 | 195 | .windows => netListenIpWindows, |
| ... | ... | @@ -291,6 +239,73 @@ pub fn io(t: *Threaded) Io { |
| 291 | 239 | }; |
| 292 | 240 | } |
| 293 | 241 | |
| 242 | /// Same as `io` but disables all networking functionality, which has |
| 243 | /// an additional dependency on Windows (ws2_32). |
| 244 | pub fn ioBasic(t: *Threaded) Io { |
| 245 | return .{ |
| 246 | .userdata = t, |
| 247 | .vtable = &.{ |
| 248 | .async = async, |
| 249 | .concurrent = concurrent, |
| 250 | .await = await, |
| 251 | .cancel = cancel, |
| 252 | .cancelRequested = cancelRequested, |
| 253 | .select = select, |
| 254 | |
| 255 | .groupAsync = groupAsync, |
| 256 | .groupWait = groupWait, |
| 257 | .groupWaitUncancelable = groupWaitUncancelable, |
| 258 | .groupCancel = groupCancel, |
| 259 | |
| 260 | .mutexLock = mutexLock, |
| 261 | .mutexLockUncancelable = mutexLockUncancelable, |
| 262 | .mutexUnlock = mutexUnlock, |
| 263 | |
| 264 | .conditionWait = conditionWait, |
| 265 | .conditionWaitUncancelable = conditionWaitUncancelable, |
| 266 | .conditionWake = conditionWake, |
| 267 | |
| 268 | .dirMake = dirMake, |
| 269 | .dirMakePath = dirMakePath, |
| 270 | .dirMakeOpenPath = dirMakeOpenPath, |
| 271 | .dirStat = dirStat, |
| 272 | .dirStatPath = dirStatPath, |
| 273 | .fileStat = fileStat, |
| 274 | .dirAccess = dirAccess, |
| 275 | .dirCreateFile = dirCreateFile, |
| 276 | .dirOpenFile = dirOpenFile, |
| 277 | .dirOpenDir = dirOpenDir, |
| 278 | .dirClose = dirClose, |
| 279 | .fileClose = fileClose, |
| 280 | .fileWriteStreaming = fileWriteStreaming, |
| 281 | .fileWritePositional = fileWritePositional, |
| 282 | .fileReadStreaming = fileReadStreaming, |
| 283 | .fileReadPositional = fileReadPositional, |
| 284 | .fileSeekBy = fileSeekBy, |
| 285 | .fileSeekTo = fileSeekTo, |
| 286 | .openSelfExe = openSelfExe, |
| 287 | |
| 288 | .now = now, |
| 289 | .sleep = sleep, |
| 290 | |
| 291 | .netListenIp = netListenIpUnavailable, |
| 292 | .netListenUnix = netListenUnixUnavailable, |
| 293 | .netAccept = netAcceptUnavailable, |
| 294 | .netBindIp = netBindIpUnavailable, |
| 295 | .netConnectIp = netConnectIpUnavailable, |
| 296 | .netConnectUnix = netConnectUnixUnavailable, |
| 297 | .netClose = netCloseUnavailable, |
| 298 | .netRead = netReadUnavailable, |
| 299 | .netWrite = netWriteUnavailable, |
| 300 | .netSend = netSendUnavailable, |
| 301 | .netReceive = netReceiveUnavailable, |
| 302 | .netInterfaceNameResolve = netInterfaceNameResolveUnavailable, |
| 303 | .netInterfaceName = netInterfaceNameUnavailable, |
| 304 | .netLookup = netLookupUnavailable, |
| 305 | }, |
| 306 | }; |
| 307 | } |
| 308 | |
| 294 | 309 | pub const socket_flags_unsupported = native_os.isDarwin() or native_os == .haiku; // 💩💩 |
| 295 | 310 | const have_accept4 = !socket_flags_unsupported; |
| 296 | 311 | const have_flock_open_flags = @hasField(posix.O, "EXLOCK"); |
| ... | ... | @@ -804,7 +819,7 @@ fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mut |
| 804 | 819 | fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) void { |
| 805 | 820 | if (builtin.single_threaded) unreachable; // Deadlock. |
| 806 | 821 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 807 | | const t_io = t.io(); |
| 822 | const t_io = ioBasic(t); |
| 808 | 823 | comptime assert(@TypeOf(cond.state) == u64); |
| 809 | 824 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); |
| 810 | 825 | const cond_state = &ints[0]; |
| ... | ... | @@ -835,6 +850,7 @@ fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: |
| 835 | 850 | fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void { |
| 836 | 851 | if (builtin.single_threaded) unreachable; // Deadlock. |
| 837 | 852 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 853 | const t_io = ioBasic(t); |
| 838 | 854 | comptime assert(@TypeOf(cond.state) == u64); |
| 839 | 855 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); |
| 840 | 856 | const cond_state = &ints[0]; |
| ... | ... | @@ -858,8 +874,8 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I |
| 858 | 874 | assert(state & waiter_mask != waiter_mask); |
| 859 | 875 | state += one_waiter; |
| 860 | 876 | |
| 861 | | mutex.unlock(t.io()); |
| 862 | | defer mutex.lockUncancelable(t.io()); |
| 877 | mutex.unlock(t_io); |
| 878 | defer mutex.lockUncancelable(t_io); |
| 863 | 879 | |
| 864 | 880 | while (true) { |
| 865 | 881 | try futexWait(t, cond_epoch, epoch); |
| ... | ... | @@ -939,6 +955,12 @@ fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition. |
| 939 | 955 | } |
| 940 | 956 | } |
| 941 | 957 | |
| 958 | const dirMake = switch (native_os) { |
| 959 | .windows => dirMakeWindows, |
| 960 | .wasi => dirMakeWasi, |
| 961 | else => dirMakePosix, |
| 962 | }; |
| 963 | |
| 942 | 964 | fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { |
| 943 | 965 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 944 | 966 | |
| ... | ... | @@ -1027,6 +1049,11 @@ fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode |
| 1027 | 1049 | windows.CloseHandle(sub_dir_handle); |
| 1028 | 1050 | } |
| 1029 | 1051 | |
| 1052 | const dirMakePath = switch (native_os) { |
| 1053 | .windows => dirMakePathWindows, |
| 1054 | else => dirMakePathPosix, |
| 1055 | }; |
| 1056 | |
| 1030 | 1057 | fn dirMakePathPosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { |
| 1031 | 1058 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1032 | 1059 | _ = t; |
| ... | ... | @@ -1045,6 +1072,12 @@ fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, |
| 1045 | 1072 | @panic("TODO implement dirMakePathWindows"); |
| 1046 | 1073 | } |
| 1047 | 1074 | |
| 1075 | const dirMakeOpenPath = switch (native_os) { |
| 1076 | .windows => dirMakeOpenPathWindows, |
| 1077 | .wasi => dirMakeOpenPathWasi, |
| 1078 | else => dirMakeOpenPathPosix, |
| 1079 | }; |
| 1080 | |
| 1048 | 1081 | fn dirMakeOpenPathPosix( |
| 1049 | 1082 | userdata: ?*anyopaque, |
| 1050 | 1083 | dir: Io.Dir, |
| ... | ... | @@ -1052,11 +1085,11 @@ fn dirMakeOpenPathPosix( |
| 1052 | 1085 | options: Io.Dir.OpenOptions, |
| 1053 | 1086 | ) Io.Dir.MakeOpenPathError!Io.Dir { |
| 1054 | 1087 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1055 | | const t_io = t.io(); |
| 1056 | | return dir.openDir(t_io, sub_path, options) catch |err| switch (err) { |
| 1088 | const t_io = ioBasic(t); |
| 1089 | return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) { |
| 1057 | 1090 | error.FileNotFound => { |
| 1058 | 1091 | try dir.makePath(t_io, sub_path); |
| 1059 | | return dir.openDir(t_io, sub_path, options); |
| 1092 | return dirOpenDirPosix(t, dir, sub_path, options); |
| 1060 | 1093 | }, |
| 1061 | 1094 | else => |e| return e, |
| 1062 | 1095 | }; |
| ... | ... | @@ -1135,7 +1168,7 @@ fn dirMakeOpenPathWindows( |
| 1135 | 1168 | // could cause an infinite loop |
| 1136 | 1169 | check_dir: { |
| 1137 | 1170 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 1138 | | const fstat = dir.statPath(t.io(), component.path, .{ |
| 1171 | const fstat = dirStatPathWindows(t, dir, component.path, .{ |
| 1139 | 1172 | .follow_symlinks = options.follow_symlinks, |
| 1140 | 1173 | }) catch |stat_err| switch (stat_err) { |
| 1141 | 1174 | error.IsDir => break :check_dir, |
| ... | ... | @@ -1187,6 +1220,13 @@ fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { |
| 1187 | 1220 | @panic("TODO implement dirStat"); |
| 1188 | 1221 | } |
| 1189 | 1222 | |
| 1223 | const dirStatPath = switch (native_os) { |
| 1224 | .linux => dirStatPathLinux, |
| 1225 | .windows => dirStatPathWindows, |
| 1226 | .wasi => dirStatPathWasi, |
| 1227 | else => dirStatPathPosix, |
| 1228 | }; |
| 1229 | |
| 1190 | 1230 | fn dirStatPathLinux( |
| 1191 | 1231 | userdata: ?*anyopaque, |
| 1192 | 1232 | dir: Io.Dir, |
| ... | ... | @@ -1275,12 +1315,11 @@ fn dirStatPathWindows( |
| 1275 | 1315 | options: Io.Dir.StatPathOptions, |
| 1276 | 1316 | ) Io.Dir.StatPathError!Io.File.Stat { |
| 1277 | 1317 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1278 | | const t_io = t.io(); |
| 1279 | | var file = try dir.openFile(t_io, sub_path, .{ |
| 1318 | const file = try dirOpenFileWindows(t, dir, sub_path, .{ |
| 1280 | 1319 | .follow_symlinks = options.follow_symlinks, |
| 1281 | 1320 | }); |
| 1282 | | defer file.close(t_io); |
| 1283 | | return file.stat(t_io); |
| 1321 | defer windows.CloseHandle(file.handle); |
| 1322 | return fileStatWindows(t, file); |
| 1284 | 1323 | } |
| 1285 | 1324 | |
| 1286 | 1325 | fn dirStatPathWasi( |
| ... | ... | @@ -1318,6 +1357,13 @@ fn dirStatPathWasi( |
| 1318 | 1357 | } |
| 1319 | 1358 | } |
| 1320 | 1359 | |
| 1360 | const fileStat = switch (native_os) { |
| 1361 | .linux => fileStatLinux, |
| 1362 | .windows => fileStatWindows, |
| 1363 | .wasi => fileStatWasi, |
| 1364 | else => fileStatPosix, |
| 1365 | }; |
| 1366 | |
| 1321 | 1367 | fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat { |
| 1322 | 1368 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1323 | 1369 | |
| ... | ... | @@ -1440,6 +1486,12 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. |
| 1440 | 1486 | } |
| 1441 | 1487 | } |
| 1442 | 1488 | |
| 1489 | const dirAccess = switch (native_os) { |
| 1490 | .windows => dirAccessWindows, |
| 1491 | .wasi => dirAccessWasi, |
| 1492 | else => dirAccessPosix, |
| 1493 | }; |
| 1494 | |
| 1443 | 1495 | fn dirAccessPosix( |
| 1444 | 1496 | userdata: ?*anyopaque, |
| 1445 | 1497 | dir: Io.Dir, |
| ... | ... | @@ -1589,6 +1641,12 @@ fn dirAccessWindows( |
| 1589 | 1641 | } |
| 1590 | 1642 | } |
| 1591 | 1643 | |
| 1644 | const dirCreateFile = switch (native_os) { |
| 1645 | .windows => dirCreateFileWindows, |
| 1646 | .wasi => dirCreateFileWasi, |
| 1647 | else => dirCreateFilePosix, |
| 1648 | }; |
| 1649 | |
| 1592 | 1650 | fn dirCreateFilePosix( |
| 1593 | 1651 | userdata: ?*anyopaque, |
| 1594 | 1652 | dir: Io.Dir, |
| ... | ... | @@ -1827,6 +1885,12 @@ fn dirCreateFileWasi( |
| 1827 | 1885 | } |
| 1828 | 1886 | } |
| 1829 | 1887 | |
| 1888 | const dirOpenFile = switch (native_os) { |
| 1889 | .windows => dirOpenFileWindows, |
| 1890 | .wasi => dirOpenFileWasi, |
| 1891 | else => dirOpenFilePosix, |
| 1892 | }; |
| 1893 | |
| 1830 | 1894 | fn dirOpenFilePosix( |
| 1831 | 1895 | userdata: ?*anyopaque, |
| 1832 | 1896 | dir: Io.Dir, |
| ... | ... | @@ -2077,6 +2141,12 @@ fn dirOpenFileWasi( |
| 2077 | 2141 | } |
| 2078 | 2142 | } |
| 2079 | 2143 | |
| 2144 | const dirOpenDir = switch (native_os) { |
| 2145 | .wasi => dirOpenDirWasi, |
| 2146 | .haiku => dirOpenDirHaiku, |
| 2147 | else => dirOpenDirPosix, |
| 2148 | }; |
| 2149 | |
| 2080 | 2150 | fn dirOpenDirPosix( |
| 2081 | 2151 | userdata: ?*anyopaque, |
| 2082 | 2152 | dir: Io.Dir, |
| ... | ... | @@ -2320,6 +2390,11 @@ fn fileClose(userdata: ?*anyopaque, file: Io.File) void { |
| 2320 | 2390 | posix.close(file.handle); |
| 2321 | 2391 | } |
| 2322 | 2392 | |
| 2393 | const fileReadStreaming = switch (native_os) { |
| 2394 | .windows => fileReadStreamingWindows, |
| 2395 | else => fileReadStreamingPosix, |
| 2396 | }; |
| 2397 | |
| 2323 | 2398 | fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize { |
| 2324 | 2399 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2325 | 2400 | |
| ... | ... | @@ -2482,6 +2557,11 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o |
| 2482 | 2557 | } |
| 2483 | 2558 | } |
| 2484 | 2559 | |
| 2560 | const fileReadPositional = switch (native_os) { |
| 2561 | .windows => fileReadPositionalWindows, |
| 2562 | else => fileReadPositionalPosix, |
| 2563 | }; |
| 2564 | |
| 2485 | 2565 | fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize { |
| 2486 | 2566 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2487 | 2567 | try t.checkCancel(); |
| ... | ... | @@ -2652,6 +2732,12 @@ fn nowPosix(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp |
| 2652 | 2732 | } |
| 2653 | 2733 | } |
| 2654 | 2734 | |
| 2735 | const now = switch (native_os) { |
| 2736 | .windows => nowWindows, |
| 2737 | .wasi => nowWasi, |
| 2738 | else => nowPosix, |
| 2739 | }; |
| 2740 | |
| 2655 | 2741 | fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 2656 | 2742 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2657 | 2743 | _ = t; |
| ... | ... | @@ -2680,6 +2766,13 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 2680 | 2766 | return .fromNanoseconds(ns); |
| 2681 | 2767 | } |
| 2682 | 2768 | |
| 2769 | const sleep = switch (native_os) { |
| 2770 | .windows => sleepWindows, |
| 2771 | .wasi => sleepWasi, |
| 2772 | .linux => sleepLinux, |
| 2773 | else => sleepPosix, |
| 2774 | }; |
| 2775 | |
| 2683 | 2776 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2684 | 2777 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2685 | 2778 | const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { |
| ... | ... | @@ -2710,9 +2803,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2710 | 2803 | |
| 2711 | 2804 | fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2712 | 2805 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2806 | const t_io = ioBasic(t); |
| 2713 | 2807 | try t.checkCancel(); |
| 2714 | 2808 | const ms = ms: { |
| 2715 | | const d = (try timeout.toDurationFromNow(t.io())) orelse |
| 2809 | const d = (try timeout.toDurationFromNow(t_io)) orelse |
| 2716 | 2810 | break :ms std.math.maxInt(windows.DWORD); |
| 2717 | 2811 | break :ms std.math.lossyCast(windows.DWORD, d.raw.toMilliseconds()); |
| 2718 | 2812 | }; |
| ... | ... | @@ -2721,11 +2815,12 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2721 | 2815 | |
| 2722 | 2816 | fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2723 | 2817 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2818 | const t_io = ioBasic(t); |
| 2724 | 2819 | try t.checkCancel(); |
| 2725 | 2820 | |
| 2726 | 2821 | const w = std.os.wasi; |
| 2727 | 2822 | |
| 2728 | | const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t.io())) |d| .{ |
| 2823 | const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{ |
| 2729 | 2824 | .id = clockToWasi(d.clock), |
| 2730 | 2825 | .timeout = std.math.lossyCast(u64, d.raw.nanoseconds), |
| 2731 | 2826 | .precision = 0, |
| ... | ... | @@ -2750,11 +2845,12 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2750 | 2845 | |
| 2751 | 2846 | fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2752 | 2847 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2848 | const t_io = ioBasic(t); |
| 2753 | 2849 | const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type; |
| 2754 | 2850 | const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type; |
| 2755 | 2851 | |
| 2756 | 2852 | var timespec: posix.timespec = t: { |
| 2757 | | const d = (try timeout.toDurationFromNow(t.io())) orelse break :t .{ |
| 2853 | const d = (try timeout.toDurationFromNow(t_io)) orelse break :t .{ |
| 2758 | 2854 | .sec = std.math.maxInt(sec_type), |
| 2759 | 2855 | .nsec = std.math.maxInt(nsec_type), |
| 2760 | 2856 | }; |
| ... | ... | @@ -2919,6 +3015,17 @@ fn netListenIpWindows( |
| 2919 | 3015 | }; |
| 2920 | 3016 | } |
| 2921 | 3017 | |
| 3018 | fn netListenIpUnavailable( |
| 3019 | userdata: ?*anyopaque, |
| 3020 | address: IpAddress, |
| 3021 | options: IpAddress.ListenOptions, |
| 3022 | ) IpAddress.ListenError!net.Server { |
| 3023 | _ = userdata; |
| 3024 | _ = address; |
| 3025 | _ = options; |
| 3026 | return error.NetworkDown; |
| 3027 | } |
| 3028 | |
| 2922 | 3029 | fn netListenUnixPosix( |
| 2923 | 3030 | userdata: ?*anyopaque, |
| 2924 | 3031 | address: *const net.UnixAddress, |
| ... | ... | @@ -2965,6 +3072,17 @@ fn netListenUnixWindows( |
| 2965 | 3072 | @panic("TODO implement netListenUnixWindows"); |
| 2966 | 3073 | } |
| 2967 | 3074 | |
| 3075 | fn netListenUnixUnavailable( |
| 3076 | userdata: ?*anyopaque, |
| 3077 | address: *const net.UnixAddress, |
| 3078 | options: net.UnixAddress.ListenOptions, |
| 3079 | ) net.UnixAddress.ListenError!net.Socket.Handle { |
| 3080 | _ = userdata; |
| 3081 | _ = address; |
| 3082 | _ = options; |
| 3083 | return error.AddressFamilyUnsupported; |
| 3084 | } |
| 3085 | |
| 2968 | 3086 | fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void { |
| 2969 | 3087 | while (true) { |
| 2970 | 3088 | try t.checkCancel(); |
| ... | ... | @@ -3235,6 +3353,17 @@ fn netConnectIpWindows( |
| 3235 | 3353 | } }; |
| 3236 | 3354 | } |
| 3237 | 3355 | |
| 3356 | fn netConnectIpUnavailable( |
| 3357 | userdata: ?*anyopaque, |
| 3358 | address: *const IpAddress, |
| 3359 | options: IpAddress.ConnectOptions, |
| 3360 | ) IpAddress.ConnectError!net.Stream { |
| 3361 | _ = userdata; |
| 3362 | _ = address; |
| 3363 | _ = options; |
| 3364 | return error.NetworkDown; |
| 3365 | } |
| 3366 | |
| 3238 | 3367 | fn netConnectUnixPosix( |
| 3239 | 3368 | userdata: ?*anyopaque, |
| 3240 | 3369 | address: *const net.UnixAddress, |
| ... | ... | @@ -3263,6 +3392,15 @@ fn netConnectUnixWindows( |
| 3263 | 3392 | @panic("TODO implement netConnectUnixWindows"); |
| 3264 | 3393 | } |
| 3265 | 3394 | |
| 3395 | fn netConnectUnixUnavailable( |
| 3396 | userdata: ?*anyopaque, |
| 3397 | address: *const net.UnixAddress, |
| 3398 | ) net.UnixAddress.ConnectError!net.Socket.Handle { |
| 3399 | _ = userdata; |
| 3400 | _ = address; |
| 3401 | return error.AddressFamilyUnsupported; |
| 3402 | } |
| 3403 | |
| 3266 | 3404 | fn netBindIpPosix( |
| 3267 | 3405 | userdata: ?*anyopaque, |
| 3268 | 3406 | address: *const IpAddress, |
| ... | ... | @@ -3330,6 +3468,17 @@ fn netBindIpWindows( |
| 3330 | 3468 | }; |
| 3331 | 3469 | } |
| 3332 | 3470 | |
| 3471 | fn netBindIpUnavailable( |
| 3472 | userdata: ?*anyopaque, |
| 3473 | address: *const IpAddress, |
| 3474 | options: IpAddress.BindOptions, |
| 3475 | ) IpAddress.BindError!net.Socket { |
| 3476 | _ = userdata; |
| 3477 | _ = address; |
| 3478 | _ = options; |
| 3479 | return error.NetworkDown; |
| 3480 | } |
| 3481 | |
| 3333 | 3482 | fn openSocketPosix( |
| 3334 | 3483 | t: *Threaded, |
| 3335 | 3484 | family: posix.sa_family_t, |
| ... | ... | @@ -3498,7 +3647,14 @@ fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net |
| 3498 | 3647 | } |
| 3499 | 3648 | } |
| 3500 | 3649 | |
| 3650 | fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream { |
| 3651 | _ = userdata; |
| 3652 | _ = listen_handle; |
| 3653 | return error.NetworkDown; |
| 3654 | } |
| 3655 | |
| 3501 | 3656 | fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { |
| 3657 | if (!have_networking) return error.NetworkDown; |
| 3502 | 3658 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3503 | 3659 | |
| 3504 | 3660 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| ... | ... | @@ -3560,7 +3716,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net. |
| 3560 | 3716 | } |
| 3561 | 3717 | |
| 3562 | 3718 | fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { |
| 3563 | | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 3719 | if (!have_networking) return error.NetworkDown; |
| 3564 | 3720 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3565 | 3721 | _ = t; |
| 3566 | 3722 | _ = handle; |
| ... | ... | @@ -3568,6 +3724,13 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8 |
| 3568 | 3724 | @panic("TODO implement netReadWindows"); |
| 3569 | 3725 | } |
| 3570 | 3726 | |
| 3727 | fn netReadUnavailable(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { |
| 3728 | _ = userdata; |
| 3729 | _ = fd; |
| 3730 | _ = data; |
| 3731 | return error.NetworkDown; |
| 3732 | } |
| 3733 | |
| 3571 | 3734 | fn netSendPosix( |
| 3572 | 3735 | userdata: ?*anyopaque, |
| 3573 | 3736 | handle: net.Socket.Handle, |
| ... | ... | @@ -3612,6 +3775,19 @@ fn netSendWindows( |
| 3612 | 3775 | @panic("TODO netSendWindows"); |
| 3613 | 3776 | } |
| 3614 | 3777 | |
| 3778 | fn netSendUnavailable( |
| 3779 | userdata: ?*anyopaque, |
| 3780 | handle: net.Socket.Handle, |
| 3781 | messages: []net.OutgoingMessage, |
| 3782 | flags: net.SendFlags, |
| 3783 | ) struct { ?net.Socket.SendError, usize } { |
| 3784 | _ = userdata; |
| 3785 | _ = handle; |
| 3786 | _ = messages; |
| 3787 | _ = flags; |
| 3788 | return .{ error.NetworkDown, 0 }; |
| 3789 | } |
| 3790 | |
| 3615 | 3791 | fn netSendOne( |
| 3616 | 3792 | t: *Threaded, |
| 3617 | 3793 | handle: net.Socket.Handle, |
| ... | ... | @@ -3777,6 +3953,7 @@ fn netReceivePosix( |
| 3777 | 3953 | ) struct { ?net.Socket.ReceiveTimeoutError, usize } { |
| 3778 | 3954 | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 3779 | 3955 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3956 | const t_io = io(t); |
| 3780 | 3957 | |
| 3781 | 3958 | // recvmmsg is useless, here's why: |
| 3782 | 3959 | // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371) |
| ... | ... | @@ -3803,7 +3980,7 @@ fn netReceivePosix( |
| 3803 | 3980 | var message_i: usize = 0; |
| 3804 | 3981 | var data_i: usize = 0; |
| 3805 | 3982 | |
| 3806 | | const deadline = timeout.toDeadline(t.io()) catch |err| return .{ err, message_i }; |
| 3983 | const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i }; |
| 3807 | 3984 | |
| 3808 | 3985 | recv: while (true) { |
| 3809 | 3986 | t.checkCancel() catch |err| return .{ err, message_i }; |
| ... | ... | @@ -3849,7 +4026,7 @@ fn netReceivePosix( |
| 3849 | 4026 | |
| 3850 | 4027 | const max_poll_ms = std.math.maxInt(u31); |
| 3851 | 4028 | const timeout_ms: u31 = if (deadline) |d| t: { |
| 3852 | | const duration = d.durationFromNow(t.io()) catch |err| return .{ err, message_i }; |
| 4029 | const duration = d.durationFromNow(t_io) catch |err| return .{ err, message_i }; |
| 3853 | 4030 | if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i }; |
| 3854 | 4031 | break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); |
| 3855 | 4032 | } else max_poll_ms; |
| ... | ... | @@ -3915,6 +4092,23 @@ fn netReceiveWindows( |
| 3915 | 4092 | @panic("TODO implement netReceiveWindows"); |
| 3916 | 4093 | } |
| 3917 | 4094 | |
| 4095 | fn netReceiveUnavailable( |
| 4096 | userdata: ?*anyopaque, |
| 4097 | handle: net.Socket.Handle, |
| 4098 | message_buffer: []net.IncomingMessage, |
| 4099 | data_buffer: []u8, |
| 4100 | flags: net.ReceiveFlags, |
| 4101 | timeout: Io.Timeout, |
| 4102 | ) struct { ?net.Socket.ReceiveTimeoutError, usize } { |
| 4103 | _ = userdata; |
| 4104 | _ = handle; |
| 4105 | _ = message_buffer; |
| 4106 | _ = data_buffer; |
| 4107 | _ = flags; |
| 4108 | _ = timeout; |
| 4109 | return .{ error.NetworkDown, 0 }; |
| 4110 | } |
| 4111 | |
| 3918 | 4112 | fn netWritePosix( |
| 3919 | 4113 | userdata: ?*anyopaque, |
| 3920 | 4114 | fd: net.Socket.Handle, |
| ... | ... | @@ -4013,6 +4207,21 @@ fn netWriteWindows( |
| 4013 | 4207 | @panic("TODO implement netWriteWindows"); |
| 4014 | 4208 | } |
| 4015 | 4209 | |
| 4210 | fn netWriteUnavailable( |
| 4211 | userdata: ?*anyopaque, |
| 4212 | handle: net.Socket.Handle, |
| 4213 | header: []const u8, |
| 4214 | data: []const []const u8, |
| 4215 | splat: usize, |
| 4216 | ) net.Stream.Writer.Error!usize { |
| 4217 | _ = userdata; |
| 4218 | _ = handle; |
| 4219 | _ = header; |
| 4220 | _ = data; |
| 4221 | _ = splat; |
| 4222 | return error.NetworkDown; |
| 4223 | } |
| 4224 | |
| 4016 | 4225 | fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { |
| 4017 | 4226 | // OS checks ptr addr before length so zero length vectors must be omitted. |
| 4018 | 4227 | if (bytes.len == 0) return; |
| ... | ... | @@ -4030,6 +4239,12 @@ fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void { |
| 4030 | 4239 | } |
| 4031 | 4240 | } |
| 4032 | 4241 | |
| 4242 | fn netCloseUnavailable(userdata: ?*anyopaque, handle: net.Socket.Handle) void { |
| 4243 | _ = userdata; |
| 4244 | _ = handle; |
| 4245 | unreachable; // How you gonna close something that was impossible to open? |
| 4246 | } |
| 4247 | |
| 4033 | 4248 | fn netInterfaceNameResolve( |
| 4034 | 4249 | userdata: ?*anyopaque, |
| 4035 | 4250 | name: *const net.Interface.Name, |
| ... | ... | @@ -4089,6 +4304,15 @@ fn netInterfaceNameResolve( |
| 4089 | 4304 | @panic("unimplemented"); |
| 4090 | 4305 | } |
| 4091 | 4306 | |
| 4307 | fn netInterfaceNameResolveUnavailable( |
| 4308 | userdata: ?*anyopaque, |
| 4309 | name: *const net.Interface.Name, |
| 4310 | ) net.Interface.Name.ResolveError!net.Interface { |
| 4311 | _ = userdata; |
| 4312 | _ = name; |
| 4313 | return error.InterfaceNotFound; |
| 4314 | } |
| 4315 | |
| 4092 | 4316 | fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { |
| 4093 | 4317 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4094 | 4318 | try t.checkCancel(); |
| ... | ... | @@ -4109,6 +4333,12 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa |
| 4109 | 4333 | @panic("unimplemented"); |
| 4110 | 4334 | } |
| 4111 | 4335 | |
| 4336 | fn netInterfaceNameUnavailable(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { |
| 4337 | _ = userdata; |
| 4338 | _ = interface; |
| 4339 | return error.Unexpected; |
| 4340 | } |
| 4341 | |
| 4112 | 4342 | fn netLookup( |
| 4113 | 4343 | userdata: ?*anyopaque, |
| 4114 | 4344 | host_name: HostName, |
| ... | ... | @@ -4116,17 +4346,31 @@ fn netLookup( |
| 4116 | 4346 | options: HostName.LookupOptions, |
| 4117 | 4347 | ) void { |
| 4118 | 4348 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4119 | | const t_io = t.io(); |
| 4349 | const t_io = io(t); |
| 4120 | 4350 | resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) }); |
| 4121 | 4351 | } |
| 4122 | 4352 | |
| 4353 | fn netLookupUnavailable( |
| 4354 | userdata: ?*anyopaque, |
| 4355 | host_name: HostName, |
| 4356 | resolved: *Io.Queue(HostName.LookupResult), |
| 4357 | options: HostName.LookupOptions, |
| 4358 | ) void { |
| 4359 | _ = host_name; |
| 4360 | _ = options; |
| 4361 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4362 | const t_io = ioBasic(t); |
| 4363 | resolved.putOneUncancelable(t_io, .{ .end = error.NetworkDown }); |
| 4364 | } |
| 4365 | |
| 4123 | 4366 | fn netLookupFallible( |
| 4124 | 4367 | t: *Threaded, |
| 4125 | 4368 | host_name: HostName, |
| 4126 | 4369 | resolved: *Io.Queue(HostName.LookupResult), |
| 4127 | 4370 | options: HostName.LookupOptions, |
| 4128 | 4371 | ) !void { |
| 4129 | | const t_io = t.io(); |
| 4372 | if (!have_networking) return error.NetworkDown; |
| 4373 | const t_io = io(t); |
| 4130 | 4374 | const name = host_name.bytes; |
| 4131 | 4375 | assert(name.len <= HostName.max_len); |
| 4132 | 4376 | |
| ... | ... | @@ -4637,7 +4881,7 @@ fn lookupDnsSearch( |
| 4637 | 4881 | resolved: *Io.Queue(HostName.LookupResult), |
| 4638 | 4882 | options: HostName.LookupOptions, |
| 4639 | 4883 | ) HostName.LookupError!void { |
| 4640 | | const t_io = t.io(); |
| 4884 | const t_io = io(t); |
| 4641 | 4885 | const rc = HostName.ResolvConf.init(t_io) catch return error.ResolvConfParseFailed; |
| 4642 | 4886 | |
| 4643 | 4887 | // Count dots, suppress search when >=ndots or name ends in |
| ... | ... | @@ -4681,7 +4925,7 @@ fn lookupDns( |
| 4681 | 4925 | resolved: *Io.Queue(HostName.LookupResult), |
| 4682 | 4926 | options: HostName.LookupOptions, |
| 4683 | 4927 | ) HostName.LookupError!void { |
| 4684 | | const t_io = t.io(); |
| 4928 | const t_io = io(t); |
| 4685 | 4929 | const family_records: [2]struct { af: IpAddress.Family, rr: HostName.DnsRecord } = .{ |
| 4686 | 4930 | .{ .af = .ip6, .rr = .A }, |
| 4687 | 4931 | .{ .af = .ip4, .rr = .AAAA }, |
| ... | ... | @@ -4868,7 +5112,7 @@ fn lookupHosts( |
| 4868 | 5112 | resolved: *Io.Queue(HostName.LookupResult), |
| 4869 | 5113 | options: HostName.LookupOptions, |
| 4870 | 5114 | ) !void { |
| 4871 | | const t_io = t.io(); |
| 5115 | const t_io = io(t); |
| 4872 | 5116 | const file = Io.File.openAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) { |
| 4873 | 5117 | error.FileNotFound, |
| 4874 | 5118 | error.NotDir, |
| ... | ... | @@ -4906,7 +5150,7 @@ fn lookupHostsReader( |
| 4906 | 5150 | options: HostName.LookupOptions, |
| 4907 | 5151 | reader: *Io.Reader, |
| 4908 | 5152 | ) error{ ReadFailed, Canceled, UnknownHostName }!void { |
| 4909 | | const t_io = t.io(); |
| 5153 | const t_io = io(t); |
| 4910 | 5154 | var addresses_len: usize = 0; |
| 4911 | 5155 | var canonical_name: ?HostName = null; |
| 4912 | 5156 | while (true) { |
| ... | ... | @@ -5374,7 +5618,7 @@ const Wsa = struct { |
| 5374 | 5618 | }; |
| 5375 | 5619 | |
| 5376 | 5620 | fn initializeWsa(t: *Threaded) error{NetworkDown}!void { |
| 5377 | | const t_io = t.io(); |
| 5621 | const t_io = io(t); |
| 5378 | 5622 | const wsa = &t.wsa; |
| 5379 | 5623 | wsa.mutex.lockUncancelable(t_io); |
| 5380 | 5624 | defer wsa.mutex.unlock(t_io); |