*WIP* async/await TCP server

This commit is contained in:
Andrew Kelley 2018-03-07 03:55:52 -05:00
parent 292d0cbdad
commit 0d22a00f6f
17 changed files with 888 additions and 804 deletions

View File

@ -432,7 +432,6 @@ set(ZIG_STD_FILES
"dwarf.zig"
"elf.zig"
"empty.zig"
"endian.zig"
"fmt/errol/enum3.zig"
"fmt/errol/index.zig"
"fmt/errol/lookup.zig"
@ -503,7 +502,6 @@ set(ZIG_STD_FILES
"os/get_user_id.zig"
"os/index.zig"
"os/linux/errno.zig"
"os/linux/i386.zig"
"os/linux/index.zig"
"os/linux/x86_64.zig"
"os/path.zig"

View File

@ -359,7 +359,6 @@ enum NodeType {
NodeTypeRoot,
NodeTypeFnProto,
NodeTypeFnDef,
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeBlock,
NodeTypeGroupedExpr,
@ -453,10 +452,6 @@ struct AstNodeFnDef {
AstNode *body;
};
struct AstNodeFnDecl {
AstNode *fn_proto;
};
struct AstNodeParamDecl {
Buf *name;
AstNode *type;
@ -713,10 +708,6 @@ struct AstNodeSwitchRange {
AstNode *end;
};
struct AstNodeLabel {
Buf *name;
};
struct AstNodeCompTime {
AstNode *expr;
};
@ -892,7 +883,6 @@ struct AstNode {
union {
AstNodeRoot root;
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
AstNodeParamDecl param_decl;
AstNodeBlock block;
@ -917,7 +907,6 @@ struct AstNode {
AstNodeSwitchExpr switch_expr;
AstNodeSwitchProng switch_prong;
AstNodeSwitchRange switch_range;
AstNodeLabel label;
AstNodeCompTime comptime_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
@ -2702,6 +2691,7 @@ struct IrInstructionFnProto {
IrInstruction **param_types;
IrInstruction *align_value;
IrInstruction *async_allocator_type_value;
IrInstruction *return_type;
IrInstruction *async_allocator_type_value;
bool is_var_args;

View File

@ -3236,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
break;
case NodeTypeContainerDecl:
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeDefer:
case NodeTypeBlock:

View File

@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {
return "Root";
case NodeTypeFnDef:
return "FnDef";
case NodeTypeFnDecl:
return "FnDecl";
case NodeTypeFnProto:
return "FnProto";
case NodeTypeParamDecl:
@ -1098,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
break;
}
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeTestDecl:
case NodeTypeStructField:

View File

@ -2153,12 +2153,12 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
}
static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
IrInstruction *async_allocator_type_value, bool is_var_args)
IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, IrInstruction *async_allocator_type_value, bool is_var_args)
{
IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
instruction->param_types = param_types;
instruction->align_value = align_value;
instruction->async_allocator_type_value = async_allocator_type_value;
instruction->return_type = return_type;
instruction->async_allocator_type_value = async_allocator_type_value;
instruction->is_var_args = is_var_args;
@ -6041,6 +6041,13 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
return irb->codegen->invalid_instruction;
}
IrInstruction *async_allocator_type_value = nullptr;
if (node->data.fn_proto.async_allocator_type != nullptr) {
async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
if (async_allocator_type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
IrInstruction *return_type;
if (node->data.fn_proto.return_var_token == nullptr) {
if (node->data.fn_proto.return_type == nullptr) {
@ -6061,8 +6068,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
return irb->codegen->invalid_instruction;
}
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type,
async_allocator_type_value, is_var_args);
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, async_allocator_type_value, is_var_args);
}
static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@ -6273,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSwitchRange:
case NodeTypeStructField:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
@ -16741,6 +16746,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
return ira->codegen->builtin_types.entry_invalid;
}
if (instruction->async_allocator_type_value != nullptr) {
fn_type_id.async_allocator_type = ir_resolve_type(ira, instruction->async_allocator_type_value->other);
if (type_is_invalid(fn_type_id.async_allocator_type))
return ira->codegen->builtin_types.entry_invalid;
}
IrInstruction *return_type_value = instruction->return_type->other;
fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
if (type_is_invalid(fn_type_id.return_type))

View File

@ -1037,6 +1037,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
Token *async_token = &pc->tokens->at(*token_index);
if (async_token->id == TokenIdKeywordAsync) {
size_t token_index_of_async = *token_index;
*token_index += 1;
AstNode *allocator_expr_node = nullptr;
@ -2923,9 +2924,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.fn_def.fn_proto, visit, context);
visit_field(&node->data.fn_def.body, visit, context);
break;
case NodeTypeFnDecl:
visit_field(&node->data.fn_decl.fn_proto, visit, context);
break;
case NodeTypeParamDecl:
visit_field(&node->data.param_decl.type, visit, context);
break;

View File

@ -1,25 +0,0 @@
const mem = @import("mem.zig");
const builtin = @import("builtin");
pub fn swapIfLe(comptime T: type, x: T) T {
return swapIf(builtin.Endian.Little, T, x);
}
pub fn swapIfBe(comptime T: type, x: T) T {
return swapIf(builtin.Endian.Big, T, x);
}
pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) T {
return if (builtin.endian == endian) swap(T, x) else x;
}
pub fn swap(comptime T: type, x: T) T {
var buf: [@sizeOf(T)]u8 = undefined;
mem.writeInt(buf[0..], x, builtin.Endian.Little);
return mem.readInt(buf, T, builtin.Endian.Big);
}
test "swap" {
const debug = @import("debug/index.zig");
debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE);
}

202
std/event.zig Normal file
View File

@ -0,0 +1,202 @@
const std = @import("index.zig");
const assert = std.debug.assert;
const event = this;
const mem = std.mem;
const posix = std.os.posix;
pub const TcpServer = struct {
handleRequestFn: async(&mem.Allocator) fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
loop: &Loop,
sockfd: i32,
accept_coro: ?promise,
waiting_for_emfile_node: PromiseNode,
const PromiseNode = std.LinkedList(promise).Node;
pub fn init(loop: &Loop) !TcpServer {
const sockfd = try std.os.posixSocket(posix.AF_INET,
posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
posix.PROTO_tcp);
errdefer std.os.close(sockfd);
// TODO can't initialize handler coroutine here because we need well defined copy elision
return TcpServer {
.loop = loop,
.sockfd = sockfd,
.accept_coro = null,
.handleRequestFn = undefined,
.waiting_for_emfile_node = undefined,
};
}
pub fn listen(self: &TcpServer, address: &const std.net.Address,
handleRequestFn: async(&mem.Allocator) fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
{
self.handleRequestFn = handleRequestFn;
try std.os.posixBind(self.sockfd, &address.sockaddr);
try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
self.accept_coro = try async(self.loop.allocator) (TcpServer.handler)(self); // TODO #817
errdefer cancel ??self.accept_coro;
try self.loop.addFd(self.sockfd, ??self.accept_coro);
errdefer self.loop.removeFd(self.sockfd);
}
pub fn deinit(self: &TcpServer) void {
self.loop.removeFd(self.sockfd);
if (self.accept_coro) |accept_coro| cancel accept_coro;
std.os.close(self.sockfd);
}
pub async fn handler(self: &TcpServer) void {
while (true) {
var accepted_addr: std.net.Address = undefined;
if (std.os.posixAccept(self.sockfd, &accepted_addr.sockaddr,
posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
{
var socket = std.os.File.openHandle(accepted_fd);
// TODO #817
_ = async(self.loop.allocator) (self.handleRequestFn)(self, accepted_addr,
socket) catch |err| switch (err)
{
error.OutOfMemory => {
socket.close();
continue;
},
};
} else |err| switch (err) {
error.WouldBlock => {
suspend; // we will get resumed by epoll_wait in the event loop
continue;
},
error.ProcessFdQuotaExceeded => {
errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
suspend |p| {
self.waiting_for_emfile_node = PromiseNode.init(p);
std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
}
continue;
},
error.ConnectionAborted,
error.FileDescriptorClosed => continue,
error.PageFault => unreachable,
error.InvalidSyscall => unreachable,
error.FileDescriptorNotASocket => unreachable,
error.OperationNotSupported => unreachable,
error.SystemFdQuotaExceeded,
error.SystemResources,
error.ProtocolFailure,
error.BlockedByFirewall,
error.Unexpected => {
@panic("TODO handle this error");
},
}
}
}
};
pub const Loop = struct {
allocator: &mem.Allocator,
epollfd: i32,
keep_running: bool,
fn init(allocator: &mem.Allocator) !Loop {
const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
return Loop {
.keep_running = true,
.allocator = allocator,
.epollfd = epollfd,
};
}
pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
var ev = std.os.linux.epoll_event {
.events = std.os.linux.EPOLLIN|std.os.linux.EPOLLET,
.data = std.os.linux.epoll_data {
.ptr = @ptrToInt(prom),
},
};
try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
}
pub fn removeFd(self: &Loop, fd: i32) void {
std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
}
async fn waitFd(self: &Loop, fd: i32) !void {
defer self.removeFd(fd);
suspend |p| {
try self.addFd(fd, p);
}
}
pub fn stop(self: &Loop) void {
// TODO make atomic
self.keep_running = false;
// TODO activate an fd in the epoll set
}
pub fn run(self: &Loop) void {
while (self.keep_running) {
var events: [16]std.os.linux.epoll_event = undefined;
const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);
for (events[0..count]) |ev| {
const p = @intToPtr(promise, ev.data.ptr);
resume p;
}
}
}
};
test "listen on a port, send bytes, receive bytes" {
const MyServer = struct {
tcp_server: TcpServer,
const Self = this;
async(&mem.Allocator) fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
_socket: &const std.os.File) void
{
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
defer socket.close();
const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
error.OutOfMemory => return,
};
(await next_handler) catch |err| switch (err) {
};
suspend |p| { cancel p; }
}
async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
_socket: &const std.os.File) !void
{
const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
var adapter = std.io.FileOutStream.init(&socket);
var stream = &adapter.stream;
try stream.print("hello from server\n") catch unreachable;
}
};
const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
const addr = std.net.Address.initIp4(ip4addr, 0);
var loop = try Loop.init(std.debug.global_allocator);
var server = MyServer {
.tcp_server = try TcpServer.init(&loop),
};
defer server.tcp_server.deinit();
try server.tcp_server.listen(addr, MyServer.handler);
loop.run();
}

View File

@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
return x;
}
fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
const value = switch (c) {
'0' ... '9' => c - '0',
'A' ... 'Z' => c - 'A' + 10,

View File

@ -17,7 +17,7 @@ pub const debug = @import("debug/index.zig");
pub const dwarf = @import("dwarf.zig");
pub const elf = @import("elf.zig");
pub const empty_import = @import("empty.zig");
pub const endian = @import("endian.zig");
pub const event = @import("event.zig");
pub const fmt = @import("fmt/index.zig");
pub const hash = @import("hash/index.zig");
pub const heap = @import("heap.zig");
@ -50,13 +50,13 @@ test "std" {
_ = @import("dwarf.zig");
_ = @import("elf.zig");
_ = @import("empty.zig");
_ = @import("endian.zig");
_ = @import("fmt/index.zig");
_ = @import("hash/index.zig");
_ = @import("io.zig");
_ = @import("macho.zig");
_ = @import("math/index.zig");
_ = @import("mem.zig");
_ = @import("net.zig");
_ = @import("heap.zig");
_ = @import("net.zig");
_ = @import("os/index.zig");

View File

@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
}
list.len -= 1;
assert(list.len == 0 or (list.first != null and list.last != null));
}
/// Remove and return the last node in the list.

View File

@ -3,6 +3,7 @@ const debug = std.debug;
const assert = debug.assert;
const math = std.math;
const builtin = @import("builtin");
const mem = this;
pub const Allocator = struct {
const Error = error {OutOfMemory};
@ -550,3 +551,28 @@ test "std.mem.rotate" {
assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
}
// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
// endian-casting the pointer and then dereferencing
pub fn endianSwapIfLe(comptime T: type, x: T) T {
return endianSwapIf(builtin.Endian.Little, T, x);
}
pub fn endianSwapIfBe(comptime T: type, x: T) T {
return endianSwapIf(builtin.Endian.Big, T, x);
}
pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
return if (builtin.endian == endian) endianSwap(T, x) else x;
}
pub fn endianSwap(comptime T: type, x: T) T {
var buf: [@sizeOf(T)]u8 = undefined;
mem.writeInt(buf[0..], x, builtin.Endian.Little);
return mem.readInt(buf, T, builtin.Endian.Big);
}
test "std.mem.endianSwap" {
assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
}

View File

@ -1,143 +1,103 @@
const std = @import("index.zig");
const linux = std.os.linux;
const assert = std.debug.assert;
const endian = std.endian;
const net = this;
const posix = std.os.posix;
const mem = std.mem;
// TODO don't trust this file, it bit rotted. start over
pub const Address = struct {
sockaddr: posix.sockaddr,
const Connection = struct {
socket_fd: i32,
pub fn send(c: Connection, buf: []const u8) !usize {
const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
const send_err = linux.getErrno(send_ret);
switch (send_err) {
0 => return send_ret,
linux.EINVAL => unreachable,
linux.EFAULT => unreachable,
linux.ECONNRESET => return error.ConnectionReset,
linux.EINTR => return error.SigInterrupt,
// TODO there are more possible errors
else => return error.Unexpected,
}
pub fn initIp4(ip4: u32, port: u16) Address {
return Address {
.sockaddr = posix.sockaddr {
.in = posix.sockaddr_in {
.family = posix.AF_INET,
.port = std.mem.endianSwapIfLe(u16, port),
.addr = ip4,
.zero = []u8{0} ** 8,
},
},
};
}
pub fn recv(c: Connection, buf: []u8) ![]u8 {
const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
const recv_err = linux.getErrno(recv_ret);
switch (recv_err) {
0 => return buf[0..recv_ret],
linux.EINVAL => unreachable,
linux.EFAULT => unreachable,
linux.ENOTSOCK => return error.NotSocket,
linux.EINTR => return error.SigInterrupt,
linux.ENOMEM => return error.OutOfMemory,
linux.ECONNREFUSED => return error.ConnectionRefused,
linux.EBADF => return error.BadFd,
// TODO more error values
else => return error.Unexpected,
}
pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
return Address {
.family = posix.AF_INET6,
.sockaddr = posix.sockaddr {
.in6 = posix.sockaddr_in6 {
.family = posix.AF_INET6,
.port = std.mem.endianSwapIfLe(u16, port),
.flowinfo = 0,
.addr = ip6.addr,
.scope_id = ip6.scope_id,
},
},
};
}
pub fn close(c: Connection) !void {
switch (linux.getErrno(linux.close(c.socket_fd))) {
0 => return,
linux.EBADF => unreachable,
linux.EINTR => return error.SigInterrupt,
linux.EIO => return error.Io,
else => return error.Unexpected,
pub fn format(self: &const Address, out_stream: var) !void {
switch (self.sockaddr.in.family) {
posix.AF_INET => {
const native_endian_port = std.mem.endianSwapIfLe(u16, self.sockaddr.in.port);
const bytes = ([]const u8)((&self.sockaddr.in.addr)[0..1]);
try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
},
posix.AF_INET6 => {
const native_endian_port = std.mem.endianSwapIfLe(u16, self.sockaddr.in6.port);
try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
},
else => try out_stream.write("(unrecognized address family)"),
}
}
};
const Address = struct {
family: u16,
pub fn parseIp4(buf: []const u8) !u32 {
var result: u32 = undefined;
const out_ptr = ([]u8)((&result)[0..1]);
var x: u8 = 0;
var index: u8 = 0;
var saw_any_digits = false;
for (buf) |c| {
if (c == '.') {
if (!saw_any_digits) {
return error.InvalidCharacter;
}
if (index == 3) {
return error.InvalidEnd;
}
out_ptr[index] = x;
index += 1;
x = 0;
saw_any_digits = false;
} else if (c >= '0' and c <= '9') {
saw_any_digits = true;
const digit = c - '0';
if (@mulWithOverflow(u8, x, 10, &x)) {
return error.Overflow;
}
if (@addWithOverflow(u8, x, digit, &x)) {
return error.Overflow;
}
} else {
return error.InvalidCharacter;
}
}
if (index == 3 and saw_any_digits) {
out_ptr[index] = x;
return result;
}
return error.Incomplete;
}
pub const Ip6Addr = struct {
scope_id: u32,
addr: [16]u8,
sort_key: i32,
};
pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {
if (hostname.len == 0) {
unreachable; // TODO
}
unreachable; // TODO
}
pub fn connectAddr(addr: &Address, port: u16) !Connection {
const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);
const socket_err = linux.getErrno(socket_ret);
if (socket_err > 0) {
// TODO figure out possible errors from socket()
return error.Unexpected;
}
const socket_fd = i32(socket_ret);
const connect_ret = if (addr.family == linux.AF_INET) x: {
var os_addr: linux.sockaddr_in = undefined;
os_addr.family = addr.family;
os_addr.port = endian.swapIfLe(u16, port);
@memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
@memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));
} else if (addr.family == linux.AF_INET6) x: {
var os_addr: linux.sockaddr_in6 = undefined;
os_addr.family = addr.family;
os_addr.port = endian.swapIfLe(u16, port);
os_addr.flowinfo = 0;
os_addr.scope_id = addr.scope_id;
@memcpy(&os_addr.addr[0], &addr.addr[0], 16);
break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
} else {
unreachable;
};
const connect_err = linux.getErrno(connect_ret);
if (connect_err > 0) {
switch (connect_err) {
linux.ETIMEDOUT => return error.TimedOut,
else => {
// TODO figure out possible errors from connect()
return error.Unexpected;
},
}
}
return Connection {
.socket_fd = socket_fd,
};
}
pub fn connect(hostname: []const u8, port: u16) !Connection {
var addrs_buf: [1]Address = undefined;
const addrs_slice = try lookup(hostname, addrs_buf[0..]);
const main_addr = &addrs_slice[0];
return connectAddr(main_addr, port);
}
pub fn parseIpLiteral(buf: []const u8) !Address {
return error.InvalidIpLiteral;
}
fn hexDigit(c: u8) u8 {
// TODO use switch with range
if ('0' <= c and c <= '9') {
return c - '0';
} else if ('A' <= c and c <= 'Z') {
return c - 'A' + 10;
} else if ('a' <= c and c <= 'z') {
return c - 'a' + 10;
} else {
return @maxValue(u8);
}
}
fn parseIp6(buf: []const u8) !Address {
var result: Address = undefined;
result.family = linux.AF_INET6;
pub fn parseIp6(buf: []const u8) !Ip6Addr {
var result: Ip6Addr = undefined;
result.scope_id = 0;
const ip_slice = result.addr[0..];
@ -156,14 +116,14 @@ fn parseIp6(buf: []const u8) !Address {
return error.Overflow;
}
} else {
return error.InvalidChar;
return error.InvalidCharacter;
}
} else if (c == ':') {
if (!saw_any_digits) {
return error.InvalidChar;
return error.InvalidCharacter;
}
if (index == 14) {
return error.JunkAtEnd;
return error.InvalidEnd;
}
ip_slice[index] = @truncate(u8, x >> 8);
index += 1;
@ -174,7 +134,7 @@ fn parseIp6(buf: []const u8) !Address {
saw_any_digits = false;
} else if (c == '%') {
if (!saw_any_digits) {
return error.InvalidChar;
return error.InvalidCharacter;
}
if (index == 14) {
ip_slice[index] = @truncate(u8, x >> 8);
@ -185,10 +145,7 @@ fn parseIp6(buf: []const u8) !Address {
scope_id = true;
saw_any_digits = false;
} else {
const digit = hexDigit(c);
if (digit == @maxValue(u8)) {
return error.InvalidChar;
}
const digit = try std.fmt.charToDigit(c, 16);
if (@mulWithOverflow(u16, x, 16, &x)) {
return error.Overflow;
}
@ -216,42 +173,27 @@ fn parseIp6(buf: []const u8) !Address {
return error.Incomplete;
}
fn parseIp4(buf: []const u8) !u32 {
var result: u32 = undefined;
const out_ptr = ([]u8)((&result)[0..1]);
test "std.net.parseIp4" {
assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
var x: u8 = 0;
var index: u8 = 0;
var saw_any_digits = false;
for (buf) |c| {
if (c == '.') {
if (!saw_any_digits) {
return error.InvalidChar;
}
if (index == 3) {
return error.JunkAtEnd;
}
out_ptr[index] = x;
index += 1;
x = 0;
saw_any_digits = false;
} else if (c >= '0' and c <= '9') {
saw_any_digits = true;
const digit = c - '0';
if (@mulWithOverflow(u8, x, 10, &x)) {
return error.Overflow;
}
if (@addWithOverflow(u8, x, digit, &x)) {
return error.Overflow;
}
} else {
return error.InvalidChar;
}
}
if (index == 3 and saw_any_digits) {
out_ptr[index] = x;
return result;
}
return error.Incomplete;
testParseIp4Fail("256.0.0.1", error.Overflow);
testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
testParseIp4Fail("127.0.0.", error.Incomplete);
testParseIp4Fail("100..0.1", error.InvalidCharacter);
}
fn testParseIp4Fail(buf: []const u8, expected_err: error) void {
if (parseIp4(buf)) |_| {
@panic("expected error");
} else |e| {
assert(e == expected_err);
}
}
test "std.net.parseIp6" {
const addr = try parseIp6("FF01:0:0:0:0:0:0:FB");
assert(addr.addr[0] == 0xff);
assert(addr.addr[1] == 0x01);
assert(addr.addr[2] == 0x00);
}

View File

@ -4,6 +4,19 @@ const Os = builtin.Os;
const is_windows = builtin.os == Os.windows;
const os = this;
test "std.os" {
_ = @import("child_process.zig");
_ = @import("darwin.zig");
_ = @import("darwin_errno.zig");
_ = @import("get_user_id.zig");
_ = @import("linux/errno.zig");
_ = @import("linux/index.zig");
_ = @import("linux/x86_64.zig");
_ = @import("path.zig");
_ = @import("test.zig");
_ = @import("windows/index.zig");
}
pub const windows = @import("windows/index.zig");
pub const darwin = @import("darwin.zig");
pub const linux = @import("linux/index.zig");
@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {
Os.zen => zen,
else => @compileError("Unsupported OS"),
};
pub const net = @import("net.zig");
pub const ChildProcess = @import("child_process.zig").ChildProcess;
pub const path = @import("path.zig");
@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {
}
}
/// When a file descriptor is closed on linux, it pops the first
/// node from this queue and resumes it.
/// Async functions which get the EMFILE error code can suspend,
/// putting their coroutine handle into this list.
/// TODO make this an atomic linked list
pub var emfile_promise_queue = std.LinkedList(promise).init();
/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
pub fn close(handle: FileHandle) void {
if (is_windows) {
@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {
} else {
while (true) {
const err = posix.getErrno(posix.close(handle));
if (err == posix.EINTR) {
continue;
} else {
return;
switch (err) {
posix.EINTR => continue,
else => {
if (emfile_promise_queue.popFirst()) |p| resume p.data;
return;
},
}
}
}
@ -1753,27 +1776,16 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
assert(it.next(debug.global_allocator) == null);
}
test "std.os" {
_ = @import("child_process.zig");
_ = @import("darwin_errno.zig");
_ = @import("darwin.zig");
_ = @import("get_user_id.zig");
_ = @import("linux/errno.zig");
//_ = @import("linux_i386.zig");
_ = @import("linux/x86_64.zig");
_ = @import("linux/index.zig");
_ = @import("path.zig");
_ = @import("windows/index.zig");
_ = @import("test.zig");
}
// TODO make this a build variable that you can set
const unexpected_error_tracing = false;
const UnexpectedError = error {
/// The Operating System returned an undocumented error code.
Unexpected,
};
/// Call this when you made a syscall or something that sets errno
/// and you get an unexpected error.
pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
if (unexpected_error_tracing) {
debug.warn("unexpected errno: {}\n", errno);
debug.dumpCurrentStackTrace(null);
@ -1783,7 +1795,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
/// Call this when you made a windows DLL call or something that does SetLastError
/// and you get an unexpected error.
pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
if (unexpected_error_tracing) {
debug.warn("unexpected GetLastError(): {}\n", err);
debug.dumpCurrentStackTrace(null);
@ -1898,3 +1910,322 @@ pub fn isTty(handle: FileHandle) bool {
}
}
}
pub const PosixSocketError = error {
/// Permission to create a socket of the specified type and/or
/// protocol is denied.
PermissionDenied,
/// The implementation does not support the specified address family.
AddressFamilyNotSupported,
/// Unknown protocol, or protocol family not available.
ProtocolFamilyNotAvailable,
/// The per-process limit on the number of open file descriptors has been reached.
ProcessFdQuotaExceeded,
/// The system-wide limit on the total number of open files has been reached.
SystemFdQuotaExceeded,
/// Insufficient memory is available. The socket cannot be created until sufficient
/// resources are freed.
SystemResources,
/// The protocol type or the specified protocol is not supported within this domain.
ProtocolNotSupported,
};
pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
const rc = posix.socket(domain, socket_type, protocol);
const err = posix.getErrno(rc);
switch (err) {
0 => return i32(rc),
posix.EACCES => return PosixSocketError.PermissionDenied,
posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
else => return unexpectedErrorPosix(err),
}
}
pub const PosixBindError = error {
/// The address is protected, and the user is not the superuser.
/// For UNIX domain sockets: Search permission is denied on a component
/// of the path prefix.
AccessDenied,
/// The given address is already in use, or in the case of Internet domain sockets,
/// The port number was specified as zero in the socket
/// address structure, but, upon attempting to bind to an ephemeral port, it was
/// determined that all port numbers in the ephemeral port range are currently in
/// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
AddressInUse,
/// sockfd is not a valid file descriptor.
InvalidFileDescriptor,
/// The socket is already bound to an address, or addrlen is wrong, or addr is not
/// a valid address for this socket's domain.
InvalidSocketOrAddress,
/// The file descriptor sockfd does not refer to a socket.
FileDescriptorNotASocket,
/// A nonexistent interface was requested or the requested address was not local.
AddressNotAvailable,
/// addr points outside the user's accessible address space.
PageFault,
/// Too many symbolic links were encountered in resolving addr.
SymLinkLoop,
/// addr is too long.
NameTooLong,
/// A component in the directory prefix of the socket pathname does not exist.
FileNotFound,
/// Insufficient kernel memory was available.
SystemResources,
/// A component of the path prefix is not a directory.
NotDir,
/// The socket inode would reside on a read-only filesystem.
ReadOnlyFileSystem,
Unexpected,
};
/// addr is `&const T` where T is one of the sockaddr
pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
const err = posix.getErrno(rc);
switch (err) {
0 => return,
posix.EACCES => return PosixBindError.AccessDenied,
posix.EADDRINUSE => return PosixBindError.AddressInUse,
posix.EBADF => return PosixBindError.InvalidFileDescriptor,
posix.EINVAL => return PosixBindError.InvalidSocketOrAddress,
posix.ENOTSOCK => return PosixBindError.FileDescriptorNotASocket,
posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
posix.EFAULT => return PosixBindError.PageFault,
posix.ELOOP => return PosixBindError.SymLinkLoop,
posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
posix.ENOENT => return PosixBindError.FileNotFound,
posix.ENOMEM => return PosixBindError.SystemResources,
posix.ENOTDIR => return PosixBindError.NotDir,
posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
else => return unexpectedErrorPosix(err),
}
}
const PosixListenError = error {
/// Another socket is already listening on the same port.
/// For Internet domain sockets, the socket referred to by sockfd had not previously
/// been bound to an address and, upon attempting to bind it to an ephemeral port, it
/// was determined that all port numbers in the ephemeral port range are currently in
/// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
AddressInUse,
/// The argument sockfd is not a valid file descriptor.
InvalidFileDescriptor,
/// The file descriptor sockfd does not refer to a socket.
FileDescriptorNotASocket,
/// The socket is not of a type that supports the listen() operation.
OperationNotSupported,
Unexpected,
};
pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
const rc = posix.listen(sockfd, backlog);
const err = posix.getErrno(rc);
switch (err) {
0 => return,
posix.EADDRINUSE => return PosixListenError.AddressInUse,
posix.EBADF => return PosixListenError.InvalidFileDescriptor,
posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
else => return unexpectedErrorPosix(err),
}
}
pub const PosixAcceptError = error {
/// The socket is marked nonblocking and no connections are present to be accepted.
WouldBlock,
/// sockfd is not an open file descriptor.
FileDescriptorClosed,
ConnectionAborted,
/// The addr argument is not in a writable part of the user address space.
PageFault,
/// Socket is not listening for connections, or addrlen is invalid (e.g., is negative),
/// or invalid value in flags.
InvalidSyscall,
/// The per-process limit on the number of open file descriptors has been reached.
ProcessFdQuotaExceeded,
/// The system-wide limit on the total number of open files has been reached.
SystemFdQuotaExceeded,
/// Not enough free memory. This often means that the memory allocation is limited
/// by the socket buffer limits, not by the system memory.
SystemResources,
/// The file descriptor sockfd does not refer to a socket.
FileDescriptorNotASocket,
/// The referenced socket is not of type SOCK_STREAM.
OperationNotSupported,
ProtocolFailure,
/// Firewall rules forbid connection.
BlockedByFirewall,
Unexpected,
};
pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 {
while (true) {
var sockaddr_size = u32(@sizeOf(posix.sockaddr));
const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
const err = posix.getErrno(rc);
switch (err) {
0 => return i32(rc),
posix.EINTR => continue,
else => return unexpectedErrorPosix(err),
posix.EAGAIN => return PosixAcceptError.WouldBlock,
posix.EBADF => return PosixAcceptError.FileDescriptorClosed,
posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
posix.EFAULT => return PosixAcceptError.PageFault,
posix.EINVAL => return PosixAcceptError.InvalidSyscall,
posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources,
posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
posix.EPROTO => return PosixAcceptError.ProtocolFailure,
posix.EPERM => return PosixAcceptError.BlockedByFirewall,
}
}
}
pub const LinuxEpollCreateError = error {
/// Invalid value specified in flags.
InvalidSyscall,
/// The per-user limit on the number of epoll instances imposed by
/// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
/// details.
/// Or, The per-process limit on the number of open file descriptors has been reached.
ProcessFdQuotaExceeded,
/// The system-wide limit on the total number of open files has been reached.
SystemFdQuotaExceeded,
/// There was insufficient memory to create the kernel object.
SystemResources,
Unexpected,
};
pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
const rc = posix.epoll_create1(flags);
const err = posix.getErrno(rc);
switch (err) {
0 => return i32(rc),
else => return unexpectedErrorPosix(err),
posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall,
posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
}
}
pub const LinuxEpollCtlError = error {
/// epfd or fd is not a valid file descriptor.
InvalidFileDescriptor,
/// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
/// with this epoll instance.
FileDescriptorAlreadyPresentInSet,
/// epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested
/// operation op is not supported by this interface, or
/// An invalid event type was specified along with EPOLLEXCLUSIVE in events, or
/// op was EPOLL_CTL_MOD and events included EPOLLEXCLUSIVE, or
/// op was EPOLL_CTL_MOD and the EPOLLEXCLUSIVE flag has previously been applied to
/// this epfd, fd pair, or
/// EPOLLEXCLUSIVE was specified in event and fd refers to an epoll instance.
InvalidSyscall,
/// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
/// circular loop of epoll instances monitoring one another.
OperationCausesCircularLoop,
/// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
/// instance.
FileDescriptorNotRegistered,
/// There was insufficient memory to handle the requested op control operation.
SystemResources,
/// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
/// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
/// See epoll(7) for further details.
UserResourceLimitReached,
/// The target file fd does not support epoll. This error can occur if fd refers to,
/// for example, a regular file or a directory.
FileDescriptorIncompatibleWithEpoll,
Unexpected,
};
pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void {
const rc = posix.epoll_ctl(epfd, op, fd, event);
const err = posix.getErrno(rc);
switch (err) {
0 => return,
else => return unexpectedErrorPosix(err),
posix.EBADF => return LinuxEpollCtlError.InvalidFileDescriptor,
posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
posix.EINVAL => return LinuxEpollCtlError.InvalidSyscall,
posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
}
}
pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
while (true) {
const rc = posix.epoll_wait(epfd, &events[0], u32(events.len), timeout);
const err = posix.getErrno(rc);
switch (err) {
0 => return rc,
posix.EINTR => continue,
posix.EBADF => unreachable,
posix.EFAULT => unreachable,
posix.EINVAL => unreachable,
else => unreachable,
}
}
}

View File

@ -1,505 +0,0 @@
const std = @import("../../index.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
const iovec = linux.iovec;
pub const SYS_restart_syscall = 0;
pub const SYS_exit = 1;
pub const SYS_fork = 2;
pub const SYS_read = 3;
pub const SYS_write = 4;
pub const SYS_open = 5;
pub const SYS_close = 6;
pub const SYS_waitpid = 7;
pub const SYS_creat = 8;
pub const SYS_link = 9;
pub const SYS_unlink = 10;
pub const SYS_execve = 11;
pub const SYS_chdir = 12;
pub const SYS_time = 13;
pub const SYS_mknod = 14;
pub const SYS_chmod = 15;
pub const SYS_lchown = 16;
pub const SYS_break = 17;
pub const SYS_oldstat = 18;
pub const SYS_lseek = 19;
pub const SYS_getpid = 20;
pub const SYS_mount = 21;
pub const SYS_umount = 22;
pub const SYS_setuid = 23;
pub const SYS_getuid = 24;
pub const SYS_stime = 25;
pub const SYS_ptrace = 26;
pub const SYS_alarm = 27;
pub const SYS_oldfstat = 28;
pub const SYS_pause = 29;
pub const SYS_utime = 30;
pub const SYS_stty = 31;
pub const SYS_gtty = 32;
pub const SYS_access = 33;
pub const SYS_nice = 34;
pub const SYS_ftime = 35;
pub const SYS_sync = 36;
pub const SYS_kill = 37;
pub const SYS_rename = 38;
pub const SYS_mkdir = 39;
pub const SYS_rmdir = 40;
pub const SYS_dup = 41;
pub const SYS_pipe = 42;
pub const SYS_times = 43;
pub const SYS_prof = 44;
pub const SYS_brk = 45;
pub const SYS_setgid = 46;
pub const SYS_getgid = 47;
pub const SYS_signal = 48;
pub const SYS_geteuid = 49;
pub const SYS_getegid = 50;
pub const SYS_acct = 51;
pub const SYS_umount2 = 52;
pub const SYS_lock = 53;
pub const SYS_ioctl = 54;
pub const SYS_fcntl = 55;
pub const SYS_mpx = 56;
pub const SYS_setpgid = 57;
pub const SYS_ulimit = 58;
pub const SYS_oldolduname = 59;
pub const SYS_umask = 60;
pub const SYS_chroot = 61;
pub const SYS_ustat = 62;
pub const SYS_dup2 = 63;
pub const SYS_getppid = 64;
pub const SYS_getpgrp = 65;
pub const SYS_setsid = 66;
pub const SYS_sigaction = 67;
pub const SYS_sgetmask = 68;
pub const SYS_ssetmask = 69;
pub const SYS_setreuid = 70;
pub const SYS_setregid = 71;
pub const SYS_sigsuspend = 72;
pub const SYS_sigpending = 73;
pub const SYS_sethostname = 74;
pub const SYS_setrlimit = 75;
pub const SYS_getrlimit = 76;
pub const SYS_getrusage = 77;
pub const SYS_gettimeofday = 78;
pub const SYS_settimeofday = 79;
pub const SYS_getgroups = 80;
pub const SYS_setgroups = 81;
pub const SYS_select = 82;
pub const SYS_symlink = 83;
pub const SYS_oldlstat = 84;
pub const SYS_readlink = 85;
pub const SYS_uselib = 86;
pub const SYS_swapon = 87;
pub const SYS_reboot = 88;
pub const SYS_readdir = 89;
pub const SYS_mmap = 90;
pub const SYS_munmap = 91;
pub const SYS_truncate = 92;
pub const SYS_ftruncate = 93;
pub const SYS_fchmod = 94;
pub const SYS_fchown = 95;
pub const SYS_getpriority = 96;
pub const SYS_setpriority = 97;
pub const SYS_profil = 98;
pub const SYS_statfs = 99;
pub const SYS_fstatfs = 100;
pub const SYS_ioperm = 101;
pub const SYS_socketcall = 102;
pub const SYS_syslog = 103;
pub const SYS_setitimer = 104;
pub const SYS_getitimer = 105;
pub const SYS_stat = 106;
pub const SYS_lstat = 107;
pub const SYS_fstat = 108;
pub const SYS_olduname = 109;
pub const SYS_iopl = 110;
pub const SYS_vhangup = 111;
pub const SYS_idle = 112;
pub const SYS_vm86old = 113;
pub const SYS_wait4 = 114;
pub const SYS_swapoff = 115;
pub const SYS_sysinfo = 116;
pub const SYS_ipc = 117;
pub const SYS_fsync = 118;
pub const SYS_sigreturn = 119;
pub const SYS_clone = 120;
pub const SYS_setdomainname = 121;
pub const SYS_uname = 122;
pub const SYS_modify_ldt = 123;
pub const SYS_adjtimex = 124;
pub const SYS_mprotect = 125;
pub const SYS_sigprocmask = 126;
pub const SYS_create_module = 127;
pub const SYS_init_module = 128;
pub const SYS_delete_module = 129;
pub const SYS_get_kernel_syms = 130;
pub const SYS_quotactl = 131;
pub const SYS_getpgid = 132;
pub const SYS_fchdir = 133;
pub const SYS_bdflush = 134;
pub const SYS_sysfs = 135;
pub const SYS_personality = 136;
pub const SYS_afs_syscall = 137;
pub const SYS_setfsuid = 138;
pub const SYS_setfsgid = 139;
pub const SYS__llseek = 140;
pub const SYS_getdents = 141;
pub const SYS__newselect = 142;
pub const SYS_flock = 143;
pub const SYS_msync = 144;
pub const SYS_readv = 145;
pub const SYS_writev = 146;
pub const SYS_getsid = 147;
pub const SYS_fdatasync = 148;
pub const SYS__sysctl = 149;
pub const SYS_mlock = 150;
pub const SYS_munlock = 151;
pub const SYS_mlockall = 152;
pub const SYS_munlockall = 153;
pub const SYS_sched_setparam = 154;
pub const SYS_sched_getparam = 155;
pub const SYS_sched_setscheduler = 156;
pub const SYS_sched_getscheduler = 157;
pub const SYS_sched_yield = 158;
pub const SYS_sched_get_priority_max = 159;
pub const SYS_sched_get_priority_min = 160;
pub const SYS_sched_rr_get_interval = 161;
pub const SYS_nanosleep = 162;
pub const SYS_mremap = 163;
pub const SYS_setresuid = 164;
pub const SYS_getresuid = 165;
pub const SYS_vm86 = 166;
pub const SYS_query_module = 167;
pub const SYS_poll = 168;
pub const SYS_nfsservctl = 169;
pub const SYS_setresgid = 170;
pub const SYS_getresgid = 171;
pub const SYS_prctl = 172;
pub const SYS_rt_sigreturn = 173;
pub const SYS_rt_sigaction = 174;
pub const SYS_rt_sigprocmask = 175;
pub const SYS_rt_sigpending = 176;
pub const SYS_rt_sigtimedwait = 177;
pub const SYS_rt_sigqueueinfo = 178;
pub const SYS_rt_sigsuspend = 179;
pub const SYS_pread64 = 180;
pub const SYS_pwrite64 = 181;
pub const SYS_chown = 182;
pub const SYS_getcwd = 183;
pub const SYS_capget = 184;
pub const SYS_capset = 185;
pub const SYS_sigaltstack = 186;
pub const SYS_sendfile = 187;
pub const SYS_getpmsg = 188;
pub const SYS_putpmsg = 189;
pub const SYS_vfork = 190;
pub const SYS_ugetrlimit = 191;
pub const SYS_mmap2 = 192;
pub const SYS_truncate64 = 193;
pub const SYS_ftruncate64 = 194;
pub const SYS_stat64 = 195;
pub const SYS_lstat64 = 196;
pub const SYS_fstat64 = 197;
pub const SYS_lchown32 = 198;
pub const SYS_getuid32 = 199;
pub const SYS_getgid32 = 200;
pub const SYS_geteuid32 = 201;
pub const SYS_getegid32 = 202;
pub const SYS_setreuid32 = 203;
pub const SYS_setregid32 = 204;
pub const SYS_getgroups32 = 205;
pub const SYS_setgroups32 = 206;
pub const SYS_fchown32 = 207;
pub const SYS_setresuid32 = 208;
pub const SYS_getresuid32 = 209;
pub const SYS_setresgid32 = 210;
pub const SYS_getresgid32 = 211;
pub const SYS_chown32 = 212;
pub const SYS_setuid32 = 213;
pub const SYS_setgid32 = 214;
pub const SYS_setfsuid32 = 215;
pub const SYS_setfsgid32 = 216;
pub const SYS_pivot_root = 217;
pub const SYS_mincore = 218;
pub const SYS_madvise = 219;
pub const SYS_madvise1 = 219;
pub const SYS_getdents64 = 220;
pub const SYS_fcntl64 = 221;
pub const SYS_gettid = 224;
pub const SYS_readahead = 225;
pub const SYS_setxattr = 226;
pub const SYS_lsetxattr = 227;
pub const SYS_fsetxattr = 228;
pub const SYS_getxattr = 229;
pub const SYS_lgetxattr = 230;
pub const SYS_fgetxattr = 231;
pub const SYS_listxattr = 232;
pub const SYS_llistxattr = 233;
pub const SYS_flistxattr = 234;
pub const SYS_removexattr = 235;
pub const SYS_lremovexattr = 236;
pub const SYS_fremovexattr = 237;
pub const SYS_tkill = 238;
pub const SYS_sendfile64 = 239;
pub const SYS_futex = 240;
pub const SYS_sched_setaffinity = 241;
pub const SYS_sched_getaffinity = 242;
pub const SYS_set_thread_area = 243;
pub const SYS_get_thread_area = 244;
pub const SYS_io_setup = 245;
pub const SYS_io_destroy = 246;
pub const SYS_io_getevents = 247;
pub const SYS_io_submit = 248;
pub const SYS_io_cancel = 249;
pub const SYS_fadvise64 = 250;
pub const SYS_exit_group = 252;
pub const SYS_lookup_dcookie = 253;
pub const SYS_epoll_create = 254;
pub const SYS_epoll_ctl = 255;
pub const SYS_epoll_wait = 256;
pub const SYS_remap_file_pages = 257;
pub const SYS_set_tid_address = 258;
pub const SYS_timer_create = 259;
pub const SYS_timer_settime = SYS_timer_create+1;
pub const SYS_timer_gettime = SYS_timer_create+2;
pub const SYS_timer_getoverrun = SYS_timer_create+3;
pub const SYS_timer_delete = SYS_timer_create+4;
pub const SYS_clock_settime = SYS_timer_create+5;
pub const SYS_clock_gettime = SYS_timer_create+6;
pub const SYS_clock_getres = SYS_timer_create+7;
pub const SYS_clock_nanosleep = SYS_timer_create+8;
pub const SYS_statfs64 = 268;
pub const SYS_fstatfs64 = 269;
pub const SYS_tgkill = 270;
pub const SYS_utimes = 271;
pub const SYS_fadvise64_64 = 272;
pub const SYS_vserver = 273;
pub const SYS_mbind = 274;
pub const SYS_get_mempolicy = 275;
pub const SYS_set_mempolicy = 276;
pub const SYS_mq_open = 277;
pub const SYS_mq_unlink = SYS_mq_open+1;
pub const SYS_mq_timedsend = SYS_mq_open+2;
pub const SYS_mq_timedreceive = SYS_mq_open+3;
pub const SYS_mq_notify = SYS_mq_open+4;
pub const SYS_mq_getsetattr = SYS_mq_open+5;
pub const SYS_kexec_load = 283;
pub const SYS_waitid = 284;
pub const SYS_add_key = 286;
pub const SYS_request_key = 287;
pub const SYS_keyctl = 288;
pub const SYS_ioprio_set = 289;
pub const SYS_ioprio_get = 290;
pub const SYS_inotify_init = 291;
pub const SYS_inotify_add_watch = 292;
pub const SYS_inotify_rm_watch = 293;
pub const SYS_migrate_pages = 294;
pub const SYS_openat = 295;
pub const SYS_mkdirat = 296;
pub const SYS_mknodat = 297;
pub const SYS_fchownat = 298;
pub const SYS_futimesat = 299;
pub const SYS_fstatat64 = 300;
pub const SYS_unlinkat = 301;
pub const SYS_renameat = 302;
pub const SYS_linkat = 303;
pub const SYS_symlinkat = 304;
pub const SYS_readlinkat = 305;
pub const SYS_fchmodat = 306;
pub const SYS_faccessat = 307;
pub const SYS_pselect6 = 308;
pub const SYS_ppoll = 309;
pub const SYS_unshare = 310;
pub const SYS_set_robust_list = 311;
pub const SYS_get_robust_list = 312;
pub const SYS_splice = 313;
pub const SYS_sync_file_range = 314;
pub const SYS_tee = 315;
pub const SYS_vmsplice = 316;
pub const SYS_move_pages = 317;
pub const SYS_getcpu = 318;
pub const SYS_epoll_pwait = 319;
pub const SYS_utimensat = 320;
pub const SYS_signalfd = 321;
pub const SYS_timerfd_create = 322;
pub const SYS_eventfd = 323;
pub const SYS_fallocate = 324;
pub const SYS_timerfd_settime = 325;
pub const SYS_timerfd_gettime = 326;
pub const SYS_signalfd4 = 327;
pub const SYS_eventfd2 = 328;
pub const SYS_epoll_create1 = 329;
pub const SYS_dup3 = 330;
pub const SYS_pipe2 = 331;
pub const SYS_inotify_init1 = 332;
pub const SYS_preadv = 333;
pub const SYS_pwritev = 334;
pub const SYS_rt_tgsigqueueinfo = 335;
pub const SYS_perf_event_open = 336;
pub const SYS_recvmmsg = 337;
pub const SYS_fanotify_init = 338;
pub const SYS_fanotify_mark = 339;
pub const SYS_prlimit64 = 340;
pub const SYS_name_to_handle_at = 341;
pub const SYS_open_by_handle_at = 342;
pub const SYS_clock_adjtime = 343;
pub const SYS_syncfs = 344;
pub const SYS_sendmmsg = 345;
pub const SYS_setns = 346;
pub const SYS_process_vm_readv = 347;
pub const SYS_process_vm_writev = 348;
pub const SYS_kcmp = 349;
pub const SYS_finit_module = 350;
pub const SYS_sched_setattr = 351;
pub const SYS_sched_getattr = 352;
pub const SYS_renameat2 = 353;
pub const SYS_seccomp = 354;
pub const SYS_getrandom = 355;
pub const SYS_memfd_create = 356;
pub const SYS_bpf = 357;
pub const SYS_execveat = 358;
pub const SYS_socket = 359;
pub const SYS_socketpair = 360;
pub const SYS_bind = 361;
pub const SYS_connect = 362;
pub const SYS_listen = 363;
pub const SYS_accept4 = 364;
pub const SYS_getsockopt = 365;
pub const SYS_setsockopt = 366;
pub const SYS_getsockname = 367;
pub const SYS_getpeername = 368;
pub const SYS_sendto = 369;
pub const SYS_sendmsg = 370;
pub const SYS_recvfrom = 371;
pub const SYS_recvmsg = 372;
pub const SYS_shutdown = 373;
pub const SYS_userfaultfd = 374;
pub const SYS_membarrier = 375;
pub const SYS_mlock2 = 376;
pub const O_CREAT = 0o100;
pub const O_EXCL = 0o200;
pub const O_NOCTTY = 0o400;
pub const O_TRUNC = 0o1000;
pub const O_APPEND = 0o2000;
pub const O_NONBLOCK = 0o4000;
pub const O_DSYNC = 0o10000;
pub const O_SYNC = 0o4010000;
pub const O_RSYNC = 0o4010000;
pub const O_DIRECTORY = 0o200000;
pub const O_NOFOLLOW = 0o400000;
pub const O_CLOEXEC = 0o2000000;
pub const O_ASYNC = 0o20000;
pub const O_DIRECT = 0o40000;
pub const O_LARGEFILE = 0o100000;
pub const O_NOATIME = 0o1000000;
pub const O_PATH = 0o10000000;
pub const O_TMPFILE = 0o20200000;
pub const O_NDELAY = O_NONBLOCK;
pub const F_DUPFD = 0;
pub const F_GETFD = 1;
pub const F_SETFD = 2;
pub const F_GETFL = 3;
pub const F_SETFL = 4;
pub const F_SETOWN = 8;
pub const F_GETOWN = 9;
pub const F_SETSIG = 10;
pub const F_GETSIG = 11;
pub const F_GETLK = 12;
pub const F_SETLK = 13;
pub const F_SETLKW = 14;
pub const F_SETOWN_EX = 15;
pub const F_GETOWN_EX = 16;
pub const F_GETOWNER_UIDS = 17;
pub inline fn syscall0(number: usize) usize {
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number));
}
pub inline fn syscall1(number: usize, arg1: usize) usize {
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1));
}
pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2));
}
pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3));
}
pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4));
}
pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize,
arg4: usize, arg5: usize) usize
{
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4),
[arg5] "{edi}" (arg5));
}
pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize,
arg4: usize, arg5: usize, arg6: usize) usize
{
return asm volatile ("int $0x80"
: [ret] "={eax}" (-> usize)
: [number] "{eax}" (number),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4),
[arg5] "{edi}" (arg5),
[arg6] "{ebp}" (arg6));
}
pub nakedcc fn restore() void {
asm volatile (
\\popl %%eax
\\movl $119, %%eax
\\int $0x80
:
:
: "rcx", "r11");
}
pub nakedcc fn restore_rt() void {
asm volatile ("int $0x80"
:
: [number] "{eax}" (usize(SYS_rt_sigreturn))
: "rcx", "r11");
}

View File

@ -101,17 +101,6 @@ pub const SIG_BLOCK = 0;
pub const SIG_UNBLOCK = 1;
pub const SIG_SETMASK = 2;
pub const SOCK_STREAM = 1;
pub const SOCK_DGRAM = 2;
pub const SOCK_RAW = 3;
pub const SOCK_RDM = 4;
pub const SOCK_SEQPACKET = 5;
pub const SOCK_DCCP = 6;
pub const SOCK_PACKET = 10;
pub const SOCK_CLOEXEC = 0o2000000;
pub const SOCK_NONBLOCK = 0o4000;
pub const PROTO_ip = 0o000;
pub const PROTO_icmp = 0o001;
pub const PROTO_igmp = 0o002;
@ -149,6 +138,20 @@ pub const PROTO_encap = 0o142;
pub const PROTO_pim = 0o147;
pub const PROTO_raw = 0o377;
pub const SHUT_RD = 0;
pub const SHUT_WR = 1;
pub const SHUT_RDWR = 2;
pub const SOCK_STREAM = 1;
pub const SOCK_DGRAM = 2;
pub const SOCK_RAW = 3;
pub const SOCK_RDM = 4;
pub const SOCK_SEQPACKET = 5;
pub const SOCK_DCCP = 6;
pub const SOCK_PACKET = 10;
pub const SOCK_CLOEXEC = 0o2000000;
pub const SOCK_NONBLOCK = 0o4000;
pub const PF_UNSPEC = 0;
pub const PF_LOCAL = 1;
pub const PF_UNIX = PF_LOCAL;
@ -193,7 +196,10 @@ pub const PF_CAIF = 37;
pub const PF_ALG = 38;
pub const PF_NFC = 39;
pub const PF_VSOCK = 40;
pub const PF_MAX = 41;
pub const PF_KCM = 41;
pub const PF_QIPCRTR = 42;
pub const PF_SMC = 43;
pub const PF_MAX = 44;
pub const AF_UNSPEC = PF_UNSPEC;
pub const AF_LOCAL = PF_LOCAL;
@ -239,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;
pub const AF_ALG = PF_ALG;
pub const AF_NFC = PF_NFC;
pub const AF_VSOCK = PF_VSOCK;
pub const AF_KCM = PF_KCM;
pub const AF_QIPCRTR = PF_QIPCRTR;
pub const AF_SMC = PF_SMC;
pub const AF_MAX = PF_MAX;
pub const SO_DEBUG = 1;
pub const SO_REUSEADDR = 2;
pub const SO_TYPE = 3;
pub const SO_ERROR = 4;
pub const SO_DONTROUTE = 5;
pub const SO_BROADCAST = 6;
pub const SO_SNDBUF = 7;
pub const SO_RCVBUF = 8;
pub const SO_KEEPALIVE = 9;
pub const SO_OOBINLINE = 10;
pub const SO_NO_CHECK = 11;
pub const SO_PRIORITY = 12;
pub const SO_LINGER = 13;
pub const SO_BSDCOMPAT = 14;
pub const SO_REUSEPORT = 15;
pub const SO_PASSCRED = 16;
pub const SO_PEERCRED = 17;
pub const SO_RCVLOWAT = 18;
pub const SO_SNDLOWAT = 19;
pub const SO_RCVTIMEO = 20;
pub const SO_SNDTIMEO = 21;
pub const SO_ACCEPTCONN = 30;
pub const SO_SNDBUFFORCE = 32;
pub const SO_RCVBUFFORCE = 33;
pub const SO_PROTOCOL = 38;
pub const SO_DOMAIN = 39;
pub const SO_SECURITY_AUTHENTICATION = 22;
pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
pub const SO_BINDTODEVICE = 25;
pub const SO_ATTACH_FILTER = 26;
pub const SO_DETACH_FILTER = 27;
pub const SO_GET_FILTER = SO_ATTACH_FILTER;
pub const SO_PEERNAME = 28;
pub const SO_TIMESTAMP = 29;
pub const SCM_TIMESTAMP = SO_TIMESTAMP;
pub const SO_PEERSEC = 31;
pub const SO_PASSSEC = 34;
pub const SO_TIMESTAMPNS = 35;
pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
pub const SO_MARK = 36;
pub const SO_TIMESTAMPING = 37;
pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
pub const SO_RXQ_OVFL = 40;
pub const SO_WIFI_STATUS = 41;
pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
pub const SO_PEEK_OFF = 42;
pub const SO_NOFCS = 43;
pub const SO_LOCK_FILTER = 44;
pub const SO_SELECT_ERR_QUEUE = 45;
pub const SO_BUSY_POLL = 46;
pub const SO_MAX_PACING_RATE = 47;
pub const SO_BPF_EXTENSIONS = 48;
pub const SO_INCOMING_CPU = 49;
pub const SO_ATTACH_BPF = 50;
pub const SO_DETACH_BPF = SO_DETACH_FILTER;
pub const SO_ATTACH_REUSEPORT_CBPF = 51;
pub const SO_ATTACH_REUSEPORT_EBPF = 52;
pub const SO_CNX_ADVICE = 53;
pub const SCM_TIMESTAMPING_OPT_STATS = 54;
pub const SO_MEMINFO = 55;
pub const SO_INCOMING_NAPI_ID = 56;
pub const SO_COOKIE = 57;
pub const SCM_TIMESTAMPING_PKTINFO = 58;
pub const SO_PEERGROUPS = 59;
pub const SO_ZEROCOPY = 60;
pub const SOL_SOCKET = 1;
pub const SOL_IP = 0;
pub const SOL_IPV6 = 41;
pub const SOL_ICMPV6 = 58;
pub const SOL_RAW = 255;
pub const SOL_DECNET = 261;
pub const SOL_X25 = 262;
pub const SOL_PACKET = 263;
pub const SOL_ATM = 264;
pub const SOL_AAL = 265;
pub const SOL_IRDA = 266;
pub const SOL_NETBEUI = 267;
pub const SOL_LLC = 268;
pub const SOL_DCCP = 269;
pub const SOL_NETLINK = 270;
pub const SOL_TIPC = 271;
pub const SOL_RXRPC = 272;
pub const SOL_PPPOL2TP = 273;
pub const SOL_BLUETOOTH = 274;
pub const SOL_PNPIPE = 275;
pub const SOL_RDS = 276;
pub const SOL_IUCV = 277;
pub const SOL_CAIF = 278;
pub const SOL_ALG = 279;
pub const SOL_NFC = 280;
pub const SOL_KCM = 281;
pub const SOL_TLS = 282;
pub const SOMAXCONN = 128;
pub const MSG_OOB = 0x0001;
pub const MSG_PEEK = 0x0002;
pub const MSG_DONTROUTE = 0x0004;
pub const MSG_CTRUNC = 0x0008;
pub const MSG_PROXY = 0x0010;
pub const MSG_TRUNC = 0x0020;
pub const MSG_DONTWAIT = 0x0040;
pub const MSG_EOR = 0x0080;
pub const MSG_WAITALL = 0x0100;
pub const MSG_FIN = 0x0200;
pub const MSG_SYN = 0x0400;
pub const MSG_CONFIRM = 0x0800;
pub const MSG_RST = 0x1000;
pub const MSG_ERRQUEUE = 0x2000;
pub const MSG_NOSIGNAL = 0x4000;
pub const MSG_MORE = 0x8000;
pub const MSG_WAITFORONE = 0x10000;
pub const MSG_BATCH = 0x40000;
pub const MSG_ZEROCOPY = 0x4000000;
pub const MSG_FASTOPEN = 0x20000000;
pub const MSG_CMSG_CLOEXEC = 0x40000000;
pub const DT_UNKNOWN = 0;
pub const DT_FIFO = 1;
pub const DT_CHR = 2;
@ -599,30 +734,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {
return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
}
pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const socklen_t = u32;
pub const in_addr = u32;
pub const in6_addr = [16]u8;
pub const sockaddr = extern struct {
family: sa_family_t,
port: u16,
data: [12]u8,
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
};
pub const sockaddr_in = extern struct {
family: sa_family_t,
port: u16,
addr: in_addr,
port: in_port_t,
addr: u32,
zero: [8]u8,
};
pub const sockaddr_in6 = extern struct {
family: sa_family_t,
port: u16,
port: in_port_t,
flowinfo: u32,
addr: in6_addr,
addr: [16]u8,
scope_id: u32,
};
@ -639,8 +771,8 @@ pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) us
return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
}
pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {
return syscall3(SYS_socket, usize(domain), usize(socket_type), usize(protocol));
pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
return syscall3(SYS_socket, domain, socket_type, protocol);
}
pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {
@ -677,8 +809,8 @@ pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
}
pub fn listen(fd: i32, backlog: i32) usize {
return syscall2(SYS_listen, usize(fd), usize(backlog));
pub fn listen(fd: i32, backlog: u32) usize {
return syscall2(SYS_listen, usize(fd), backlog);
}
pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {
@ -697,34 +829,6 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
}
// error NameTooLong;
// error SystemResources;
// error Io;
//
// pub fn if_nametoindex(name: []u8) !u32 {
// var ifr: ifreq = undefined;
//
// if (name.len >= ifr.ifr_name.len) {
// return error.NameTooLong;
// }
//
// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
// const socket_err = getErrno(socket_ret);
// if (socket_err > 0) {
// return error.SystemResources;
// }
// const socket_fd = i32(socket_ret);
// @memcpy(&ifr.ifr_name[0], &name[0], name.len);
// ifr.ifr_name[name.len] = 0;
// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
// close(socket_fd);
// const ioctl_err = getErrno(ioctl_ret);
// if (ioctl_err > 0) {
// return error.Io;
// }
// return ifr.ifr_ifindex;
// }
pub fn fstat(fd: i32, stat_buf: &Stat) usize {
return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
}
@ -749,7 +853,7 @@ pub fn epoll_create1(flags: usize) usize {
return syscall1(SYS_epoll_create1, flags);
}
pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize {
pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize {
return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
}

View File

@ -133,6 +133,7 @@ fn early_seq(c: u8) void {
early_points[early_seq_index] = c;
early_seq_index += 1;
}
<<<<<<< HEAD
test "coro allocation failure" {
var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
@ -224,3 +225,17 @@ async fn printTrace(p: promise->error!void) void {
}
};
}
test "coroutine in a struct field" {
const Foo = struct {
bar: async fn() void,
};
var foo = Foo {
.bar = simpleAsyncFn2,
};
cancel try async<std.debug.global_allocator> foo.bar();
}
async fn simpleAsyncFn2() void {
suspend;
}