| ... | @@ -30,20 +30,20 @@ pub const Request = struct { | ... | @@ -30,20 +30,20 @@ pub const Request = struct { |
| 30 | | 30 | |
| 31 | pub const PWriteV = struct { | 31 | pub const PWriteV = struct { |
| 32 | fd: os.FileHandle, | 32 | fd: os.FileHandle, |
| 33 | iov: []os.posix.iovec_const, | 33 | iov: []const os.posix.iovec_const, |
| 34 | offset: usize, | 34 | offset: usize, |
| 35 | result: Error!void, | 35 | result: Error!void, |
| 36 | | 36 | |
| 37 | pub const Error = os.File.WriteError; | 37 | pub const Error = os.PosixWriteError; |
| 38 | }; | 38 | }; |
| 39 | | 39 | |
| 40 | pub const PReadV = struct { | 40 | pub const PReadV = struct { |
| 41 | fd: os.FileHandle, | 41 | fd: os.FileHandle, |
| 42 | iov: []os.posix.iovec, | 42 | iov: []const os.posix.iovec, |
| 43 | offset: usize, | 43 | offset: usize, |
| 44 | result: Error!usize, | 44 | result: Error!usize, |
| 45 | | 45 | |
| 46 | pub const Error = os.File.ReadError; | 46 | pub const Error = os.PosixReadError; |
| 47 | }; | 47 | }; |
| 48 | | 48 | |
| 49 | pub const Open = struct { | 49 | pub const Open = struct { |
| ... | @@ -72,28 +72,47 @@ pub const Request = struct { | ... | @@ -72,28 +72,47 @@ pub const Request = struct { |
| 72 | }; | 72 | }; |
| 73 | }; | 73 | }; |
| 74 | | 74 | |
| | 75 | pub const PWriteVError = error{OutOfMemory} || os.File.WriteError; |
| | 76 | |
| 75 | /// data - just the inner references - must live until pwritev promise completes. | 77 | /// data - just the inner references - must live until pwritev promise completes. |
| 76 | pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { | 78 | pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) PWriteVError!void { |
| | 79 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| | 80 | suspend { |
| | 81 | resume @handle(); |
| | 82 | } |
| 77 | switch (builtin.os) { | 83 | switch (builtin.os) { |
| 78 | builtin.Os.macosx, | 84 | builtin.Os.macosx, |
| 79 | builtin.Os.linux, | 85 | builtin.Os.linux, |
| 80 | => return await (async pwritevPosix(loop, fd, data, offset) catch unreachable), | 86 | => { |
| 81 | builtin.Os.windows => return await (async pwritevWindows(loop, fd, data, offset) catch unreachable), | 87 | const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); |
| | 88 | defer loop.allocator.free(iovecs); |
| | 89 | |
| | 90 | for (data) |buf, i| { |
| | 91 | iovecs[i] = os.posix.iovec_const{ |
| | 92 | .iov_base = buf.ptr, |
| | 93 | .iov_len = buf.len, |
| | 94 | }; |
| | 95 | } |
| | 96 | |
| | 97 | return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable); |
| | 98 | }, |
| | 99 | builtin.Os.windows => { |
| | 100 | const data_copy = try std.mem.dupe(loop.allocator, []const u8, data); |
| | 101 | defer loop.allocator.free(data_copy); |
| | 102 | return await (async pwritevWindows(loop, fd, data, offset) catch unreachable); |
| | 103 | }, |
| 82 | else => @compileError("Unsupported OS"), | 104 | else => @compileError("Unsupported OS"), |
| 83 | } | 105 | } |
| 84 | } | 106 | } |
| 85 | | 107 | |
| 86 | /// data - just the inner references - must live until pwritev promise completes. | 108 | /// data must outlive the returned promise |
| 87 | pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { | 109 | pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) os.WindowsWriteError!void { |
| 88 | if (data.len == 0) return; | 110 | if (data.len == 0) return; |
| 89 | if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable); | 111 | if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable); |
| 90 | | 112 | |
| 91 | const data_copy = try std.mem.dupe(loop.allocator, []const u8, data); | | |
| 92 | defer loop.allocator.free(data_copy); | | |
| 93 | | | |
| 94 | // TODO do these in parallel | 113 | // TODO do these in parallel |
| 95 | var off = offset; | 114 | var off = offset; |
| 96 | for (data_copy) |buf| { | 115 | for (data) |buf| { |
| 97 | try await (async pwriteWindows(loop, fd, buf, off) catch unreachable); | 116 | try await (async pwriteWindows(loop, fd, buf, off) catch unreachable); |
| 98 | off += buf.len; | 117 | off += buf.len; |
| 99 | } | 118 | } |
| ... | @@ -144,23 +163,18 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off | ... | @@ -144,23 +163,18 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off |
| 144 | } | 163 | } |
| 145 | } | 164 | } |
| 146 | | 165 | |
| 147 | /// data - just the inner references - must live until pwritev promise completes. | 166 | /// iovecs must live until pwritev promise completes. |
| 148 | pub async fn pwritevPosix(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) !void { | 167 | pub async fn pwritevPosix( |
| | 168 | loop: *Loop, |
| | 169 | fd: os.FileHandle, |
| | 170 | iovecs: []const posix.iovec_const, |
| | 171 | offset: usize, |
| | 172 | ) os.PosixWriteError!void { |
| 149 | // workaround for https://github.com/ziglang/zig/issues/1194 | 173 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 150 | suspend { | 174 | suspend { |
| 151 | resume @handle(); | 175 | resume @handle(); |
| 152 | } | 176 | } |
| 153 | | 177 | |
| 154 | const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); | | |
| 155 | defer loop.allocator.free(iovecs); | | |
| 156 | | | |
| 157 | for (data) |buf, i| { | | |
| 158 | iovecs[i] = os.posix.iovec_const{ | | |
| 159 | .iov_base = buf.ptr, | | |
| 160 | .iov_len = buf.len, | | |
| 161 | }; | | |
| 162 | } | | |
| 163 | | | |
| 164 | var req_node = RequestNode{ | 178 | var req_node = RequestNode{ |
| 165 | .prev = null, | 179 | .prev = null, |
| 166 | .next = null, | 180 | .next = null, |
| ... | @@ -192,38 +206,59 @@ pub async fn pwritevPosix(loop: *Loop, fd: os.FileHandle, data: []const []const | ... | @@ -192,38 +206,59 @@ pub async fn pwritevPosix(loop: *Loop, fd: os.FileHandle, data: []const []const |
| 192 | return req_node.data.msg.PWriteV.result; | 206 | return req_node.data.msg.PWriteV.result; |
| 193 | } | 207 | } |
| 194 | | 208 | |
| | 209 | pub const PReadVError = error{OutOfMemory} || os.File.ReadError; |
| | 210 | |
| 195 | /// data - just the inner references - must live until preadv promise completes. | 211 | /// data - just the inner references - must live until preadv promise completes. |
| 196 | pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) !usize { | 212 | pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) PReadVError!usize { |
| | 213 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| | 214 | suspend { |
| | 215 | resume @handle(); |
| | 216 | } |
| | 217 | |
| 197 | assert(data.len != 0); | 218 | assert(data.len != 0); |
| 198 | switch (builtin.os) { | 219 | switch (builtin.os) { |
| 199 | builtin.Os.macosx, | 220 | builtin.Os.macosx, |
| 200 | builtin.Os.linux, | 221 | builtin.Os.linux, |
| 201 | => return await (async preadvPosix(loop, fd, data, offset) catch unreachable), | 222 | => { |
| 202 | builtin.Os.windows => return await (async preadvWindows(loop, fd, data, offset) catch unreachable), | 223 | const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); |
| | 224 | defer loop.allocator.free(iovecs); |
| | 225 | |
| | 226 | for (data) |buf, i| { |
| | 227 | iovecs[i] = os.posix.iovec{ |
| | 228 | .iov_base = buf.ptr, |
| | 229 | .iov_len = buf.len, |
| | 230 | }; |
| | 231 | } |
| | 232 | |
| | 233 | return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable); |
| | 234 | }, |
| | 235 | builtin.Os.windows => { |
| | 236 | const data_copy = try std.mem.dupe(loop.allocator, []u8, data); |
| | 237 | defer loop.allocator.free(data_copy); |
| | 238 | return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable); |
| | 239 | }, |
| 203 | else => @compileError("Unsupported OS"), | 240 | else => @compileError("Unsupported OS"), |
| 204 | } | 241 | } |
| 205 | } | 242 | } |
| 206 | | 243 | |
| 207 | pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) !usize { | 244 | /// data must outlive the returned promise |
| | 245 | pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) os.WindowsReadError!usize { |
| 208 | assert(data.len != 0); | 246 | assert(data.len != 0); |
| 209 | if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable); | 247 | if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable); |
| 210 | | 248 | |
| 211 | const data_copy = try std.mem.dupe(loop.allocator, []u8, data); | | |
| 212 | defer loop.allocator.free(data_copy); | | |
| 213 | | | |
| 214 | // TODO do these in parallel? | 249 | // TODO do these in parallel? |
| 215 | var off: usize = 0; | 250 | var off: usize = 0; |
| 216 | var iov_i: usize = 0; | 251 | var iov_i: usize = 0; |
| 217 | var inner_off: usize = 0; | 252 | var inner_off: usize = 0; |
| 218 | while (true) { | 253 | while (true) { |
| 219 | const v = data_copy[iov_i]; | 254 | const v = data[iov_i]; |
| 220 | const amt_read = try await (async preadWindows(loop, fd, v[inner_off .. v.len - inner_off], offset + off) catch unreachable); | 255 | const amt_read = try await (async preadWindows(loop, fd, v[inner_off .. v.len - inner_off], offset + off) catch unreachable); |
| 221 | off += amt_read; | 256 | off += amt_read; |
| 222 | inner_off += amt_read; | 257 | inner_off += amt_read; |
| 223 | if (inner_off == v.len) { | 258 | if (inner_off == v.len) { |
| 224 | iov_i += 1; | 259 | iov_i += 1; |
| 225 | inner_off = 0; | 260 | inner_off = 0; |
| 226 | if (iov_i == data_copy.len) { | 261 | if (iov_i == data.len) { |
| 227 | return off; | 262 | return off; |
| 228 | } | 263 | } |
| 229 | } | 264 | } |
| ... | @@ -275,23 +310,18 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6 | ... | @@ -275,23 +310,18 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6 |
| 275 | return usize(bytes_transferred); | 310 | return usize(bytes_transferred); |
| 276 | } | 311 | } |
| 277 | | 312 | |
| 278 | /// data - just the inner references - must live until preadv promise completes. | 313 | /// iovecs must live until preadv promise completes |
| 279 | pub async fn preadvPosix(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) !usize { | 314 | pub async fn preadvPosix( |
| | 315 | loop: *Loop, |
| | 316 | fd: os.FileHandle, |
| | 317 | iovecs: []const posix.iovec, |
| | 318 | offset: usize, |
| | 319 | ) os.PosixReadError!usize { |
| 280 | // workaround for https://github.com/ziglang/zig/issues/1194 | 320 | // workaround for https://github.com/ziglang/zig/issues/1194 |
| 281 | suspend { | 321 | suspend { |
| 282 | resume @handle(); | 322 | resume @handle(); |
| 283 | } | 323 | } |
| 284 | | 324 | |
| 285 | const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); | | |
| 286 | defer loop.allocator.free(iovecs); | | |
| 287 | | | |
| 288 | for (data) |buf, i| { | | |
| 289 | iovecs[i] = os.posix.iovec{ | | |
| 290 | .iov_base = buf.ptr, | | |
| 291 | .iov_len = buf.len, | | |
| 292 | }; | | |
| 293 | } | | |
| 294 | | | |
| 295 | var req_node = RequestNode{ | 325 | var req_node = RequestNode{ |
| 296 | .prev = null, | 326 | .prev = null, |
| 297 | .next = null, | 327 | .next = null, |
| ... | @@ -1339,3 +1369,55 @@ async fn testFsWatch(loop: *Loop) !void { | ... | @@ -1339,3 +1369,55 @@ async fn testFsWatch(loop: *Loop) !void { |
| 1339 | | 1369 | |
| 1340 | // TODO test deleting the file and then re-adding it. we should get events for both | 1370 | // TODO test deleting the file and then re-adding it. we should get events for both |
| 1341 | } | 1371 | } |
| | 1372 | |
| | 1373 | pub const OutStream = struct { |
| | 1374 | fd: os.FileHandle, |
| | 1375 | stream: Stream, |
| | 1376 | loop: *Loop, |
| | 1377 | offset: usize, |
| | 1378 | |
| | 1379 | pub const Error = os.File.WriteError; |
| | 1380 | pub const Stream = event.io.OutStream(Error); |
| | 1381 | |
| | 1382 | pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) OutStream { |
| | 1383 | return OutStream{ |
| | 1384 | .fd = fd, |
| | 1385 | .loop = loop, |
| | 1386 | .offset = offset, |
| | 1387 | .stream = Stream{ .writeFn = writeFn }, |
| | 1388 | }; |
| | 1389 | } |
| | 1390 | |
| | 1391 | async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { |
| | 1392 | const self = @fieldParentPtr(OutStream, "stream", out_stream); |
| | 1393 | const offset = self.offset; |
| | 1394 | self.offset += bytes.len; |
| | 1395 | return await (async pwritev(self.loop, self.fd, [][]const u8{bytes}, offset) catch unreachable); |
| | 1396 | } |
| | 1397 | }; |
| | 1398 | |
| | 1399 | pub const InStream = struct { |
| | 1400 | fd: os.FileHandle, |
| | 1401 | stream: Stream, |
| | 1402 | loop: *Loop, |
| | 1403 | offset: usize, |
| | 1404 | |
| | 1405 | pub const Error = PReadVError; // TODO make this not have OutOfMemory |
| | 1406 | pub const Stream = event.io.InStream(Error); |
| | 1407 | |
| | 1408 | pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) InStream { |
| | 1409 | return InStream{ |
| | 1410 | .fd = fd, |
| | 1411 | .loop = loop, |
| | 1412 | .offset = offset, |
| | 1413 | .stream = Stream{ .readFn = readFn }, |
| | 1414 | }; |
| | 1415 | } |
| | 1416 | |
| | 1417 | async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize { |
| | 1418 | const self = @fieldParentPtr(InStream, "stream", in_stream); |
| | 1419 | const amt = try await (async preadv(self.loop, self.fd, [][]u8{bytes}, self.offset) catch unreachable); |
| | 1420 | self.offset += amt; |
| | 1421 | return amt; |
| | 1422 | } |
| | 1423 | }; |