| ... | ... | @@ -6,7 +6,7 @@ root_prog_node: std.Progress.Node, |
| 6 | 6 | watch: bool, |
| 7 | 7 | |
| 8 | 8 | tcp_server: ?net.Server, |
| 9 | | serve_thread: ?std.Thread, |
| 9 | serve_task: ?Io.Future(Io.Cancelable!void), |
| 10 | 10 | |
| 11 | 11 | /// Uses `Io.Clock.awake`. |
| 12 | 12 | base_timestamp: Io.Timestamp, |
| ... | ... | @@ -103,7 +103,7 @@ pub fn init(opts: Options) WebServer { |
| 103 | 103 | .watch = opts.watch, |
| 104 | 104 | |
| 105 | 105 | .tcp_server = null, |
| 106 | | .serve_thread = null, |
| 106 | .serve_task = null, |
| 107 | 107 | |
| 108 | 108 | .base_timestamp = opts.base_timestamp.raw, |
| 109 | 109 | .step_names_trailing = step_names_trailing, |
| ... | ... | @@ -136,9 +136,9 @@ pub fn deinit(ws: *WebServer) void { |
| 136 | 136 | gpa.free(ws.time_report_msgs); |
| 137 | 137 | gpa.free(ws.time_report_update_times); |
| 138 | 138 | |
| 139 | | if (ws.serve_thread) |t| { |
| 139 | if (ws.serve_task) |t| { |
| 140 | 140 | if (ws.tcp_server) |*s| s.stream.close(io); |
| 141 | | t.join(); |
| 141 | t.await(); |
| 142 | 142 | } |
| 143 | 143 | if (ws.tcp_server) |*s| s.deinit(); |
| 144 | 144 | |
| ... | ... | @@ -146,15 +146,15 @@ pub fn deinit(ws: *WebServer) void { |
| 146 | 146 | } |
| 147 | 147 | pub fn start(ws: *WebServer) error{AlreadyReported}!void { |
| 148 | 148 | assert(ws.tcp_server == null); |
| 149 | | assert(ws.serve_thread == null); |
| 149 | assert(ws.serve_task == null); |
| 150 | 150 | const io = ws.graph.io; |
| 151 | 151 | |
| 152 | 152 | ws.tcp_server = ws.listen_address.listen(io, .{ .reuse_address = true }) catch |err| { |
| 153 | | log.err("failed to listen to port {d}: {s}", .{ ws.listen_address.getPort(), @errorName(err) }); |
| 153 | log.err("failed to listen to port {d}: {t}", .{ ws.listen_address.getPort(), err }); |
| 154 | 154 | return error.AlreadyReported; |
| 155 | 155 | }; |
| 156 | | ws.serve_thread = std.Thread.spawn(.{}, serve, .{ws}) catch |err| { |
| 157 | | log.err("unable to spawn web server thread: {s}", .{@errorName(err)}); |
| 156 | ws.serve_task = io.concurrent(serve, .{ws}) catch |err| { |
| 157 | log.err("unable to spawn web server thread: {t}", .{err}); |
| 158 | 158 | ws.tcp_server.?.deinit(io); |
| 159 | 159 | ws.tcp_server = null; |
| 160 | 160 | return error.AlreadyReported; |
| ... | ... | @@ -165,15 +165,20 @@ pub fn start(ws: *WebServer) error{AlreadyReported}!void { |
| 165 | 165 | log.info("hint: pass '--webui={f}' to use the same port next time", .{ws.tcp_server.?.socket.address}); |
| 166 | 166 | } |
| 167 | 167 | } |
| 168 | | fn serve(ws: *WebServer) void { |
| 168 | fn serve(ws: *WebServer) Io.Cancelable!void { |
| 169 | 169 | const io = ws.graph.io; |
| 170 | var group: Io.Group = .init; |
| 171 | defer group.cancel(io); |
| 170 | 172 | while (true) { |
| 171 | | var stream = ws.tcp_server.?.accept(io) catch |err| { |
| 172 | | log.err("failed to accept connection: {s}", .{@errorName(err)}); |
| 173 | | return; |
| 173 | var stream = ws.tcp_server.?.accept(io) catch |err| switch (err) { |
| 174 | error.Canceled => |e| return e, |
| 175 | else => |e| { |
| 176 | log.err("failed to accept connection: {t}", .{e}); |
| 177 | return; |
| 178 | }, |
| 174 | 179 | }; |
| 175 | | _ = std.Thread.spawn(.{}, accept, .{ ws, stream }) catch |err| { |
| 176 | | log.err("unable to spawn connection thread: {s}", .{@errorName(err)}); |
| 180 | group.concurrent(io, accept, .{ ws, stream }) catch |err| { |
| 181 | log.err("unable to spawn connection thread: {t}", .{err}); |
| 177 | 182 | stream.close(io); |
| 178 | 183 | continue; |
| 179 | 184 | }; |
| ... | ... | @@ -303,8 +308,8 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 303 | 308 | copy.* = @atomicLoad(u8, shared, .monotonic); |
| 304 | 309 | } |
| 305 | 310 | |
| 306 | | const recv_thread = try std.Thread.spawn(.{}, recvWebSocketMessages, .{ ws, sock }); |
| 307 | | defer recv_thread.join(); |
| 311 | var recv_thread = try io.concurrent(recvWebSocketMessages, .{ ws, sock }); |
| 312 | defer recv_thread.cancel(io); |
| 308 | 313 | |
| 309 | 314 | { |
| 310 | 315 | const hello_header: abi.Hello = .{ |