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
432432 "dwarf.zig"
433433 "elf.zig"
434434 "empty.zig"
435 "event.zig"
435436 "fmt/errol/enum3.zig"
436437 "fmt/errol/index.zig"
437438 "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
408408 if (!g->have_err_ret_tracing) {
409409 return UINT32_MAX;
410410 }
411 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
412 return 0;
413 }
411414 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
413416 return UINT32_MAX;
src/ir.cpp+22-11
......@@ -2755,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
27552755
27562756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
27572757 Scope *scope = inner_scope;
2758 bool is_noreturn = false;
27582759 while (scope != outer_scope) {
27592760 if (!scope)
2760 return false;
2761 return is_noreturn;
27612762
27622763 if (scope->id == ScopeIdDefer) {
27632764 AstNode *defer_node = scope->source_node;
......@@ -2770,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
27702771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
27712772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
27722773 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 }
27742779 }
27752780 }
27762781
27772782 }
27782783 scope = scope->parent;
27792784 }
2780 return true;
2785 return is_noreturn;
27812786}
27822787
27832788static 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,
29362941 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
29372942
29382943 ir_set_cursor_at_end_and_append_block(irb, return_block);
2939 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);
2941 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2942 ir_build_save_err_ret_addr(irb, scope, node);
2944 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
2945 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2946 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2947 ir_build_save_err_ret_addr(irb, scope, node);
2948 }
2949 ir_gen_async_return(irb, scope, node, err_val, false);
29432950 }
2944 ir_gen_async_return(irb, scope, node, err_val, false);
29452951
29462952 ir_set_cursor_at_end_and_append_block(irb, continue_block);
29472953 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
56955701
56965702 IrBasicBlock *dest_block = loop_scope->continue_block;
56975703 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));
56995705}
57005706
57015707static 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
61786184
61796185 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
61806186 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
61836189 ir_set_cursor_at_end_and_append_block(irb, resume_block);
61846190 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
62546260
62556261 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
62566262 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
62596265 ir_set_cursor_at_end_and_append_block(irb, resume_block);
62606266 return ir_build_const_void(irb, parent_scope, node);
......@@ -16746,6 +16752,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1674616752 return ira->codegen->builtin_types.entry_invalid;
1674716753
1674816754 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 }
1674916760 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
1675016761 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
1675116762 if (type_is_invalid(fn_type_id.async_allocator_type))
std/c/darwin.zig+8
......@@ -55,3 +55,11 @@ pub const dirent = extern struct {
5555 d_type: u8,
5656 d_name: u8, // field address is address of first byte of name
5757};
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 @@
11const std = @import("index.zig");
2const builtin = @import("builtin");
23const assert = std.debug.assert;
34const event = this;
45const mem = std.mem;
......@@ -38,7 +39,7 @@ pub const TcpServer = struct {
3839 {
3940 self.handleRequestFn = handleRequestFn;
4041
41 try std.os.posixBind(self.sockfd, &address.sockaddr);
42 try std.os.posixBind(self.sockfd, &address.os_addr);
4243 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
4344 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
4445
......@@ -59,7 +60,7 @@ pub const TcpServer = struct {
5960 pub async fn handler(self: &TcpServer) void {
6061 while (true) {
6162 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,
6364 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
6465 {
6566 var socket = std.os.File.openHandle(accepted_fd);
......@@ -118,7 +119,7 @@ pub const Loop = struct {
118119
119120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
120121 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,
122123 .data = std.os.linux.epoll_data {
123124 .ptr = @ptrToInt(prom),
124125 },
......@@ -155,7 +156,24 @@ pub const Loop = struct {
155156 }
156157};
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
158172test "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 }
159177 const MyServer = struct {
160178 tcp_server: TcpServer,
161179
......@@ -198,11 +216,20 @@ test "listen on a port, send bytes, receive bytes" {
198216 defer server.tcp_server.deinit();
199217 try server.tcp_server.listen(addr, MyServer.handler);
200218
201 var stderr_file = try std.io.getStdErr();
202 var stderr_stream = &std.io.FileOutStream.init(&stderr_file).stream;
203 try stderr_stream.print("\nlistening at ");
204 try server.tcp_server.listen_address.format(stderr_stream);
205 try stderr_stream.print("\n");
206
219 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address);
220 defer cancel p;
207221 loop.run();
208222}
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" {
5050 _ = @import("dwarf.zig");
5151 _ = @import("elf.zig");
5252 _ = @import("empty.zig");
53 //TODO_ = @import("event.zig");
53 _ = @import("event.zig");
5454 _ = @import("fmt/index.zig");
5555 _ = @import("hash/index.zig");
5656 _ = @import("io.zig");
std/net.zig+19-8
......@@ -1,15 +1,26 @@
11const std = @import("index.zig");
2const builtin = @import("builtin");
23const assert = std.debug.assert;
34const net = this;
45const posix = std.os.posix;
56const 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
718pub const Address = struct {
8 sockaddr: posix.sockaddr,
19 os_addr: OsAddress,
920
1021 pub fn initIp4(ip4: u32, port: u16) Address {
1122 return Address {
12 .sockaddr = posix.sockaddr {
23 .os_addr = posix.sockaddr {
1324 .in = posix.sockaddr_in {
1425 .family = posix.AF_INET,
1526 .port = std.mem.endianSwapIfLe(u16, port),
......@@ -23,7 +34,7 @@ pub const Address = struct {
2334 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
2435 return Address {
2536 .family = posix.AF_INET6,
26 .sockaddr = posix.sockaddr {
37 .os_addr = posix.sockaddr {
2738 .in6 = posix.sockaddr_in6 {
2839 .family = posix.AF_INET6,
2940 .port = std.mem.endianSwapIfLe(u16, port),
......@@ -37,19 +48,19 @@ pub const Address = struct {
3748
3849 pub fn initPosix(addr: &const posix.sockaddr) Address {
3950 return Address {
40 .sockaddr = *addr,
51 .os_addr = *addr,
4152 };
4253 }
4354
4455 pub fn format(self: &const Address, out_stream: var) !void {
45 switch (self.sockaddr.in.family) {
56 switch (self.os_addr.in.family) {
4657 posix.AF_INET => {
47 const native_endian_port = std.mem.endianSwapIfLe(u16, self.sockaddr.in.port);
48 const bytes = ([]const u8)((&self.sockaddr.in.addr)[0..1]);
58 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
4960 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
5061 },
5162 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);
5364 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
5465 },
5566 else => try out_stream.write("(unrecognized address family)"),
std/os/darwin.zig+3
......@@ -301,6 +301,9 @@ pub const timespec = c.timespec;
301301pub const Stat = c.Stat;
302302pub const dirent = c.dirent;
303303
304pub const sa_family_t = c.sa_family_t;
305pub const sockaddr = c.sockaddr;
306
304307/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
305308pub const Sigaction = struct {
306309 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
22172217
22182218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
22192219 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);
22212221 const err = posix.getErrno(rc);
22222222 switch (err) {
22232223 0 => return rc,
......@@ -2253,3 +2253,134 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
22532253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
22542254 }
22552255}
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 {
775775 return syscall3(SYS_socket, domain, socket_type, protocol);
776776}
777777
778pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {
779 return syscall5(SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));
778pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
779 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
780780}
781781
782pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
783 return syscall5(SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));
782pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
783 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
784784}
785785
786786pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
......@@ -833,14 +833,14 @@ pub fn fstat(fd: i32, stat_buf: &Stat) usize {
833833 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
834834}
835835
836pub const epoll_data = extern union {
836pub const epoll_data = packed union {
837837 ptr: usize,
838838 fd: i32,
839839 @"u32": u32,
840840 @"u64": u64,
841841};
842842
843pub const epoll_event = extern struct {
843pub const epoll_event = packed struct {
844844 events: u32,
845845 data: epoll_data,
846846};
test/cases/coroutines.zig-14
......@@ -224,17 +224,3 @@ async fn printTrace(p: promise->error!void) void {
224224 }
225225 };
226226}
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}