| author | |
| committer | |
| log | 125c4a265aa7cfe82b3fc0c1ac7de75a07315411 |
| tree | 42d85f7fdee5e5efc406b474a14df423ad561bc9 |
| parent | 5f7a0bbabfde4eeb0ff4f40f0942ef710b6104a1 |
This commit re-enables the --webui functionality on windows, with the caveat that rebuild functionality is still disabled (due to deadlocks caused by reading to / writing from the same non-overlapped socket on multiple threads). I updated the UI to be aware of this, and hide the `Rebuild` button.
http.Server: Remove incorrect advance() call. This was causing browsers to disconnect the websocket, as we were sending undefined bytes.
build.WebServer: Re-enable on windows, but disable functionality that requires receiving messages from the client
build-web: Show total times in tables7 files changed, 32 insertions(+), 17 deletions(-)
lib/build-web/index.html+2| ... | ... | @@ -105,6 +105,7 @@ |
| 105 | 105 | <th scope="col">Semantic Analysis</th> |
| 106 | 106 | <th scope="col">Code Generation</th> |
| 107 | 107 | <th scope="col">Linking</th> |
| 108 | <th scope="col">Total</th> | |
| 108 | 109 | </tr> |
| 109 | 110 | </thead> |
| 110 | 111 | <!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility |
| ... | ... | @@ -125,6 +126,7 @@ |
| 125 | 126 | <th scope="col">Semantic Analysis</th> |
| 126 | 127 | <th scope="col">Code Generation</th> |
| 127 | 128 | <th scope="col">Linking</th> |
| 129 | <th scope="col">Total</th> | |
| 128 | 130 | </tr> |
| 129 | 131 | </thead> |
| 130 | 132 | <!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility |
lib/build-web/main.js+13-3| ... | ... | @@ -6,7 +6,7 @@ const domSummary = { |
| 6 | 6 | stepCount: document.getElementById("summaryStepCount"), |
| 7 | 7 | status: document.getElementById("summaryStatus"), |
| 8 | 8 | }; |
| 9 | const domButtonRebuild = document.getElementById("buttonRebuild"); | |
| 9 | let domButtonRebuild = document.getElementById("buttonRebuild"); | |
| 10 | 10 | const domStepList = document.getElementById("stepList"); |
| 11 | 11 | let domSteps = []; |
| 12 | 12 | |
| ... | ... | @@ -114,7 +114,13 @@ function hello( |
| 114 | 114 | steps_len, |
| 115 | 115 | build_status, |
| 116 | 116 | time_report, |
| 117 | supports_recv, | |
| 117 | 118 | ) { |
| 119 | if (!supports_recv && domButtonRebuild) { | |
| 120 | domButtonRebuild.remove(); | |
| 121 | domButtonRebuild = null; | |
| 122 | } | |
| 123 | ||
| 118 | 124 | domSummary.stepCount.textContent = steps_len; |
| 119 | 125 | updateBuildStatus(build_status); |
| 120 | 126 | setConnectionStatus("", false); |
| ... | ... | @@ -161,11 +167,15 @@ function updateBuildStatus(s) { |
| 161 | 167 | if (active) { |
| 162 | 168 | domSummary.status.classList.add("status-running"); |
| 163 | 169 | domSummary.status.classList.remove("status-idle"); |
| 164 | domButtonRebuild.disabled = true; | |
| 170 | if (domButtonRebuild) { | |
| 171 | domButtonRebuild.disabled = true; | |
| 172 | } | |
| 165 | 173 | } else { |
| 166 | 174 | domSummary.status.classList.remove("status-running"); |
| 167 | 175 | domSummary.status.classList.add("status-idle"); |
| 168 | domButtonRebuild.disabled = false; | |
| 176 | if (domButtonRebuild) { | |
| 177 | domButtonRebuild.disabled = false; | |
| 178 | } | |
| 169 | 179 | } |
| 170 | 180 | if (reset_time_reports) { |
| 171 | 181 | // Grey out and collapse all the time reports |
lib/build-web/main.zig+2-1| ... | ... | @@ -30,6 +30,7 @@ const js = struct { |
| 30 | 30 | steps_len: u32, |
| 31 | 31 | status: abi.BuildStatus, |
| 32 | 32 | time_report: bool, |
| 33 | supports_recv: bool, | |
| 33 | 34 | ) void; |
| 34 | 35 | extern "core" fn updateBuildStatus(status: abi.BuildStatus) void; |
| 35 | 36 | extern "core" fn updateStepStatus(step_idx: u32) void; |
| ... | ... | @@ -160,7 +161,7 @@ fn helloMessage(msg_bytes: []align(4) u8) Allocator.Error!void { |
| 160 | 161 | step_list = steps; |
| 161 | 162 | step_list_data = duped_step_name_data; |
| 162 | 163 | |
| 163 | js.hello(step_list.len, hdr.status, hdr.flags.time_report); | |
| 164 | js.hello(step_list.len, hdr.status, hdr.flags.time_report, hdr.flags.supports_recv); | |
| 164 | 165 | } |
| 165 | 166 | fn statusUpdateMessage(msg_bytes: []u8) Allocator.Error!void { |
| 166 | 167 | if (msg_bytes.len < @sizeOf(abi.StatusUpdate)) @panic("malformed StatusUpdate message"); |
lib/build-web/time_report.zig+4| ... | ... | @@ -175,6 +175,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { |
| 175 | 175 | \\ <td>{D}</td> |
| 176 | 176 | \\ <td>{D}</td> |
| 177 | 177 | \\ <td>{D}</td> |
| 178 | \\ <td>{D}</td> | |
| 178 | 179 | \\</tr> |
| 179 | 180 | \\ |
| 180 | 181 | , .{ |
| ... | ... | @@ -182,6 +183,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { |
| 182 | 183 | file.ns_sema, |
| 183 | 184 | file.ns_codegen, |
| 184 | 185 | file.ns_link, |
| 186 | file.ns_sema + file.ns_codegen + file.ns_link, | |
| 185 | 187 | }); |
| 186 | 188 | } |
| 187 | 189 | if (slowest_files.len > max_table_rows) { |
| ... | ... | @@ -203,6 +205,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { |
| 203 | 205 | \\ <td>{D}</td> |
| 204 | 206 | \\ <td>{D}</td> |
| 205 | 207 | \\ <td>{D}</td> |
| 208 | \\ <td>{D}</td> | |
| 206 | 209 | \\</tr> |
| 207 | 210 | \\ |
| 208 | 211 | , .{ |
| ... | ... | @@ -212,6 +215,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { |
| 212 | 215 | decl.ns_sema, |
| 213 | 216 | decl.ns_codegen, |
| 214 | 217 | decl.ns_link, |
| 218 | decl.ns_sema + decl.ns_codegen + decl.ns_link, | |
| 215 | 219 | }); |
| 216 | 220 | } |
| 217 | 221 | if (slowest_decls.len > max_table_rows) { |
lib/std/Build/WebServer.zig+8-11| ... | ... | @@ -65,16 +65,6 @@ pub fn init(opts: Options) WebServer { |
| 65 | 65 | std.process.fatal("--webui not yet implemented for single-threaded builds", .{}); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | if (builtin.os.tag == .windows) { | |
| 69 | // At the time of writing, there are two bugs in the standard library which break this feature on Windows: | |
| 70 | // * Reading from a socket on one thread while writing to it on another seems to deadlock. | |
| 71 | // * Vectored writes to sockets currently trigger an infinite loop when a buffer has length 0. | |
| 72 | // | |
| 73 | // Both of these bugs are expected to be solved by changes which are currently in the unmerged | |
| 74 | // 'wrangle-writer-buffering' branch. Until that makes it in, this must remain disabled. | |
| 75 | std.process.fatal("--webui is currently disabled on Windows due to bugs", .{}); | |
| 76 | } | |
| 77 | ||
| 78 | 68 | const all_steps = opts.all_steps; |
| 79 | 69 | |
| 80 | 70 | const step_names_trailing = opts.gpa.alloc(u8, len: { |
| ... | ... | @@ -297,13 +287,20 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 297 | 287 | copy.* = @atomicLoad(u8, shared, .monotonic); |
| 298 | 288 | } |
| 299 | 289 | |
| 300 | _ = try std.Thread.spawn(.{}, recvWebSocketMessages, .{ ws, sock }); | |
| 290 | // Calling WSARecvFrom on one thread while another calls WSASend deadlocks. | |
| 291 | // This functionality is disabled until std.net uses overlapped sockets on Windows. | |
| 292 | const supports_recv = builtin.os.tag != .windows; | |
| 293 | const recv_thread = if (supports_recv) | |
| 294 | try std.Thread.spawn(.{}, recvWebSocketMessages, .{ ws, sock }) | |
| 295 | else {}; | |
| 296 | defer if (supports_recv) recv_thread.join(); | |
| 301 | 297 | |
| 302 | 298 | { |
| 303 | 299 | const hello_header: abi.Hello = .{ |
| 304 | 300 | .status = prev_build_status, |
| 305 | 301 | .flags = .{ |
| 306 | 302 | .time_report = ws.graph.time_report, |
| 303 | .supports_recv = supports_recv, | |
| 307 | 304 | }, |
| 308 | 305 | .timestamp = ws.now(), |
| 309 | 306 | .steps_len = @intCast(ws.all_steps.len), |
lib/std/Build/abi.zig+3-1| ... | ... | @@ -103,7 +103,9 @@ pub const Hello = extern struct { |
| 103 | 103 | pub const Flags = packed struct(u16) { |
| 104 | 104 | /// Whether time reporting is enabled. |
| 105 | 105 | time_report: bool, |
| 106 | _: u15 = 0, | |
| 106 | /// If this platform supports receiving messages from the client | |
| 107 | supports_recv: bool, | |
| 108 | _: u14 = 0, | |
| 107 | 109 | }; |
| 108 | 110 | }; |
| 109 | 111 | /// WebSocket server->client. |
lib/std/http/Server.zig-1| ... | ... | @@ -546,7 +546,6 @@ pub const Request = struct { |
| 546 | 546 | try out.writeAll("connection: upgrade\r\nupgrade: websocket\r\nsec-websocket-accept: "); |
| 547 | 547 | const base64_digest = try out.writableArray(28); |
| 548 | 548 | assert(std.base64.standard.Encoder.encode(base64_digest, &digest).len == base64_digest.len); |
| 549 | out.advance(base64_digest.len); | |
| 550 | 549 | try out.writeAll("\r\n"); |
| 551 | 550 | |
| 552 | 551 | for (options.extra_headers) |header| { |