authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-09 00:52:45-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-09 00:52:45-04:00
loge85a10e9f5f6b17736babd321da8dceb72ea17af
tree70b94f7e1e5f761ad6fe95138ef9832cd0c32baf
parentcbda0fa78c37dd84821061309469c85a2281174c

async tcp server proof of concept


11 files changed, 231 insertions(+), 50 deletions(-)

CMakeLists.txt+1
...@@ -432,6 +432,7 @@ set(ZIG_STD_FILES...@@ -432,6 +432,7 @@ set(ZIG_STD_FILES
432 "dwarf.zig"432 "dwarf.zig"
433 "elf.zig"433 "elf.zig"
434 "empty.zig"434 "empty.zig"
435 "event.zig"
435 "fmt/errol/enum3.zig"436 "fmt/errol/enum3.zig"
436 "fmt/errol/index.zig"437 "fmt/errol/index.zig"
437 "fmt/errol/lookup.zig"438 "fmt/errol/lookup.zig"
src/codegen.cpp+3
...@@ -408,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e...@@ -408,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
408 if (!g->have_err_ret_tracing) {408 if (!g->have_err_ret_tracing) {
409 return UINT32_MAX;409 return UINT32_MAX;
410 }410 }
411 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
412 return 0;
413 }
411 TypeTableEntry *fn_type = fn_table_entry->type_entry;414 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
413 return UINT32_MAX;416 return UINT32_MAX;
src/ir.cpp+22-11
...@@ -2755,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {...@@ -2755,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
27552755
2756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {2756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
2757 Scope *scope = inner_scope;2757 Scope *scope = inner_scope;
2758 bool is_noreturn = false;
2758 while (scope != outer_scope) {2759 while (scope != outer_scope) {
2759 if (!scope)2760 if (!scope)
2760 return false;2761 return is_noreturn;
27612762
2762 if (scope->id == ScopeIdDefer) {2763 if (scope->id == ScopeIdDefer) {
2763 AstNode *defer_node = scope->source_node;2764 AstNode *defer_node = scope->source_node;
...@@ -2770,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -2770,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
2770 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;2771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2771 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);2772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2772 if (defer_expr_value != irb->codegen->invalid_instruction) {2773 if (defer_expr_value != irb->codegen->invalid_instruction) {
2773 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));2774 if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
2775 is_noreturn = true;
2776 } else {
2777 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
2778 }
2774 }2779 }
2775 }2780 }
27762781
2777 }2782 }
2778 scope = scope->parent;2783 scope = scope->parent;
2779 }2784 }
2780 return true;2785 return is_noreturn;
2781}2786}
27822787
2783static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {2788static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
...@@ -2936,12 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2936,12 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2936 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));2941 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
29372942
2938 ir_set_cursor_at_end_and_append_block(irb, return_block);2943 ir_set_cursor_at_end_and_append_block(irb, return_block);
2939 ir_gen_defers_for_block(irb, scope, outer_scope, true);2944 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
2940 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2945 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2941 if (irb->codegen->have_err_ret_tracing && !should_inline) {2946 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2942 ir_build_save_err_ret_addr(irb, scope, node);2947 ir_build_save_err_ret_addr(irb, scope, node);
2948 }
2949 ir_gen_async_return(irb, scope, node, err_val, false);
2943 }2950 }
2944 ir_gen_async_return(irb, scope, node, err_val, false);
29452951
2946 ir_set_cursor_at_end_and_append_block(irb, continue_block);2952 ir_set_cursor_at_end_and_append_block(irb, continue_block);
2947 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);2953 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
...@@ -5695,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -5695,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
56955701
5696 IrBasicBlock *dest_block = loop_scope->continue_block;5702 IrBasicBlock *dest_block = loop_scope->continue_block;
5697 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);5703 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);
5698 return ir_build_br(irb, continue_scope, node, dest_block, is_comptime);5704 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));
5699}5705}
57005706
5701static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {5707static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -6178,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6178,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61786184
6179 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6185 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6180 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6186 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6181 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6187 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
61826188
6183 ir_set_cursor_at_end_and_append_block(irb, resume_block);6189 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6184 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);6190 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
...@@ -6254,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -6254,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62546260
6255 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6261 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6256 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6262 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6257 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6263 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
62586264
6259 ir_set_cursor_at_end_and_append_block(irb, resume_block);6265 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6260 return ir_build_const_void(irb, parent_scope, node);6266 return ir_build_const_void(irb, parent_scope, node);
...@@ -16746,6 +16752,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -16746,6 +16752,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
16746 return ira->codegen->builtin_types.entry_invalid;16752 return ira->codegen->builtin_types.entry_invalid;
1674716753
16748 if (fn_type_id.cc == CallingConventionAsync) {16754 if (fn_type_id.cc == CallingConventionAsync) {
16755 if (instruction->async_allocator_type_value == nullptr) {
16756 ir_add_error(ira, &instruction->base,
16757 buf_sprintf("async fn proto missing allocator type"));
16758 return ira->codegen->builtin_types.entry_invalid;
16759 }
16749 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;16760 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
16750 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);16761 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
16751 if (type_is_invalid(fn_type_id.async_allocator_type))16762 if (type_is_invalid(fn_type_id.async_allocator_type))
std/c/darwin.zig+8
...@@ -55,3 +55,11 @@ pub const dirent = extern struct {...@@ -55,3 +55,11 @@ pub const dirent = extern struct {
55 d_type: u8,55 d_type: u8,
56 d_name: u8, // field address is address of first byte of name56 d_name: u8, // field address is address of first byte of name
57};57};
58
59pub const sockaddr = extern struct {
60 sa_len: u8,
61 sa_family: sa_family_t,
62 sa_data: [14]u8,
63};
64
65pub const sa_family_t = u8;
std/event.zig+36-9
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const event = this;4const event = this;
4const mem = std.mem;5const mem = std.mem;
...@@ -38,7 +39,7 @@ pub const TcpServer = struct {...@@ -38,7 +39,7 @@ pub const TcpServer = struct {
38 {39 {
39 self.handleRequestFn = handleRequestFn;40 self.handleRequestFn = handleRequestFn;
4041
41 try std.os.posixBind(self.sockfd, &address.sockaddr);42 try std.os.posixBind(self.sockfd, &address.os_addr);
42 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);43 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
43 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));44 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
4445
...@@ -59,7 +60,7 @@ pub const TcpServer = struct {...@@ -59,7 +60,7 @@ pub const TcpServer = struct {
59 pub async fn handler(self: &TcpServer) void {60 pub async fn handler(self: &TcpServer) void {
60 while (true) {61 while (true) {
61 var accepted_addr: std.net.Address = undefined;62 var accepted_addr: std.net.Address = undefined;
62 if (std.os.posixAccept(self.sockfd, &accepted_addr.sockaddr,63 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
63 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|64 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
64 {65 {
65 var socket = std.os.File.openHandle(accepted_fd);66 var socket = std.os.File.openHandle(accepted_fd);
...@@ -118,7 +119,7 @@ pub const Loop = struct {...@@ -118,7 +119,7 @@ pub const Loop = struct {
118119
119 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
120 var ev = std.os.linux.epoll_event {121 var ev = std.os.linux.epoll_event {
121 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLET,122 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
122 .data = std.os.linux.epoll_data {123 .data = std.os.linux.epoll_data {
123 .ptr = @ptrToInt(prom),124 .ptr = @ptrToInt(prom),
124 },125 },
...@@ -155,7 +156,24 @@ pub const Loop = struct {...@@ -155,7 +156,24 @@ pub const Loop = struct {
155 }156 }
156};157};
157158
159pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
160 var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
161
162 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
163 errdefer std.os.close(sockfd);
164
165 try std.os.posixConnectAsync(sockfd, &address.os_addr);
166 try await try async loop.waitFd(sockfd);
167 try std.os.posixGetSockOptConnectError(sockfd);
168
169 return std.os.File.openHandle(sockfd);
170}
171
158test "listen on a port, send bytes, receive bytes" {172test "listen on a port, send bytes, receive bytes" {
173 if (builtin.os != builtin.Os.linux) {
174 // TODO build abstractions for other operating systems
175 return;
176 }
159 const MyServer = struct {177 const MyServer = struct {
160 tcp_server: TcpServer,178 tcp_server: TcpServer,
161179
...@@ -198,11 +216,20 @@ test "listen on a port, send bytes, receive bytes" {...@@ -198,11 +216,20 @@ test "listen on a port, send bytes, receive bytes" {
198 defer server.tcp_server.deinit();216 defer server.tcp_server.deinit();
199 try server.tcp_server.listen(addr, MyServer.handler);217 try server.tcp_server.listen(addr, MyServer.handler);
200218
201 var stderr_file = try std.io.getStdErr();219 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address);
202 var stderr_stream = &std.io.FileOutStream.init(&stderr_file).stream;220 defer cancel p;
203 try stderr_stream.print("\nlistening at ");
204 try server.tcp_server.listen_address.format(stderr_stream);
205 try stderr_stream.print("\n");
206
207 loop.run();221 loop.run();
208}222}
223
224async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
225 errdefer @panic("test failure");
226
227 var socket_file = try await try async event.connect(loop, address);
228 defer socket_file.close();
229
230 var buf: [512]u8 = undefined;
231 const amt_read = try socket_file.read(buf[0..]);
232 const msg = buf[0..amt_read];
233 assert(mem.eql(u8, msg, "hello from server\n"));
234 loop.stop();
235}
std/index.zig+1-1
...@@ -50,7 +50,7 @@ test "std" {...@@ -50,7 +50,7 @@ test "std" {
50 _ = @import("dwarf.zig");50 _ = @import("dwarf.zig");
51 _ = @import("elf.zig");51 _ = @import("elf.zig");
52 _ = @import("empty.zig");52 _ = @import("empty.zig");
53 //TODO_ = @import("event.zig");53 _ = @import("event.zig");
54 _ = @import("fmt/index.zig");54 _ = @import("fmt/index.zig");
55 _ = @import("hash/index.zig");55 _ = @import("hash/index.zig");
56 _ = @import("io.zig");56 _ = @import("io.zig");
std/net.zig+19-8
...@@ -1,15 +1,26 @@...@@ -1,15 +1,26 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const net = this;4const net = this;
4const posix = std.os.posix;5const posix = std.os.posix;
5const mem = std.mem;6const mem = std.mem;
67
8pub const TmpWinAddr = struct {
9 family: u8,
10 data: [14]u8,
11};
12
13pub const OsAddress = switch (builtin.os) {
14 builtin.Os.windows => TmpWinAddr,
15 else => posix.sockaddr,
16};
17
7pub const Address = struct {18pub const Address = struct {
8 sockaddr: posix.sockaddr,19 os_addr: OsAddress,
920
10 pub fn initIp4(ip4: u32, port: u16) Address {21 pub fn initIp4(ip4: u32, port: u16) Address {
11 return Address {22 return Address {
12 .sockaddr = posix.sockaddr {23 .os_addr = posix.sockaddr {
13 .in = posix.sockaddr_in {24 .in = posix.sockaddr_in {
14 .family = posix.AF_INET,25 .family = posix.AF_INET,
15 .port = std.mem.endianSwapIfLe(u16, port),26 .port = std.mem.endianSwapIfLe(u16, port),
...@@ -23,7 +34,7 @@ pub const Address = struct {...@@ -23,7 +34,7 @@ pub const Address = struct {
23 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
24 return Address {35 return Address {
25 .family = posix.AF_INET6,36 .family = posix.AF_INET6,
26 .sockaddr = posix.sockaddr {37 .os_addr = posix.sockaddr {
27 .in6 = posix.sockaddr_in6 {38 .in6 = posix.sockaddr_in6 {
28 .family = posix.AF_INET6,39 .family = posix.AF_INET6,
29 .port = std.mem.endianSwapIfLe(u16, port),40 .port = std.mem.endianSwapIfLe(u16, port),
...@@ -37,19 +48,19 @@ pub const Address = struct {...@@ -37,19 +48,19 @@ pub const Address = struct {
3748
38 pub fn initPosix(addr: &const posix.sockaddr) Address {49 pub fn initPosix(addr: &const posix.sockaddr) Address {
39 return Address {50 return Address {
40 .sockaddr = *addr,51 .os_addr = *addr,
41 };52 };
42 }53 }
4354
44 pub fn format(self: &const Address, out_stream: var) !void {55 pub fn format(self: &const Address, out_stream: var) !void {
45 switch (self.sockaddr.in.family) {56 switch (self.os_addr.in.family) {
46 posix.AF_INET => {57 posix.AF_INET => {
47 const native_endian_port = std.mem.endianSwapIfLe(u16, self.sockaddr.in.port);58 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
48 const bytes = ([]const u8)((&self.sockaddr.in.addr)[0..1]);59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
49 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);60 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
50 },61 },
51 posix.AF_INET6 => {62 posix.AF_INET6 => {
52 const native_endian_port = std.mem.endianSwapIfLe(u16, self.sockaddr.in6.port);63 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
53 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);64 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
54 },65 },
55 else => try out_stream.write("(unrecognized address family)"),66 else => try out_stream.write("(unrecognized address family)"),
std/os/darwin.zig+3
...@@ -301,6 +301,9 @@ pub const timespec = c.timespec;...@@ -301,6 +301,9 @@ pub const timespec = c.timespec;
301pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;302pub const dirent = c.dirent;
303303
304pub const sa_family_t = c.sa_family_t;
305pub const sockaddr = c.sockaddr;
306
304/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.307/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
305pub const Sigaction = struct {308pub const Sigaction = struct {
306 handler: extern fn(i32)void,309 handler: extern fn(i32)void,
std/os/index.zig+132-1
...@@ -2217,7 +2217,7 @@ pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) Lin...@@ -2217,7 +2217,7 @@ pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) Lin
22172217
2218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {2218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2219 while (true) {2219 while (true) {
2220 const rc = posix.epoll_wait(epfd, &events[0], u32(events.len), timeout);2220 const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout);
2221 const err = posix.getErrno(rc);2221 const err = posix.getErrno(rc);
2222 switch (err) {2222 switch (err) {
2223 0 => return rc,2223 0 => return rc,
...@@ -2253,3 +2253,134 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {...@@ -2253,3 +2253,134 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,2253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2254 }2254 }
2255}2255}
2256
2257pub const PosixConnectError = error {
2258 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2259 /// file, or search permission is denied for one of the directories in the path prefix.
2260 /// or
2261 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2262 /// the connection request failed because of a local firewall rule.
2263 PermissionDenied,
2264
2265 /// Local address is already in use.
2266 AddressInUse,
2267
2268 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2269 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2270 /// in the ephemeral port range are currently in use. See the discussion of
2271 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2272 AddressNotAvailable,
2273
2274 /// The passed address didn't have the correct address family in its sa_family field.
2275 AddressFamilyNotSupported,
2276
2277 /// Insufficient entries in the routing cache.
2278 SystemResources,
2279
2280 /// A connect() on a stream socket found no one listening on the remote address.
2281 ConnectionRefused,
2282
2283 /// Network is unreachable.
2284 NetworkUnreachable,
2285
2286 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2287 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2288 ConnectionTimedOut,
2289
2290 Unexpected,
2291};
2292
2293pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2294 while (true) {
2295 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2296 const err = posix.getErrno(rc);
2297 switch (err) {
2298 0 => return,
2299 else => return unexpectedErrorPosix(err),
2300
2301 posix.EACCES => return PosixConnectError.PermissionDenied,
2302 posix.EPERM => return PosixConnectError.PermissionDenied,
2303 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2304 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2305 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2306 posix.EAGAIN => return PosixConnectError.SystemResources,
2307 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2308 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2309 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2310 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2311 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2312 posix.EINTR => continue,
2313 posix.EISCONN => unreachable, // The socket is already connected.
2314 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2315 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2316 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2317 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2318 }
2319 }
2320}
2321
2322/// Same as posixConnect except it is for blocking socket file descriptors.
2323/// It expects to receive EINPROGRESS.
2324pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2325 while (true) {
2326 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2327 const err = posix.getErrno(rc);
2328 switch (err) {
2329 0, posix.EINPROGRESS => return,
2330 else => return unexpectedErrorPosix(err),
2331
2332 posix.EACCES => return PosixConnectError.PermissionDenied,
2333 posix.EPERM => return PosixConnectError.PermissionDenied,
2334 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2335 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2336 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2337 posix.EAGAIN => return PosixConnectError.SystemResources,
2338 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2339 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2340 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2341 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2342 posix.EINTR => continue,
2343 posix.EISCONN => unreachable, // The socket is already connected.
2344 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2345 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2346 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2347 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2348 }
2349 }
2350}
2351
2352pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2353 var err_code: i32 = undefined;
2354 var size: u32 = @sizeOf(i32);
2355 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size);
2356 assert(size == 4);
2357 const err = posix.getErrno(rc);
2358 switch (err) {
2359 0 => switch (err_code) {
2360 0 => return,
2361 else => return unexpectedErrorPosix(err),
2362
2363 posix.EACCES => return PosixConnectError.PermissionDenied,
2364 posix.EPERM => return PosixConnectError.PermissionDenied,
2365 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2366 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2367 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2368 posix.EAGAIN => return PosixConnectError.SystemResources,
2369 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2370 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2371 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2372 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2373 posix.EISCONN => unreachable, // The socket is already connected.
2374 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2375 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2376 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2377 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2378 },
2379 else => return unexpectedErrorPosix(err),
2380 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2381 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2382 posix.EINVAL => unreachable,
2383 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2384 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2385 }
2386}
std/os/linux/index.zig+6-6
...@@ -775,12 +775,12 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {...@@ -775,12 +775,12 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
775 return syscall3(SYS_socket, domain, socket_type, protocol);775 return syscall3(SYS_socket, domain, socket_type, protocol);
776}776}
777777
778pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {778pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
779 return syscall5(SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));779 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
780}780}
781781
782pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {782pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
783 return syscall5(SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));783 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
784}784}
785785
786pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {786pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
...@@ -833,14 +833,14 @@ pub fn fstat(fd: i32, stat_buf: &Stat) usize {...@@ -833,14 +833,14 @@ pub fn fstat(fd: i32, stat_buf: &Stat) usize {
833 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));833 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
834}834}
835835
836pub const epoll_data = extern union {836pub const epoll_data = packed union {
837 ptr: usize,837 ptr: usize,
838 fd: i32,838 fd: i32,
839 @"u32": u32,839 @"u32": u32,
840 @"u64": u64,840 @"u64": u64,
841};841};
842842
843pub const epoll_event = extern struct {843pub const epoll_event = packed struct {
844 events: u32,844 events: u32,
845 data: epoll_data,845 data: epoll_data,
846};846};
test/cases/coroutines.zig-14
...@@ -224,17 +224,3 @@ async fn printTrace(p: promise->error!void) void {...@@ -224,17 +224,3 @@ async fn printTrace(p: promise->error!void) void {
224 }224 }
225 };225 };
226}226}
227
228test "coroutine in a struct field" {
229 const Foo = struct {
230 bar: async fn() void,
231 };
232 var foo = Foo {
233 .bar = simpleAsyncFn2,
234 };
235 cancel try async<std.debug.global_allocator> foo.bar();
236}
237
238async fn simpleAsyncFn2() void {
239 suspend;
240}