| author | |
| committer | |
| log | fd50a6896bc12af66caaa0da34e19adb3481b404 |
| tree | 206ce1a5a4ec975b3d2fb8fa6c61d350c93cee6c |
| parent | 2c9ed664dd771ebb96f02ede84dd1ce7b6d58e44 |
The file I/O stuff is working, but the fs watching
stuff is not yet.5 files changed, 239 insertions(+), 78 deletions(-)
std/c/index.zig+2| ... | ... | @@ -21,8 +21,10 @@ pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize; |
| 21 | 21 | pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int; |
| 22 | 22 | pub extern "c" fn raise(sig: c_int) c_int; |
| 23 | 23 | pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize; |
| 24 | pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize; | |
| 24 | 25 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; |
| 25 | 26 | pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize; |
| 27 | pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize; | |
| 26 | 28 | pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void; |
| 27 | 29 | pub extern "c" fn munmap(addr: *c_void, len: usize) c_int; |
| 28 | 30 | pub extern "c" fn unlink(path: [*]const u8) c_int; |
std/event/fs.zig+12-12| ... | ... | @@ -27,7 +27,7 @@ pub const Request = struct { |
| 27 | 27 | |
| 28 | 28 | pub const PWriteV = struct { |
| 29 | 29 | fd: os.FileHandle, |
| 30 | iov: []os.linux.iovec_const, | |
| 30 | iov: []os.posix.iovec_const, | |
| 31 | 31 | offset: usize, |
| 32 | 32 | result: Error!void, |
| 33 | 33 | |
| ... | ... | @@ -36,7 +36,7 @@ pub const Request = struct { |
| 36 | 36 | |
| 37 | 37 | pub const PReadV = struct { |
| 38 | 38 | fd: os.FileHandle, |
| 39 | iov: []os.linux.iovec, | |
| 39 | iov: []os.posix.iovec, | |
| 40 | 40 | offset: usize, |
| 41 | 41 | result: Error!usize, |
| 42 | 42 | |
| ... | ... | @@ -83,11 +83,11 @@ pub async fn pwritev(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: |
| 83 | 83 | resume @handle(); |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | const iovecs = try loop.allocator.alloc(os.linux.iovec_const, data.len); | |
| 86 | const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); | |
| 87 | 87 | defer loop.allocator.free(iovecs); |
| 88 | 88 | |
| 89 | 89 | for (data) |buf, i| { |
| 90 | iovecs[i] = os.linux.iovec_const{ | |
| 90 | iovecs[i] = os.posix.iovec_const{ | |
| 91 | 91 | .iov_base = buf.ptr, |
| 92 | 92 | .iov_len = buf.len, |
| 93 | 93 | }; |
| ... | ... | @@ -116,7 +116,7 @@ pub async fn pwritev(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: |
| 116 | 116 | }; |
| 117 | 117 | |
| 118 | 118 | suspend { |
| 119 | loop.linuxFsRequest(&req_node); | |
| 119 | loop.posixFsRequest(&req_node); | |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | return req_node.data.msg.PWriteV.result; |
| ... | ... | @@ -132,11 +132,11 @@ pub async fn preadv(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: [ |
| 132 | 132 | resume @handle(); |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | const iovecs = try loop.allocator.alloc(os.linux.iovec, data.len); | |
| 135 | const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); | |
| 136 | 136 | defer loop.allocator.free(iovecs); |
| 137 | 137 | |
| 138 | 138 | for (data) |buf, i| { |
| 139 | iovecs[i] = os.linux.iovec{ | |
| 139 | iovecs[i] = os.posix.iovec{ | |
| 140 | 140 | .iov_base = buf.ptr, |
| 141 | 141 | .iov_len = buf.len, |
| 142 | 142 | }; |
| ... | ... | @@ -165,7 +165,7 @@ pub async fn preadv(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: [ |
| 165 | 165 | }; |
| 166 | 166 | |
| 167 | 167 | suspend { |
| 168 | loop.linuxFsRequest(&req_node); | |
| 168 | loop.posixFsRequest(&req_node); | |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | 171 | return req_node.data.msg.PReadV.result; |
| ... | ... | @@ -201,7 +201,7 @@ pub async fn openRead(loop: *event.Loop, path: []const u8) os.File.OpenError!os. |
| 201 | 201 | }; |
| 202 | 202 | |
| 203 | 203 | suspend { |
| 204 | loop.linuxFsRequest(&req_node); | |
| 204 | loop.posixFsRequest(&req_node); | |
| 205 | 205 | } |
| 206 | 206 | |
| 207 | 207 | return req_node.data.msg.OpenRead.result; |
| ... | ... | @@ -243,7 +243,7 @@ pub async fn openReadWrite( |
| 243 | 243 | }; |
| 244 | 244 | |
| 245 | 245 | suspend { |
| 246 | loop.linuxFsRequest(&req_node); | |
| 246 | loop.posixFsRequest(&req_node); | |
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | return req_node.data.msg.OpenRW.result; |
| ... | ... | @@ -280,7 +280,7 @@ pub const CloseOperation = struct { |
| 280 | 280 | /// Defer this after creating. |
| 281 | 281 | pub fn deinit(self: *CloseOperation) void { |
| 282 | 282 | if (self.have_fd) { |
| 283 | self.loop.linuxFsRequest(&self.close_req_node); | |
| 283 | self.loop.posixFsRequest(&self.close_req_node); | |
| 284 | 284 | } else { |
| 285 | 285 | self.loop.allocator.destroy(self); |
| 286 | 286 | } |
| ... | ... | @@ -330,7 +330,7 @@ pub async fn writeFileMode(loop: *event.Loop, path: []const u8, contents: []cons |
| 330 | 330 | }; |
| 331 | 331 | |
| 332 | 332 | suspend { |
| 333 | loop.linuxFsRequest(&req_node); | |
| 333 | loop.posixFsRequest(&req_node); | |
| 334 | 334 | } |
| 335 | 335 | |
| 336 | 336 | return req_node.data.msg.WriteFile.result; |
std/event/loop.zig+99-31| ... | ... | @@ -127,11 +127,6 @@ pub const Loop = struct { |
| 127 | 127 | .finish = fs.Request.Finish.NoAction, |
| 128 | 128 | }, |
| 129 | 129 | }; |
| 130 | self.os_data.fs_thread = try os.spawnThread(self, linuxFsRun); | |
| 131 | errdefer { | |
| 132 | self.linuxFsRequest(&self.os_data.fs_end_request); | |
| 133 | self.os_data.fs_thread.wait(); | |
| 134 | } | |
| 135 | 130 | |
| 136 | 131 | errdefer { |
| 137 | 132 | while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd); |
| ... | ... | @@ -168,6 +163,12 @@ pub const Loop = struct { |
| 168 | 163 | &self.os_data.final_eventfd_event, |
| 169 | 164 | ); |
| 170 | 165 | |
| 166 | self.os_data.fs_thread = try os.spawnThread(self, posixFsRun); | |
| 167 | errdefer { | |
| 168 | self.posixFsRequest(&self.os_data.fs_end_request); | |
| 169 | self.os_data.fs_thread.wait(); | |
| 170 | } | |
| 171 | ||
| 171 | 172 | var extra_thread_index: usize = 0; |
| 172 | 173 | errdefer { |
| 173 | 174 | // writing 8 bytes to an eventfd cannot fail |
| ... | ... | @@ -185,10 +186,25 @@ pub const Loop = struct { |
| 185 | 186 | self.os_data.kqfd = try os.bsdKQueue(); |
| 186 | 187 | errdefer os.close(self.os_data.kqfd); |
| 187 | 188 | |
| 189 | self.os_data.fs_kqfd = try os.bsdKQueue(); | |
| 190 | errdefer os.close(self.os_data.fs_kqfd); | |
| 191 | ||
| 192 | self.os_data.fs_queue = std.atomic.Queue(fs.Request).init(); | |
| 193 | // we need another thread for the file system because Darwin does not have an async | |
| 194 | // file system I/O API. | |
| 195 | self.os_data.fs_end_request = fs.RequestNode{ | |
| 196 | .prev = undefined, | |
| 197 | .next = undefined, | |
| 198 | .data = fs.Request{ | |
| 199 | .msg = fs.Request.Msg.End, | |
| 200 | .finish = fs.Request.Finish.NoAction, | |
| 201 | }, | |
| 202 | }; | |
| 203 | ||
| 188 | 204 | self.os_data.kevents = try self.allocator.alloc(posix.Kevent, extra_thread_count); |
| 189 | 205 | errdefer self.allocator.free(self.os_data.kevents); |
| 190 | 206 | |
| 191 | const eventlist = ([*]posix.Kevent)(undefined)[0..0]; | |
| 207 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; | |
| 192 | 208 | |
| 193 | 209 | for (self.eventfd_resume_nodes) |*eventfd_node, i| { |
| 194 | 210 | eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{ |
| ... | ... | @@ -207,12 +223,11 @@ pub const Loop = struct { |
| 207 | 223 | .udata = @ptrToInt(&eventfd_node.data.base), |
| 208 | 224 | }, |
| 209 | 225 | }, |
| 210 | .prev = undefined, | |
| 211 | 226 | .next = undefined, |
| 212 | 227 | }; |
| 213 | 228 | self.available_eventfd_resume_nodes.push(eventfd_node); |
| 214 | 229 | const kevent_array = (*[1]posix.Kevent)(&eventfd_node.data.kevent); |
| 215 | _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null); | |
| 230 | _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null); | |
| 216 | 231 | eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE; |
| 217 | 232 | eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER; |
| 218 | 233 | // this one is for waiting for events |
| ... | ... | @@ -236,14 +251,38 @@ pub const Loop = struct { |
| 236 | 251 | .data = 0, |
| 237 | 252 | .udata = @ptrToInt(&self.final_resume_node), |
| 238 | 253 | }; |
| 239 | const kevent_array = (*[1]posix.Kevent)(&self.os_data.final_kevent); | |
| 240 | _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null); | |
| 254 | const final_kev_arr = (*[1]posix.Kevent)(&self.os_data.final_kevent); | |
| 255 | _ = try os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null); | |
| 241 | 256 | self.os_data.final_kevent.flags = posix.EV_ENABLE; |
| 242 | 257 | self.os_data.final_kevent.fflags = posix.NOTE_TRIGGER; |
| 243 | 258 | |
| 259 | self.os_data.fs_kevent_wake = posix.Kevent{ | |
| 260 | .ident = extra_thread_count + 1, | |
| 261 | .filter = posix.EVFILT_USER, | |
| 262 | .flags = posix.EV_ADD, | |
| 263 | .fflags = posix.NOTE_TRIGGER, | |
| 264 | .data = 0, | |
| 265 | .udata = undefined, | |
| 266 | }; | |
| 267 | ||
| 268 | self.os_data.fs_kevent_wait = posix.Kevent{ | |
| 269 | .ident = extra_thread_count + 1, | |
| 270 | .filter = posix.EVFILT_USER, | |
| 271 | .flags = posix.EV_ADD|posix.EV_CLEAR, | |
| 272 | .fflags = 0, | |
| 273 | .data = 0, | |
| 274 | .udata = undefined, | |
| 275 | }; | |
| 276 | ||
| 277 | self.os_data.fs_thread = try os.spawnThread(self, posixFsRun); | |
| 278 | errdefer { | |
| 279 | self.posixFsRequest(&self.os_data.fs_end_request); | |
| 280 | self.os_data.fs_thread.wait(); | |
| 281 | } | |
| 282 | ||
| 244 | 283 | var extra_thread_index: usize = 0; |
| 245 | 284 | errdefer { |
| 246 | _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null) catch unreachable; | |
| 285 | _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable; | |
| 247 | 286 | while (extra_thread_index != 0) { |
| 248 | 287 | extra_thread_index -= 1; |
| 249 | 288 | self.extra_threads[extra_thread_index].wait(); |
| ... | ... | @@ -312,6 +351,7 @@ pub const Loop = struct { |
| 312 | 351 | builtin.Os.macosx => { |
| 313 | 352 | self.allocator.free(self.os_data.kevents); |
| 314 | 353 | os.close(self.os_data.kqfd); |
| 354 | os.close(self.os_data.fs_kqfd); | |
| 315 | 355 | }, |
| 316 | 356 | builtin.Os.windows => { |
| 317 | 357 | os.close(self.os_data.io_port); |
| ... | ... | @@ -375,8 +415,8 @@ pub const Loop = struct { |
| 375 | 415 | switch (builtin.os) { |
| 376 | 416 | builtin.Os.macosx => { |
| 377 | 417 | const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); |
| 378 | const eventlist = ([*]posix.Kevent)(undefined)[0..0]; | |
| 379 | _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null) catch { | |
| 418 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; | |
| 419 | _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { | |
| 380 | 420 | self.next_tick_queue.unget(next_tick_node); |
| 381 | 421 | self.available_eventfd_resume_nodes.push(resume_stack_node); |
| 382 | 422 | return; |
| ... | ... | @@ -493,16 +533,17 @@ pub const Loop = struct { |
| 493 | 533 | // cause all the threads to stop |
| 494 | 534 | switch (builtin.os) { |
| 495 | 535 | builtin.Os.linux => { |
| 496 | self.linuxFsRequest(&self.os_data.fs_end_request); | |
| 536 | self.posixFsRequest(&self.os_data.fs_end_request); | |
| 497 | 537 | // writing 8 bytes to an eventfd cannot fail |
| 498 | 538 | os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; |
| 499 | 539 | return; |
| 500 | 540 | }, |
| 501 | 541 | builtin.Os.macosx => { |
| 542 | self.posixFsRequest(&self.os_data.fs_end_request); | |
| 502 | 543 | const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent); |
| 503 | const eventlist = ([*]posix.Kevent)(undefined)[0..0]; | |
| 544 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; | |
| 504 | 545 | // cannot fail because we already added it and this just enables it |
| 505 | _ = os.bsdKEvent(self.os_data.kqfd, final_kevent, eventlist, null) catch unreachable; | |
| 546 | _ = os.bsdKEvent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable; | |
| 506 | 547 | return; |
| 507 | 548 | }, |
| 508 | 549 | builtin.Os.windows => { |
| ... | ... | @@ -576,6 +617,7 @@ pub const Loop = struct { |
| 576 | 617 | self.finishOneEvent(); |
| 577 | 618 | } |
| 578 | 619 | } |
| 620 | break; | |
| 579 | 621 | }, |
| 580 | 622 | builtin.Os.windows => { |
| 581 | 623 | var completion_key: usize = undefined; |
| ... | ... | @@ -610,19 +652,29 @@ pub const Loop = struct { |
| 610 | 652 | } |
| 611 | 653 | } |
| 612 | 654 | |
| 613 | fn linuxFsRequest(self: *Loop, request_node: *fs.RequestNode) void { | |
| 614 | self.beginOneEvent(); // finished in linuxFsRun after processing the msg | |
| 655 | fn posixFsRequest(self: *Loop, request_node: *fs.RequestNode) void { | |
| 656 | self.beginOneEvent(); // finished in posixFsRun after processing the msg | |
| 615 | 657 | self.os_data.fs_queue.put(request_node); |
| 616 | _ = @atomicRmw(i32, &self.os_data.fs_queue_len, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst); // let this wrap | |
| 617 | const rc = os.linux.futex_wake(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAKE, 1); | |
| 618 | switch (os.linux.getErrno(rc)) { | |
| 619 | 0 => {}, | |
| 620 | posix.EINVAL => unreachable, | |
| 621 | else => unreachable, | |
| 658 | switch (builtin.os) { | |
| 659 | builtin.Os.macosx => { | |
| 660 | const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake); | |
| 661 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; | |
| 662 | _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable; | |
| 663 | }, | |
| 664 | builtin.Os.linux => { | |
| 665 | _ = @atomicRmw(i32, &self.os_data.fs_queue_len, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst); // let this wrap | |
| 666 | const rc = os.linux.futex_wake(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAKE, 1); | |
| 667 | switch (os.linux.getErrno(rc)) { | |
| 668 | 0 => {}, | |
| 669 | posix.EINVAL => unreachable, | |
| 670 | else => unreachable, | |
| 671 | } | |
| 672 | }, | |
| 673 | else => @compileError("Unsupported OS"), | |
| 622 | 674 | } |
| 623 | 675 | } |
| 624 | 676 | |
| 625 | fn linuxFsRun(self: *Loop) void { | |
| 677 | fn posixFsRun(self: *Loop) void { | |
| 626 | 678 | var processed_count: i32 = 0; // we let this wrap |
| 627 | 679 | while (true) { |
| 628 | 680 | while (self.os_data.fs_queue.get()) |node| { |
| ... | ... | @@ -664,12 +716,22 @@ pub const Loop = struct { |
| 664 | 716 | } |
| 665 | 717 | self.finishOneEvent(); |
| 666 | 718 | } |
| 667 | const rc = os.linux.futex_wait(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAIT, processed_count, null); | |
| 668 | switch (os.linux.getErrno(rc)) { | |
| 669 | 0 => continue, | |
| 670 | posix.EINTR => continue, | |
| 671 | posix.EAGAIN => continue, | |
| 672 | else => unreachable, | |
| 719 | switch (builtin.os) { | |
| 720 | builtin.Os.linux => { | |
| 721 | const rc = os.linux.futex_wait(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAIT, processed_count, null); | |
| 722 | switch (os.linux.getErrno(rc)) { | |
| 723 | 0 => continue, | |
| 724 | posix.EINTR => continue, | |
| 725 | posix.EAGAIN => continue, | |
| 726 | else => unreachable, | |
| 727 | } | |
| 728 | }, | |
| 729 | builtin.Os.macosx => { | |
| 730 | const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait); | |
| 731 | var out_kevs: [1]posix.Kevent = undefined; | |
| 732 | _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable; | |
| 733 | }, | |
| 734 | else => @compileError("Unsupported OS"), | |
| 673 | 735 | } |
| 674 | 736 | } |
| 675 | 737 | } |
| ... | ... | @@ -696,6 +758,12 @@ pub const Loop = struct { |
| 696 | 758 | kqfd: i32, |
| 697 | 759 | final_kevent: posix.Kevent, |
| 698 | 760 | kevents: []posix.Kevent, |
| 761 | fs_kevent_wake: posix.Kevent, | |
| 762 | fs_kevent_wait: posix.Kevent, | |
| 763 | fs_thread: *os.Thread, | |
| 764 | fs_kqfd: i32, | |
| 765 | fs_queue: std.atomic.Queue(fs.Request), | |
| 766 | fs_end_request: fs.RequestNode, | |
| 699 | 767 | }; |
| 700 | 768 | }; |
| 701 | 769 |
std/os/darwin.zig+8| ... | ... | @@ -646,6 +646,10 @@ pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { |
| 646 | 646 | return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); |
| 647 | 647 | } |
| 648 | 648 | |
| 649 | pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize { | |
| 650 | return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset)); | |
| 651 | } | |
| 652 | ||
| 649 | 653 | pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { |
| 650 | 654 | return errnoWrap(c.stat(path, buf)); |
| 651 | 655 | } |
| ... | ... | @@ -654,6 +658,10 @@ pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { |
| 654 | 658 | return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); |
| 655 | 659 | } |
| 656 | 660 | |
| 661 | pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize { | |
| 662 | return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset)); | |
| 663 | } | |
| 664 | ||
| 657 | 665 | pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { |
| 658 | 666 | const ptr_result = c.mmap( |
| 659 | 667 | @ptrCast(*c_void, address), |
std/os/index.zig+118-35| ... | ... | @@ -246,23 +246,64 @@ pub fn posixRead(fd: i32, buf: []u8) !void { |
| 246 | 246 | } |
| 247 | 247 | } |
| 248 | 248 | |
| 249 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. | |
| 249 | 250 | pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) !usize { |
| 250 | while (true) { | |
| 251 | const rc = posix.preadv(fd, iov, count, offset); | |
| 252 | const err = posix.getErrno(rc); | |
| 253 | switch (err) { | |
| 254 | 0 => return rc, | |
| 255 | posix.EINTR => continue, | |
| 256 | posix.EINVAL => unreachable, | |
| 257 | posix.EFAULT => unreachable, | |
| 258 | posix.EAGAIN => return error.WouldBlock, | |
| 259 | posix.EBADF => return error.FileClosed, | |
| 260 | posix.EIO => return error.InputOutput, | |
| 261 | posix.EISDIR => return error.IsDir, | |
| 262 | posix.ENOBUFS => return error.SystemResources, | |
| 263 | posix.ENOMEM => return error.SystemResources, | |
| 264 | else => return unexpectedErrorPosix(err), | |
| 265 | } | |
| 251 | switch (builtin.os) { | |
| 252 | builtin.Os.macosx => { | |
| 253 | // Darwin does not have preadv but it does have pread. | |
| 254 | var off: usize = 0; | |
| 255 | var iov_i: usize = 0; | |
| 256 | var inner_off: usize = 0; | |
| 257 | while (true) { | |
| 258 | const v = iov[iov_i]; | |
| 259 | const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off); | |
| 260 | const err = darwin.getErrno(rc); | |
| 261 | switch (err) { | |
| 262 | 0 => { | |
| 263 | off += rc; | |
| 264 | inner_off += rc; | |
| 265 | if (inner_off == v.iov_len) { | |
| 266 | iov_i += 1; | |
| 267 | inner_off = 0; | |
| 268 | if (iov_i == count) { | |
| 269 | return off; | |
| 270 | } | |
| 271 | } | |
| 272 | if (rc == 0) return off; // EOF | |
| 273 | continue; | |
| 274 | }, | |
| 275 | posix.EINTR => continue, | |
| 276 | posix.EINVAL => unreachable, | |
| 277 | posix.EFAULT => unreachable, | |
| 278 | posix.ESPIPE => unreachable, // fd is not seekable | |
| 279 | posix.EAGAIN => return error.WouldBlock, | |
| 280 | posix.EBADF => return error.FileClosed, | |
| 281 | posix.EIO => return error.InputOutput, | |
| 282 | posix.EISDIR => return error.IsDir, | |
| 283 | posix.ENOBUFS => return error.SystemResources, | |
| 284 | posix.ENOMEM => return error.SystemResources, | |
| 285 | else => return unexpectedErrorPosix(err), | |
| 286 | } | |
| 287 | } | |
| 288 | }, | |
| 289 | builtin.Os.linux, builtin.Os.freebsd => while (true) { | |
| 290 | const rc = posix.preadv(fd, iov, count, offset); | |
| 291 | const err = posix.getErrno(rc); | |
| 292 | switch (err) { | |
| 293 | 0 => return rc, | |
| 294 | posix.EINTR => continue, | |
| 295 | posix.EINVAL => unreachable, | |
| 296 | posix.EFAULT => unreachable, | |
| 297 | posix.EAGAIN => return error.WouldBlock, | |
| 298 | posix.EBADF => return error.FileClosed, | |
| 299 | posix.EIO => return error.InputOutput, | |
| 300 | posix.EISDIR => return error.IsDir, | |
| 301 | posix.ENOBUFS => return error.SystemResources, | |
| 302 | posix.ENOMEM => return error.SystemResources, | |
| 303 | else => return unexpectedErrorPosix(err), | |
| 304 | } | |
| 305 | }, | |
| 306 | else => @compileError("Unsupported OS"), | |
| 266 | 307 | } |
| 267 | 308 | } |
| 268 | 309 | |
| ... | ... | @@ -311,25 +352,67 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 311 | 352 | } |
| 312 | 353 | |
| 313 | 354 | pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void { |
| 314 | while (true) { | |
| 315 | const rc = posix.pwritev(fd, iov, count, offset); | |
| 316 | const err = posix.getErrno(rc); | |
| 317 | switch (err) { | |
| 318 | 0 => return, | |
| 319 | posix.EINTR => continue, | |
| 320 | posix.EINVAL => unreachable, | |
| 321 | posix.EFAULT => unreachable, | |
| 322 | posix.EAGAIN => return PosixWriteError.WouldBlock, | |
| 323 | posix.EBADF => return PosixWriteError.FileClosed, | |
| 324 | posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, | |
| 325 | posix.EDQUOT => return PosixWriteError.DiskQuota, | |
| 326 | posix.EFBIG => return PosixWriteError.FileTooBig, | |
| 327 | posix.EIO => return PosixWriteError.InputOutput, | |
| 328 | posix.ENOSPC => return PosixWriteError.NoSpaceLeft, | |
| 329 | posix.EPERM => return PosixWriteError.AccessDenied, | |
| 330 | posix.EPIPE => return PosixWriteError.BrokenPipe, | |
| 331 | else => return unexpectedErrorPosix(err), | |
| 332 | } | |
| 355 | switch (builtin.os) { | |
| 356 | builtin.Os.macosx => { | |
| 357 | // Darwin does not have pwritev but it does have pwrite. | |
| 358 | var off: usize = 0; | |
| 359 | var iov_i: usize = 0; | |
| 360 | var inner_off: usize = 0; | |
| 361 | while (true) { | |
| 362 | const v = iov[iov_i]; | |
| 363 | const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off); | |
| 364 | const err = darwin.getErrno(rc); | |
| 365 | switch (err) { | |
| 366 | 0 => { | |
| 367 | off += rc; | |
| 368 | inner_off += rc; | |
| 369 | if (inner_off == v.iov_len) { | |
| 370 | iov_i += 1; | |
| 371 | inner_off = 0; | |
| 372 | if (iov_i == count) { | |
| 373 | return; | |
| 374 | } | |
| 375 | } | |
| 376 | continue; | |
| 377 | }, | |
| 378 | posix.EINTR => continue, | |
| 379 | posix.ESPIPE => unreachable, // fd is not seekable | |
| 380 | posix.EINVAL => unreachable, | |
| 381 | posix.EFAULT => unreachable, | |
| 382 | posix.EAGAIN => return PosixWriteError.WouldBlock, | |
| 383 | posix.EBADF => return PosixWriteError.FileClosed, | |
| 384 | posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, | |
| 385 | posix.EDQUOT => return PosixWriteError.DiskQuota, | |
| 386 | posix.EFBIG => return PosixWriteError.FileTooBig, | |
| 387 | posix.EIO => return PosixWriteError.InputOutput, | |
| 388 | posix.ENOSPC => return PosixWriteError.NoSpaceLeft, | |
| 389 | posix.EPERM => return PosixWriteError.AccessDenied, | |
| 390 | posix.EPIPE => return PosixWriteError.BrokenPipe, | |
| 391 | else => return unexpectedErrorPosix(err), | |
| 392 | } | |
| 393 | } | |
| 394 | }, | |
| 395 | builtin.Os.linux => while (true) { | |
| 396 | const rc = posix.pwritev(fd, iov, count, offset); | |
| 397 | const err = posix.getErrno(rc); | |
| 398 | switch (err) { | |
| 399 | 0 => return, | |
| 400 | posix.EINTR => continue, | |
| 401 | posix.EINVAL => unreachable, | |
| 402 | posix.EFAULT => unreachable, | |
| 403 | posix.EAGAIN => return PosixWriteError.WouldBlock, | |
| 404 | posix.EBADF => return PosixWriteError.FileClosed, | |
| 405 | posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, | |
| 406 | posix.EDQUOT => return PosixWriteError.DiskQuota, | |
| 407 | posix.EFBIG => return PosixWriteError.FileTooBig, | |
| 408 | posix.EIO => return PosixWriteError.InputOutput, | |
| 409 | posix.ENOSPC => return PosixWriteError.NoSpaceLeft, | |
| 410 | posix.EPERM => return PosixWriteError.AccessDenied, | |
| 411 | posix.EPIPE => return PosixWriteError.BrokenPipe, | |
| 412 | else => return unexpectedErrorPosix(err), | |
| 413 | } | |
| 414 | }, | |
| 415 | else => @compileError("Unsupported OS"), | |
| 333 | 416 | } |
| 334 | 417 | } |
| 335 | 418 |