Skip to content

Commit 125c4a2

Browse files
committed
Fix respondWebSocket, enable --webui on Windows
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 tables
1 parent 5f7a0bb commit 125c4a2

File tree

7 files changed

+32
-17
lines changed

7 files changed

+32
-17
lines changed

lib/build-web/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
<th scope="col">Semantic Analysis</th>
106106
<th scope="col">Code Generation</th>
107107
<th scope="col">Linking</th>
108+
<th scope="col">Total</th>
108109
</tr>
109110
</thead>
110111
<!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility
@@ -125,6 +126,7 @@
125126
<th scope="col">Semantic Analysis</th>
126127
<th scope="col">Code Generation</th>
127128
<th scope="col">Linking</th>
129+
<th scope="col">Total</th>
128130
</tr>
129131
</thead>
130132
<!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility

lib/build-web/main.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const domSummary = {
66
stepCount: document.getElementById("summaryStepCount"),
77
status: document.getElementById("summaryStatus"),
88
};
9-
const domButtonRebuild = document.getElementById("buttonRebuild");
9+
let domButtonRebuild = document.getElementById("buttonRebuild");
1010
const domStepList = document.getElementById("stepList");
1111
let domSteps = [];
1212

@@ -114,7 +114,13 @@ function hello(
114114
steps_len,
115115
build_status,
116116
time_report,
117+
supports_recv,
117118
) {
119+
if (!supports_recv && domButtonRebuild) {
120+
domButtonRebuild.remove();
121+
domButtonRebuild = null;
122+
}
123+
118124
domSummary.stepCount.textContent = steps_len;
119125
updateBuildStatus(build_status);
120126
setConnectionStatus("", false);
@@ -161,11 +167,15 @@ function updateBuildStatus(s) {
161167
if (active) {
162168
domSummary.status.classList.add("status-running");
163169
domSummary.status.classList.remove("status-idle");
164-
domButtonRebuild.disabled = true;
170+
if (domButtonRebuild) {
171+
domButtonRebuild.disabled = true;
172+
}
165173
} else {
166174
domSummary.status.classList.remove("status-running");
167175
domSummary.status.classList.add("status-idle");
168-
domButtonRebuild.disabled = false;
176+
if (domButtonRebuild) {
177+
domButtonRebuild.disabled = false;
178+
}
169179
}
170180
if (reset_time_reports) {
171181
// Grey out and collapse all the time reports

lib/build-web/main.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const js = struct {
3030
steps_len: u32,
3131
status: abi.BuildStatus,
3232
time_report: bool,
33+
supports_recv: bool,
3334
) void;
3435
extern "core" fn updateBuildStatus(status: abi.BuildStatus) void;
3536
extern "core" fn updateStepStatus(step_idx: u32) void;
@@ -160,7 +161,7 @@ fn helloMessage(msg_bytes: []align(4) u8) Allocator.Error!void {
160161
step_list = steps;
161162
step_list_data = duped_step_name_data;
162163

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);
164165
}
165166
fn statusUpdateMessage(msg_bytes: []u8) Allocator.Error!void {
166167
if (msg_bytes.len < @sizeOf(abi.StatusUpdate)) @panic("malformed StatusUpdate message");

lib/build-web/time_report.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,15 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void {
175175
\\ <td>{D}</td>
176176
\\ <td>{D}</td>
177177
\\ <td>{D}</td>
178+
\\ <td>{D}</td>
178179
\\</tr>
179180
\\
180181
, .{
181182
fmtEscapeHtml(file.name),
182183
file.ns_sema,
183184
file.ns_codegen,
184185
file.ns_link,
186+
file.ns_sema + file.ns_codegen + file.ns_link,
185187
});
186188
}
187189
if (slowest_files.len > max_table_rows) {
@@ -203,6 +205,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void {
203205
\\ <td>{D}</td>
204206
\\ <td>{D}</td>
205207
\\ <td>{D}</td>
208+
\\ <td>{D}</td>
206209
\\</tr>
207210
\\
208211
, .{
@@ -212,6 +215,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{OutOfMemory}!void {
212215
decl.ns_sema,
213216
decl.ns_codegen,
214217
decl.ns_link,
218+
decl.ns_sema + decl.ns_codegen + decl.ns_link,
215219
});
216220
}
217221
if (slowest_decls.len > max_table_rows) {

lib/std/Build/WebServer.zig

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,6 @@ pub fn init(opts: Options) WebServer {
6565
std.process.fatal("--webui not yet implemented for single-threaded builds", .{});
6666
}
6767

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-
7868
const all_steps = opts.all_steps;
7969

8070
const step_names_trailing = opts.gpa.alloc(u8, len: {
@@ -297,13 +287,20 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn {
297287
copy.* = @atomicLoad(u8, shared, .monotonic);
298288
}
299289

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();
301297

302298
{
303299
const hello_header: abi.Hello = .{
304300
.status = prev_build_status,
305301
.flags = .{
306302
.time_report = ws.graph.time_report,
303+
.supports_recv = supports_recv,
307304
},
308305
.timestamp = ws.now(),
309306
.steps_len = @intCast(ws.all_steps.len),

lib/std/Build/abi.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ pub const Hello = extern struct {
103103
pub const Flags = packed struct(u16) {
104104
/// Whether time reporting is enabled.
105105
time_report: bool,
106-
_: u15 = 0,
106+
/// If this platform supports receiving messages from the client
107+
supports_recv: bool,
108+
_: u14 = 0,
107109
};
108110
};
109111
/// WebSocket server->client.

lib/std/http/Server.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,6 @@ pub const Request = struct {
546546
try out.writeAll("connection: upgrade\r\nupgrade: websocket\r\nsec-websocket-accept: ");
547547
const base64_digest = try out.writableArray(28);
548548
assert(std.base64.standard.Encoder.encode(base64_digest, &digest).len == base64_digest.len);
549-
out.advance(base64_digest.len);
550549
try out.writeAll("\r\n");
551550

552551
for (options.extra_headers) |header| {

0 commit comments

Comments
 (0)