| 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,8 +21,10 @@ pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize; |
| 21 | pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int; | 21 | pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int; |
| 22 | pub extern "c" fn raise(sig: c_int) c_int; | 22 | pub extern "c" fn raise(sig: c_int) c_int; |
| 23 | pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize; | 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 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; | 25 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; |
| 25 | pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize; | 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 | pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void; | 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 | pub extern "c" fn munmap(addr: *c_void, len: usize) c_int; | 29 | pub extern "c" fn munmap(addr: *c_void, len: usize) c_int; |
| 28 | pub extern "c" fn unlink(path: [*]const u8) c_int; | 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,7 +27,7 @@ pub const Request = struct { |
| 27 | 27 | ||
| 28 | pub const PWriteV = struct { | 28 | pub const PWriteV = struct { |
| 29 | fd: os.FileHandle, | 29 | fd: os.FileHandle, |
| 30 | iov: []os.linux.iovec_const, | 30 | iov: []os.posix.iovec_const, |
| 31 | offset: usize, | 31 | offset: usize, |
| 32 | result: Error!void, | 32 | result: Error!void, |
| 33 | 33 | ||
| ... | @@ -36,7 +36,7 @@ pub const Request = struct { | ... | @@ -36,7 +36,7 @@ pub const Request = struct { |
| 36 | 36 | ||
| 37 | pub const PReadV = struct { | 37 | pub const PReadV = struct { |
| 38 | fd: os.FileHandle, | 38 | fd: os.FileHandle, |
| 39 | iov: []os.linux.iovec, | 39 | iov: []os.posix.iovec, |
| 40 | offset: usize, | 40 | offset: usize, |
| 41 | result: Error!usize, | 41 | result: Error!usize, |
| 42 | 42 | ||
| ... | @@ -83,11 +83,11 @@ pub async fn pwritev(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: | ... | @@ -83,11 +83,11 @@ pub async fn pwritev(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: |
| 83 | resume @handle(); | 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 | defer loop.allocator.free(iovecs); | 87 | defer loop.allocator.free(iovecs); |
| 88 | 88 | ||
| 89 | for (data) |buf, i| { | 89 | for (data) |buf, i| { |
| 90 | iovecs[i] = os.linux.iovec_const{ | 90 | iovecs[i] = os.posix.iovec_const{ |
| 91 | .iov_base = buf.ptr, | 91 | .iov_base = buf.ptr, |
| 92 | .iov_len = buf.len, | 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,7 +116,7 @@ pub async fn pwritev(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: |
| 116 | }; | 116 | }; |
| 117 | 117 | ||
| 118 | suspend { | 118 | suspend { |
| 119 | loop.linuxFsRequest(&req_node); | 119 | loop.posixFsRequest(&req_node); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | return req_node.data.msg.PWriteV.result; | 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,11 +132,11 @@ pub async fn preadv(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: [ |
| 132 | resume @handle(); | 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 | defer loop.allocator.free(iovecs); | 136 | defer loop.allocator.free(iovecs); |
| 137 | 137 | ||
| 138 | for (data) |buf, i| { | 138 | for (data) |buf, i| { |
| 139 | iovecs[i] = os.linux.iovec{ | 139 | iovecs[i] = os.posix.iovec{ |
| 140 | .iov_base = buf.ptr, | 140 | .iov_base = buf.ptr, |
| 141 | .iov_len = buf.len, | 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,7 +165,7 @@ pub async fn preadv(loop: *event.Loop, fd: os.FileHandle, offset: usize, data: [ |
| 165 | }; | 165 | }; |
| 166 | 166 | ||
| 167 | suspend { | 167 | suspend { |
| 168 | loop.linuxFsRequest(&req_node); | 168 | loop.posixFsRequest(&req_node); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | return req_node.data.msg.PReadV.result; | 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,7 +201,7 @@ pub async fn openRead(loop: *event.Loop, path: []const u8) os.File.OpenError!os. |
| 201 | }; | 201 | }; |
| 202 | 202 | ||
| 203 | suspend { | 203 | suspend { |
| 204 | loop.linuxFsRequest(&req_node); | 204 | loop.posixFsRequest(&req_node); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | return req_node.data.msg.OpenRead.result; | 207 | return req_node.data.msg.OpenRead.result; |
| ... | @@ -243,7 +243,7 @@ pub async fn openReadWrite( | ... | @@ -243,7 +243,7 @@ pub async fn openReadWrite( |
| 243 | }; | 243 | }; |
| 244 | 244 | ||
| 245 | suspend { | 245 | suspend { |
| 246 | loop.linuxFsRequest(&req_node); | 246 | loop.posixFsRequest(&req_node); |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | return req_node.data.msg.OpenRW.result; | 249 | return req_node.data.msg.OpenRW.result; |
| ... | @@ -280,7 +280,7 @@ pub const CloseOperation = struct { | ... | @@ -280,7 +280,7 @@ pub const CloseOperation = struct { |
| 280 | /// Defer this after creating. | 280 | /// Defer this after creating. |
| 281 | pub fn deinit(self: *CloseOperation) void { | 281 | pub fn deinit(self: *CloseOperation) void { |
| 282 | if (self.have_fd) { | 282 | if (self.have_fd) { |
| 283 | self.loop.linuxFsRequest(&self.close_req_node); | 283 | self.loop.posixFsRequest(&self.close_req_node); |
| 284 | } else { | 284 | } else { |
| 285 | self.loop.allocator.destroy(self); | 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,7 +330,7 @@ pub async fn writeFileMode(loop: *event.Loop, path: []const u8, contents: []cons |
| 330 | }; | 330 | }; |
| 331 | 331 | ||
| 332 | suspend { | 332 | suspend { |
| 333 | loop.linuxFsRequest(&req_node); | 333 | loop.posixFsRequest(&req_node); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | return req_node.data.msg.WriteFile.result; | 336 | return req_node.data.msg.WriteFile.result; |
std/event/loop.zig+99-31| ... | @@ -127,11 +127,6 @@ pub const Loop = struct { | ... | @@ -127,11 +127,6 @@ pub const Loop = struct { |
| 127 | .finish = fs.Request.Finish.NoAction, | 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 | errdefer { | 131 | errdefer { |
| 137 | while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd); | 132 | while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd); |
| ... | @@ -168,6 +163,12 @@ pub const Loop = struct { | ... | @@ -168,6 +163,12 @@ pub const Loop = struct { |
| 168 | &self.os_data.final_eventfd_event, | 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 | var extra_thread_index: usize = 0; | 172 | var extra_thread_index: usize = 0; |
| 172 | errdefer { | 173 | errdefer { |
| 173 | // writing 8 bytes to an eventfd cannot fail | 174 | // writing 8 bytes to an eventfd cannot fail |
| ... | @@ -185,10 +186,25 @@ pub const Loop = struct { | ... | @@ -185,10 +186,25 @@ pub const Loop = struct { |
| 185 | self.os_data.kqfd = try os.bsdKQueue(); | 186 | self.os_data.kqfd = try os.bsdKQueue(); |
| 186 | errdefer os.close(self.os_data.kqfd); | 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 | self.os_data.kevents = try self.allocator.alloc(posix.Kevent, extra_thread_count); | 204 | self.os_data.kevents = try self.allocator.alloc(posix.Kevent, extra_thread_count); |
| 189 | errdefer self.allocator.free(self.os_data.kevents); | 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 | for (self.eventfd_resume_nodes) |*eventfd_node, i| { | 209 | for (self.eventfd_resume_nodes) |*eventfd_node, i| { |
| 194 | eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{ | 210 | eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{ |
| ... | @@ -207,12 +223,11 @@ pub const Loop = struct { | ... | @@ -207,12 +223,11 @@ pub const Loop = struct { |
| 207 | .udata = @ptrToInt(&eventfd_node.data.base), | 223 | .udata = @ptrToInt(&eventfd_node.data.base), |
| 208 | }, | 224 | }, |
| 209 | }, | 225 | }, |
| 210 | .prev = undefined, | ||
| 211 | .next = undefined, | 226 | .next = undefined, |
| 212 | }; | 227 | }; |
| 213 | self.available_eventfd_resume_nodes.push(eventfd_node); | 228 | self.available_eventfd_resume_nodes.push(eventfd_node); |
| 214 | const kevent_array = (*[1]posix.Kevent)(&eventfd_node.data.kevent); | 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 | eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE; | 231 | eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE; |
| 217 | eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER; | 232 | eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER; |
| 218 | // this one is for waiting for events | 233 | // this one is for waiting for events |
| ... | @@ -236,14 +251,38 @@ pub const Loop = struct { | ... | @@ -236,14 +251,38 @@ pub const Loop = struct { |
| 236 | .data = 0, | 251 | .data = 0, |
| 237 | .udata = @ptrToInt(&self.final_resume_node), | 252 | .udata = @ptrToInt(&self.final_resume_node), |
| 238 | }; | 253 | }; |
| 239 | const kevent_array = (*[1]posix.Kevent)(&self.os_data.final_kevent); | 254 | const final_kev_arr = (*[1]posix.Kevent)(&self.os_data.final_kevent); |
| 240 | _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null); | 255 | _ = try os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null); |
| 241 | self.os_data.final_kevent.flags = posix.EV_ENABLE; | 256 | self.os_data.final_kevent.flags = posix.EV_ENABLE; |
| 242 | self.os_data.final_kevent.fflags = posix.NOTE_TRIGGER; | 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 | var extra_thread_index: usize = 0; | 283 | var extra_thread_index: usize = 0; |
| 245 | errdefer { | 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 | while (extra_thread_index != 0) { | 286 | while (extra_thread_index != 0) { |
| 248 | extra_thread_index -= 1; | 287 | extra_thread_index -= 1; |
| 249 | self.extra_threads[extra_thread_index].wait(); | 288 | self.extra_threads[extra_thread_index].wait(); |
| ... | @@ -312,6 +351,7 @@ pub const Loop = struct { | ... | @@ -312,6 +351,7 @@ pub const Loop = struct { |
| 312 | builtin.Os.macosx => { | 351 | builtin.Os.macosx => { |
| 313 | self.allocator.free(self.os_data.kevents); | 352 | self.allocator.free(self.os_data.kevents); |
| 314 | os.close(self.os_data.kqfd); | 353 | os.close(self.os_data.kqfd); |
| 354 | os.close(self.os_data.fs_kqfd); | ||
| 315 | }, | 355 | }, |
| 316 | builtin.Os.windows => { | 356 | builtin.Os.windows => { |
| 317 | os.close(self.os_data.io_port); | 357 | os.close(self.os_data.io_port); |
| ... | @@ -375,8 +415,8 @@ pub const Loop = struct { | ... | @@ -375,8 +415,8 @@ pub const Loop = struct { |
| 375 | switch (builtin.os) { | 415 | switch (builtin.os) { |
| 376 | builtin.Os.macosx => { | 416 | builtin.Os.macosx => { |
| 377 | const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); | 417 | const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); |
| 378 | const eventlist = ([*]posix.Kevent)(undefined)[0..0]; | 418 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; |
| 379 | _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null) catch { | 419 | _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { |
| 380 | self.next_tick_queue.unget(next_tick_node); | 420 | self.next_tick_queue.unget(next_tick_node); |
| 381 | self.available_eventfd_resume_nodes.push(resume_stack_node); | 421 | self.available_eventfd_resume_nodes.push(resume_stack_node); |
| 382 | return; | 422 | return; |
| ... | @@ -493,16 +533,17 @@ pub const Loop = struct { | ... | @@ -493,16 +533,17 @@ pub const Loop = struct { |
| 493 | // cause all the threads to stop | 533 | // cause all the threads to stop |
| 494 | switch (builtin.os) { | 534 | switch (builtin.os) { |
| 495 | builtin.Os.linux => { | 535 | builtin.Os.linux => { |
| 496 | self.linuxFsRequest(&self.os_data.fs_end_request); | 536 | self.posixFsRequest(&self.os_data.fs_end_request); |
| 497 | // writing 8 bytes to an eventfd cannot fail | 537 | // writing 8 bytes to an eventfd cannot fail |
| 498 | os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; | 538 | os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; |
| 499 | return; | 539 | return; |
| 500 | }, | 540 | }, |
| 501 | builtin.Os.macosx => { | 541 | builtin.Os.macosx => { |
| 542 | self.posixFsRequest(&self.os_data.fs_end_request); | ||
| 502 | const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent); | 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 | // cannot fail because we already added it and this just enables it | 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 | return; | 547 | return; |
| 507 | }, | 548 | }, |
| 508 | builtin.Os.windows => { | 549 | builtin.Os.windows => { |
| ... | @@ -576,6 +617,7 @@ pub const Loop = struct { | ... | @@ -576,6 +617,7 @@ pub const Loop = struct { |
| 576 | self.finishOneEvent(); | 617 | self.finishOneEvent(); |
| 577 | } | 618 | } |
| 578 | } | 619 | } |
| 620 | break; | ||
| 579 | }, | 621 | }, |
| 580 | builtin.Os.windows => { | 622 | builtin.Os.windows => { |
| 581 | var completion_key: usize = undefined; | 623 | var completion_key: usize = undefined; |
| ... | @@ -610,19 +652,29 @@ pub const Loop = struct { | ... | @@ -610,19 +652,29 @@ pub const Loop = struct { |
| 610 | } | 652 | } |
| 611 | } | 653 | } |
| 612 | 654 | ||
| 613 | fn linuxFsRequest(self: *Loop, request_node: *fs.RequestNode) void { | 655 | fn posixFsRequest(self: *Loop, request_node: *fs.RequestNode) void { |
| 614 | self.beginOneEvent(); // finished in linuxFsRun after processing the msg | 656 | self.beginOneEvent(); // finished in posixFsRun after processing the msg |
| 615 | self.os_data.fs_queue.put(request_node); | 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 | 658 | switch (builtin.os) { |
| 617 | const rc = os.linux.futex_wake(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAKE, 1); | 659 | builtin.Os.macosx => { |
| 618 | switch (os.linux.getErrno(rc)) { | 660 | const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake); |
| 619 | 0 => {}, | 661 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; |
| 620 | posix.EINVAL => unreachable, | 662 | _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable; |
| 621 | else => 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 | var processed_count: i32 = 0; // we let this wrap | 678 | var processed_count: i32 = 0; // we let this wrap |
| 627 | while (true) { | 679 | while (true) { |
| 628 | while (self.os_data.fs_queue.get()) |node| { | 680 | while (self.os_data.fs_queue.get()) |node| { |
| ... | @@ -664,12 +716,22 @@ pub const Loop = struct { | ... | @@ -664,12 +716,22 @@ pub const Loop = struct { |
| 664 | } | 716 | } |
| 665 | self.finishOneEvent(); | 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); | 719 | switch (builtin.os) { |
| 668 | switch (os.linux.getErrno(rc)) { | 720 | builtin.Os.linux => { |
| 669 | 0 => continue, | 721 | const rc = os.linux.futex_wait(@ptrToInt(&self.os_data.fs_queue_len), os.linux.FUTEX_WAIT, processed_count, null); |
| 670 | posix.EINTR => continue, | 722 | switch (os.linux.getErrno(rc)) { |
| 671 | posix.EAGAIN => continue, | 723 | 0 => continue, |
| 672 | else => unreachable, | 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,6 +758,12 @@ pub const Loop = struct { |
| 696 | kqfd: i32, | 758 | kqfd: i32, |
| 697 | final_kevent: posix.Kevent, | 759 | final_kevent: posix.Kevent, |
| 698 | kevents: []posix.Kevent, | 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,6 +646,10 @@ pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { |
| 646 | return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); | 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 | pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { | 653 | pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { |
| 650 | return errnoWrap(c.stat(path, buf)); | 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,6 +658,10 @@ pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { |
| 654 | return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); | 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 | pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { | 665 | pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { |
| 658 | const ptr_result = c.mmap( | 666 | const ptr_result = c.mmap( |
| 659 | @ptrCast(*c_void, address), | 667 | @ptrCast(*c_void, address), |
std/os/index.zig+118-35| ... | @@ -246,23 +246,64 @@ pub fn posixRead(fd: i32, buf: []u8) !void { | ... | @@ -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 | pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) !usize { | 250 | pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) !usize { |
| 250 | while (true) { | 251 | switch (builtin.os) { |
| 251 | const rc = posix.preadv(fd, iov, count, offset); | 252 | builtin.Os.macosx => { |
| 252 | const err = posix.getErrno(rc); | 253 | // Darwin does not have preadv but it does have pread. |
| 253 | switch (err) { | 254 | var off: usize = 0; |
| 254 | 0 => return rc, | 255 | var iov_i: usize = 0; |
| 255 | posix.EINTR => continue, | 256 | var inner_off: usize = 0; |
| 256 | posix.EINVAL => unreachable, | 257 | while (true) { |
| 257 | posix.EFAULT => unreachable, | 258 | const v = iov[iov_i]; |
| 258 | posix.EAGAIN => return error.WouldBlock, | 259 | const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off); |
| 259 | posix.EBADF => return error.FileClosed, | 260 | const err = darwin.getErrno(rc); |
| 260 | posix.EIO => return error.InputOutput, | 261 | switch (err) { |
| 261 | posix.EISDIR => return error.IsDir, | 262 | 0 => { |
| 262 | posix.ENOBUFS => return error.SystemResources, | 263 | off += rc; |
| 263 | posix.ENOMEM => return error.SystemResources, | 264 | inner_off += rc; |
| 264 | else => return unexpectedErrorPosix(err), | 265 | if (inner_off == v.iov_len) { |
| 265 | } | 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,25 +352,67 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 311 | } | 352 | } |
| 312 | 353 | ||
| 313 | pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void { | 354 | pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void { |
| 314 | while (true) { | 355 | switch (builtin.os) { |
| 315 | const rc = posix.pwritev(fd, iov, count, offset); | 356 | builtin.Os.macosx => { |
| 316 | const err = posix.getErrno(rc); | 357 | // Darwin does not have pwritev but it does have pwrite. |
| 317 | switch (err) { | 358 | var off: usize = 0; |
| 318 | 0 => return, | 359 | var iov_i: usize = 0; |
| 319 | posix.EINTR => continue, | 360 | var inner_off: usize = 0; |
| 320 | posix.EINVAL => unreachable, | 361 | while (true) { |
| 321 | posix.EFAULT => unreachable, | 362 | const v = iov[iov_i]; |
| 322 | posix.EAGAIN => return PosixWriteError.WouldBlock, | 363 | const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off); |
| 323 | posix.EBADF => return PosixWriteError.FileClosed, | 364 | const err = darwin.getErrno(rc); |
| 324 | posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, | 365 | switch (err) { |
| 325 | posix.EDQUOT => return PosixWriteError.DiskQuota, | 366 | 0 => { |
| 326 | posix.EFBIG => return PosixWriteError.FileTooBig, | 367 | off += rc; |
| 327 | posix.EIO => return PosixWriteError.InputOutput, | 368 | inner_off += rc; |
| 328 | posix.ENOSPC => return PosixWriteError.NoSpaceLeft, | 369 | if (inner_off == v.iov_len) { |
| 329 | posix.EPERM => return PosixWriteError.AccessDenied, | 370 | iov_i += 1; |
| 330 | posix.EPIPE => return PosixWriteError.BrokenPipe, | 371 | inner_off = 0; |
| 331 | else => return unexpectedErrorPosix(err), | 372 | if (iov_i == count) { |
| 332 | } | 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 |