authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-07 00:49:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-07 00:49:09-04:00
logfd50a6896bc12af66caaa0da34e19adb3481b404
tree206ce1a5a4ec975b3d2fb8fa6c61d350c93cee6c
parent2c9ed664dd771ebb96f02ede84dd1ce7b6d58e44

std.event.fs support for macos

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;
21pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;21pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
22pub extern "c" fn raise(sig: c_int) c_int;22pub extern "c" fn raise(sig: c_int) c_int;
23pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;23pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
24pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
24pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;25pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
25pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;26pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
27pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
26pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;28pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
27pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;29pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
28pub extern "c" fn unlink(path: [*]const u8) c_int;30pub 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 {
2727
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,
3333
...@@ -36,7 +36,7 @@ pub const Request = struct {...@@ -36,7 +36,7 @@ pub const Request = struct {
3636
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,
4242
...@@ -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 }
8585
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);
8888
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 };
117117
118 suspend {118 suspend {
119 loop.linuxFsRequest(&req_node);119 loop.posixFsRequest(&req_node);
120 }120 }
121121
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 }
134134
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);
137137
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 };
166166
167 suspend {167 suspend {
168 loop.linuxFsRequest(&req_node);168 loop.posixFsRequest(&req_node);
169 }169 }
170170
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 };
202202
203 suspend {203 suspend {
204 loop.linuxFsRequest(&req_node);204 loop.posixFsRequest(&req_node);
205 }205 }
206206
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 };
244244
245 suspend {245 suspend {
246 loop.linuxFsRequest(&req_node);246 loop.posixFsRequest(&req_node);
247 }247 }
248248
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 };
331331
332 suspend {332 suspend {
333 loop.linuxFsRequest(&req_node);333 loop.posixFsRequest(&req_node);
334 }334 }
335335
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 }
135130
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 );
170165
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 fail174 // 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);
187188
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);
190206
191 const eventlist = ([*]posix.Kevent)(undefined)[0..0];207 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
192208
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 events233 // 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;
243258
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 stop533 // 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 fail537 // 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 it545 // 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 }
612654
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 msg656 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 wrap658 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 }
624676
625 fn linuxFsRun(self: *Loop) void {677 fn posixFsRun(self: *Loop) void {
626 var processed_count: i32 = 0; // we let this wrap678 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};
701769
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}
648648
649pub 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
649pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {653pub 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}
656660
661pub 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
657pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {665pub 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}
248248
249/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
249pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) !usize {250pub 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}
268309
...@@ -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}
312353
313pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {354pub 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}
335418