mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Merge pull request #6412 from kristoff-it/generalize-event-loop
Make os.zig not depend on the event loop
This commit is contained in:
commit
a502604702
@ -721,6 +721,50 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// ------- I/0 APIs -------
|
||||
pub fn accept(
|
||||
self: *Loop,
|
||||
/// This argument is a socket that has been created with `socket`, bound to a local address
|
||||
/// with `bind`, and is listening for connections after a `listen`.
|
||||
sockfd: os.fd_t,
|
||||
/// This argument is a pointer to a sockaddr structure. This structure is filled in with the
|
||||
/// address of the peer socket, as known to the communications layer. The exact format of the
|
||||
/// address returned addr is determined by the socket's address family (see `socket` and the
|
||||
/// respective protocol man pages).
|
||||
addr: *os.sockaddr,
|
||||
/// This argument is a value-result argument: the caller must initialize it to contain the
|
||||
/// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
|
||||
/// of the peer address.
|
||||
///
|
||||
/// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
|
||||
/// will return a value greater than was supplied to the call.
|
||||
addr_size: *os.socklen_t,
|
||||
/// The following values can be bitwise ORed in flags to obtain different behavior:
|
||||
/// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
|
||||
/// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
|
||||
flags: u32,
|
||||
) os.AcceptError!os.fd_t {
|
||||
while (true) {
|
||||
return os.accept(sockfd, addr, addr_size, flags | os.SOCK_NONBLOCK) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(self: *Loop, sockfd: os.socket_t, sock_addr: *const os.sockaddr, len: os.socklen_t) os.ConnectError!void {
|
||||
os.connect(sockfd, sock_addr, len) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(sockfd);
|
||||
return os.getsockoptError(sockfd);
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
|
||||
/// Performs an async `os.open` using a separate thread.
|
||||
pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {
|
||||
var req_node = Request.Node{
|
||||
@ -779,152 +823,309 @@ pub const Loop = struct {
|
||||
|
||||
/// Performs an async `os.read` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn read(self: *Loop, fd: os.fd_t, buf: []u8) os.ReadError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.read = .{
|
||||
.fd = fd,
|
||||
.buf = buf,
|
||||
.result = undefined,
|
||||
pub fn read(self: *Loop, fd: os.fd_t, buf: []u8, simulate_evented: bool) os.ReadError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.read = .{
|
||||
.fd = fd,
|
||||
.buf = buf,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.read.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.read(fd, buf) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.read.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.readv` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec) os.ReadError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.readv = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.result = undefined,
|
||||
pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, simulate_evented: bool) os.ReadError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.readv = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.readv.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.readv(fd, iov) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.readv.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.pread` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64) os.PReadError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.pread = .{
|
||||
.fd = fd,
|
||||
.buf = buf,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64, simulate_evented: bool) os.PReadError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.pread = .{
|
||||
.fd = fd,
|
||||
.buf = buf,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.pread.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.pread(fd, buf, offset) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.pread.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.preadv` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64) os.ReadError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.preadv = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64, simulate_evented: bool) os.ReadError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.preadv = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.preadv.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.preadv(fd, iov, offset) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.preadv.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.write` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8) os.WriteError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.write = .{
|
||||
.fd = fd,
|
||||
.bytes = bytes,
|
||||
.result = undefined,
|
||||
pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8, simulate_evented: bool) os.WriteError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.write = .{
|
||||
.fd = fd,
|
||||
.bytes = bytes,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.write.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.write(fd, bytes) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.write.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.writev` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const) os.WriteError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.writev = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.result = undefined,
|
||||
pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, simulate_evented: bool) os.WriteError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.writev = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.writev.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.writev(fd, iov) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs an async `os.pwrite` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn pwrite(self: *Loop, fd: os.fd_t, bytes: []const u8, offset: u64, simulate_evented: bool) os.PerformsWriteError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.pwrite = .{
|
||||
.fd = fd,
|
||||
.bytes = bytes,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.pwrite.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.pwrite(fd, bytes, offset) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
return req_node.data.msg.writev.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.pwritev` using a separate thread.
|
||||
/// `fd` must block and not return EAGAIN.
|
||||
pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64) os.WriteError!usize {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.pwritev = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64, simulate_evented: bool) os.PWriteError!usize {
|
||||
if (simulate_evented) {
|
||||
var req_node = Request.Node{
|
||||
.data = .{
|
||||
.msg = .{
|
||||
.pwritev = .{
|
||||
.fd = fd,
|
||||
.iov = iov,
|
||||
.offset = offset,
|
||||
.result = undefined,
|
||||
},
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
.finish = .{ .TickNode = .{ .data = @frame() } },
|
||||
},
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
};
|
||||
suspend {
|
||||
self.posixFsRequest(&req_node);
|
||||
}
|
||||
return req_node.data.msg.pwritev.result;
|
||||
} else {
|
||||
while (true) {
|
||||
return os.pwritev(fd, iov, offset) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sendto(
|
||||
self: *Loop,
|
||||
/// The file descriptor of the sending socket.
|
||||
sockfd: os.fd_t,
|
||||
/// Message to send.
|
||||
buf: []const u8,
|
||||
flags: u32,
|
||||
dest_addr: ?*const os.sockaddr,
|
||||
addrlen: os.socklen_t,
|
||||
) os.SendError!usize {
|
||||
while (true) {
|
||||
return os.sendto(sockfd, buf, flags, dest_addr, addrlen) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdWritable(sockfd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recvfrom(
|
||||
sockfd: os.fd_t,
|
||||
buf: []u8,
|
||||
flags: u32,
|
||||
src_addr: ?*os.sockaddr,
|
||||
addrlen: ?*os.socklen_t,
|
||||
) os.RecvFromError!usize {
|
||||
while (true) {
|
||||
return os.recvfrom(sockfd, buf, flags, src_addr, addrlen) catch |err| switch (err) {
|
||||
error.WouldBlock => {
|
||||
self.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
return req_node.data.msg.pwritev.result;
|
||||
}
|
||||
|
||||
/// Performs an async `os.faccessatZ` using a separate thread.
|
||||
@ -1079,6 +1280,9 @@ pub const Loop = struct {
|
||||
.writev => |*msg| {
|
||||
msg.result = os.writev(msg.fd, msg.iov);
|
||||
},
|
||||
.pwrite => |*msg| {
|
||||
msg.result = os.pwrite(msg.fd, msg.bytes, msg.offset);
|
||||
},
|
||||
.pwritev => |*msg| {
|
||||
msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
|
||||
},
|
||||
@ -1148,6 +1352,7 @@ pub const Loop = struct {
|
||||
readv: ReadV,
|
||||
write: Write,
|
||||
writev: WriteV,
|
||||
pwrite: PWrite,
|
||||
pwritev: PWriteV,
|
||||
pread: PRead,
|
||||
preadv: PReadV,
|
||||
@ -1191,6 +1396,15 @@ pub const Loop = struct {
|
||||
pub const Error = os.WriteError;
|
||||
};
|
||||
|
||||
pub const PWrite = struct {
|
||||
fd: os.fd_t,
|
||||
bytes: []const u8,
|
||||
offset: usize,
|
||||
result: Error!usize,
|
||||
|
||||
pub const Error = os.PWriteError;
|
||||
};
|
||||
|
||||
pub const PWriteV = struct {
|
||||
fd: os.fd_t,
|
||||
iov: []const os.iovec_const,
|
||||
|
||||
@ -414,10 +414,12 @@ pub const File = struct {
|
||||
pub fn read(self: File, buffer: []u8) ReadError!usize {
|
||||
if (is_windows) {
|
||||
return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.read(self.handle, buffer);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.read(self.handle, buffer);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.read(self.handle, buffer, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,10 +438,12 @@ pub const File = struct {
|
||||
pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
|
||||
if (is_windows) {
|
||||
return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.pread(self.handle, buffer, offset);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.pread(self.handle, buffer, offset);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.pread(self.handle, buffer, offset, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,10 +465,12 @@ pub const File = struct {
|
||||
if (iovecs.len == 0) return @as(usize, 0);
|
||||
const first = iovecs[0];
|
||||
return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.readv(self.handle, iovecs);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.readv(self.handle, iovecs);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.readv(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,10 +506,12 @@ pub const File = struct {
|
||||
if (iovecs.len == 0) return @as(usize, 0);
|
||||
const first = iovecs[0];
|
||||
return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.preadv(self.handle, iovecs, offset);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,10 +547,12 @@ pub const File = struct {
|
||||
pub fn write(self: File, bytes: []const u8) WriteError!usize {
|
||||
if (is_windows) {
|
||||
return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.write(self.handle, bytes);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.write(self.handle, bytes);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.write(self.handle, bytes, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,10 +566,12 @@ pub const File = struct {
|
||||
pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
|
||||
if (is_windows) {
|
||||
return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.pwrite(self.handle, bytes, offset);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,10 +588,12 @@ pub const File = struct {
|
||||
if (iovecs.len == 0) return @as(usize, 0);
|
||||
const first = iovecs[0];
|
||||
return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.writev(self.handle, iovecs);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.writev(self.handle, iovecs);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.writev(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,10 +621,12 @@ pub const File = struct {
|
||||
if (iovecs.len == 0) return @as(usize, 0);
|
||||
const first = iovecs[0];
|
||||
return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
|
||||
} else if (self.capable_io_mode != self.intended_io_mode) {
|
||||
return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (self.intended_io_mode == .blocking) {
|
||||
return os.pwritev(self.handle, iovecs, offset);
|
||||
} else {
|
||||
return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -614,11 +614,11 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
|
||||
|
||||
var addr = try std.net.Address.initUnix(path);
|
||||
|
||||
try os.connect(
|
||||
sockfd,
|
||||
&addr.any,
|
||||
addr.getOsSockLen(),
|
||||
);
|
||||
if (std.io.is_async) {
|
||||
try loop.connect(sockfd, &addr.any, addr.getOsSockLen());
|
||||
} else {
|
||||
try os.connect(sockfd, &addr.any, addr.getOsSockLen());
|
||||
}
|
||||
|
||||
return fs.File{
|
||||
.handle = sockfd,
|
||||
@ -677,7 +677,13 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
|
||||
(if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
|
||||
const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
|
||||
errdefer os.close(sockfd);
|
||||
try os.connect(sockfd, &address.any, address.getOsSockLen());
|
||||
|
||||
if (std.io.is_async) {
|
||||
const loop = std.event.Loop.instance orelse return error.WouldBlock;
|
||||
try loop.connect(sockfd, &address.any, address.getOsSockLen());
|
||||
} else {
|
||||
try os.connect(sockfd, &address.any, address.getOsSockLen());
|
||||
}
|
||||
|
||||
return fs.File{ .handle = sockfd };
|
||||
}
|
||||
@ -1429,7 +1435,11 @@ fn resMSendRc(
|
||||
if (answers[i].len == 0) {
|
||||
var j: usize = 0;
|
||||
while (j < ns.len) : (j += 1) {
|
||||
_ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
if (std.io.is_async) {
|
||||
_ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
} else {
|
||||
_ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1444,7 +1454,10 @@ fn resMSendRc(
|
||||
|
||||
while (true) {
|
||||
var sl_copy = sl;
|
||||
const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
|
||||
const rlen = if (std.io.is_async)
|
||||
std.event.Loop.instance.?.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break
|
||||
else
|
||||
os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
|
||||
|
||||
// Ignore non-identifiable packets
|
||||
if (rlen < 4) continue;
|
||||
@ -1470,7 +1483,11 @@ fn resMSendRc(
|
||||
0, 3 => {},
|
||||
2 => if (servfail_retry != 0) {
|
||||
servfail_retry -= 1;
|
||||
_ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
if (std.io.is_async) {
|
||||
_ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
} else {
|
||||
_ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||
}
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
@ -1661,18 +1678,23 @@ pub const StreamServer = struct {
|
||||
|
||||
/// If this function succeeds, the returned `Connection` is a caller-managed resource.
|
||||
pub fn accept(self: *StreamServer) AcceptError!Connection {
|
||||
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
||||
const accept_flags = nonblock | os.SOCK_CLOEXEC;
|
||||
var accepted_addr: Address = undefined;
|
||||
var adr_len: os.socklen_t = @sizeOf(Address);
|
||||
if (os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
|
||||
const accept_result = blk: {
|
||||
if (std.io.is_async) {
|
||||
const loop = std.event.Loop.instance orelse return error.UnexpectedError;
|
||||
break :blk loop.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
|
||||
} else {
|
||||
break :blk os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
|
||||
}
|
||||
};
|
||||
|
||||
if (accept_result) |fd| {
|
||||
return Connection{
|
||||
.file = fs.File{ .handle = fd },
|
||||
.address = accepted_addr,
|
||||
};
|
||||
} else |err| switch (err) {
|
||||
// We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
|
||||
// is handled by os.accept4.
|
||||
error.WouldBlock => unreachable,
|
||||
else => |e| return e,
|
||||
}
|
||||
|
||||
124
lib/std/os.zig
124
lib/std/os.zig
@ -314,8 +314,8 @@ pub const ReadError = error{
|
||||
|
||||
/// Returns the number of bytes that were read, which can be less than
|
||||
/// buf.len. If 0 bytes were read, that means EOF.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
/// If `fd` is opened in non blocking mode, the function will return error.WouldBlock
|
||||
/// when EAGAIN is received.
|
||||
///
|
||||
/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
|
||||
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
|
||||
@ -366,12 +366,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForReading, // Can be a race condition.
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -387,8 +382,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
|
||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
///
|
||||
@ -428,12 +423,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForReading, // can be a race condition
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -450,8 +440,8 @@ pub const PReadError = ReadError || error{Unseekable};
|
||||
///
|
||||
/// Retries when interrupted by a signal.
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
|
||||
@ -492,12 +482,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForReading, // Can be a race condition.
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -586,8 +571,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
|
||||
///
|
||||
/// Retries when interrupted by a signal.
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
///
|
||||
@ -637,12 +622,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForReading, // can be a race condition
|
||||
EIO => return error.InputOutput,
|
||||
EISDIR => return error.IsDir,
|
||||
@ -687,8 +667,8 @@ pub const WriteError = error{
|
||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
///
|
||||
@ -741,12 +721,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForWriting, // can be a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -772,8 +747,8 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
|
||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.k`.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
///
|
||||
@ -814,12 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForWriting, // Can be a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -847,8 +817,8 @@ pub const PWriteError = WriteError || error{Unseekable};
|
||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
||||
///
|
||||
/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
///
|
||||
@ -905,12 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForWriting, // Can be a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -939,8 +904,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
|
||||
/// another write() call to transfer the remaining bytes. The subsequent call will either
|
||||
/// transfer further bytes or may result in an error (e.g., if the disk is now full).
|
||||
///
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
|
||||
/// If `fd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
///
|
||||
/// The following systems do not have this syscall, and will return partial writes if more than one
|
||||
/// vector is provided:
|
||||
@ -993,12 +958,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable,
|
||||
EFAULT => unreachable,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(fd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => return error.NotOpenForWriting, // Can be a race condition.
|
||||
EDESTADDRREQ => unreachable, // `connect` was never called.
|
||||
EDQUOT => return error.DiskQuota,
|
||||
@ -2846,8 +2806,8 @@ pub const AcceptError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Accept a connection on a socket.
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
/// If `sockfd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
pub fn accept(
|
||||
/// This argument is a socket that has been created with `socket`, bound to a local address
|
||||
/// with `bind`, and is listening for connections after a `listen`.
|
||||
@ -2890,12 +2850,7 @@ pub fn accept(
|
||||
return fd;
|
||||
},
|
||||
EINTR => continue,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EBADF => unreachable, // always a race condition
|
||||
ECONNABORTED => return error.ConnectionAborted,
|
||||
EFAULT => unreachable,
|
||||
@ -3081,6 +3036,8 @@ pub const ConnectError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Initiate a connection on a socket.
|
||||
/// If `sockfd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.
|
||||
pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const rc = windows.ws2_32.connect(sockfd, sock_addr, len);
|
||||
@ -3113,11 +3070,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
|
||||
EADDRINUSE => return error.AddressInUse,
|
||||
EADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
EAGAIN, EINPROGRESS => {
|
||||
const loop = std.event.Loop.instance orelse return error.WouldBlock;
|
||||
loop.waitUntilFdWritable(sockfd);
|
||||
return getsockoptError(sockfd);
|
||||
},
|
||||
EAGAIN, EINPROGRESS => return error.WouldBlock,
|
||||
EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
|
||||
EBADF => unreachable, // sockfd is not a valid open file descriptor.
|
||||
ECONNREFUSED => return error.ConnectionRefused,
|
||||
@ -4620,14 +4573,8 @@ pub fn sendto(
|
||||
const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
|
||||
switch (errno(rc)) {
|
||||
0 => return @intCast(usize, rc),
|
||||
|
||||
EACCES => return error.AccessDenied,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdWritable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EALREADY => return error.FastOpenAlreadyInProgress,
|
||||
EBADF => unreachable, // always a race condition
|
||||
ECONNRESET => return error.ConnectionResetByPeer,
|
||||
@ -5106,6 +5053,8 @@ pub const RecvFromError = error{
|
||||
SystemResources,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// If `sockfd` is opened in non blocking mode, the function will
|
||||
/// return error.WouldBlock when EAGAIN is received.
|
||||
pub fn recvfrom(
|
||||
sockfd: fd_t,
|
||||
buf: []u8,
|
||||
@ -5123,12 +5072,7 @@ pub fn recvfrom(
|
||||
ENOTCONN => unreachable,
|
||||
ENOTSOCK => unreachable,
|
||||
EINTR => continue,
|
||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||
loop.waitUntilFdReadable(sockfd);
|
||||
continue;
|
||||
} else {
|
||||
return error.WouldBlock;
|
||||
},
|
||||
EAGAIN => return error.WouldBlock,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ECONNREFUSED => return error.ConnectionRefused,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user