Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ pub const store = struct {
// whose tests no std-only test root of their own reaches. `Layout`'s own `test` block brings in
// the split trees, seeds, regions, drop plans and view drag beside it.
test {
_ = update.update_notify;
_ = settings.Settings;
_ = view.ViewHost;
_ = layout.Layout;
Expand Down
58 changes: 0 additions & 58 deletions app/update/bounded_join.zig

This file was deleted.

43 changes: 35 additions & 8 deletions app/update/update_notify.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const core = @import("core");
const auto_update = @import("auto_update.zig");
const update_install = @import("update_install.zig");
const move_offer = @import("move_offer.zig");
const bounded_join = @import("bounded_join.zig");
const restart = @import("../restart.zig");

const Phase = enum(u8) {
Expand Down Expand Up @@ -96,7 +95,7 @@ fn startCheck() void {
}

// The worker may outlive `deinit` (see there), so it cannot borrow the app's allocator.
check_thread = std.Thread.spawn(.{}, worker, .{}) catch {
check_thread = std.Thread.spawn(.{}, worker, .{ std.heap.page_allocator, auto_update.checkRemoteVersionSummary }) catch {
phase.store(@backingInt(Phase.done_no), .release);
return;
};
Expand All @@ -107,7 +106,7 @@ fn startCheck() void {
var check_thread: if (auto_update.impl) ?std.Thread else void = if (auto_update.impl) null else {};

/// Set by the check's thread as its last act.
var check_done: std.atomic.Value(bool) = .init(false);
var check_done: std.Io.Event = .unset;

/// How long quit waits on a check still in flight: Velopack's request blocks in C and cannot be
/// cancelled, so past this the thread is detached and the process exit ends it.
Expand All @@ -117,19 +116,28 @@ const quit_wait_ms = 250;
/// so the one given to `setAllocator` may be torn down after this returns.
pub fn deinit(io: std.Io) void {
if (comptime !auto_update.impl) return;
if (check_thread) |thread| _ = bounded_join.joinWithin(io, thread, &check_done, quit_wait_ms);
if (check_thread) |thread| {
if (check_done.waitTimeout(io, .{ .duration = .{ .raw = .fromMilliseconds(quit_wait_ms), .clock = .awake } })) |_| {
thread.join();
} else |_| {
// Timeout or cancellation must both let shutdown proceed.
thread.detach();
}
}
check_thread = null;
}

fn worker() void {
defer check_done.store(true, .release);
fn worker(
gpa: std.mem.Allocator,
check: *const fn (std.Io, std.mem.Allocator, []u8) error{OutOfMemory}!auto_update.CheckSummary,
) void {
// A detached check must also outlive teardown of the application's Io.
const gpa = std.heap.page_allocator;
var threaded: std.Io.Threaded = .init(gpa, .{});
defer threaded.deinit();
const io = threaded.io();
defer check_done.set(io);
var ver_buf: [128]u8 = undefined;
const summary = auto_update.checkRemoteVersionSummary(io, gpa, &ver_buf) catch {
const summary = check(io, gpa, &ver_buf) catch {
phase.store(@backingInt(Phase.done_no), .release);
return;
};
Expand Down Expand Up @@ -424,3 +432,22 @@ fn displayProgressToast(id: dvui.Id) !void {
animator.data().min_size = .{};
}
}

test "launch worker signals completion on success and error" {
const Check = struct {
fn success(_: std.Io, _: std.mem.Allocator, _: []u8) error{OutOfMemory}!auto_update.CheckSummary {
return .no_update;
}
fn failure(_: std.Io, _: std.mem.Allocator, _: []u8) error{OutOfMemory}!auto_update.CheckSummary {
return error.OutOfMemory;
}
};
defer check_done = .unset;
defer phase.store(@backingInt(Phase.pending), .release);
for ([_]@TypeOf(&Check.success){ &Check.success, &Check.failure }) |check| {
check_done = .unset;
worker(std.testing.allocator, check);
try std.testing.expect(check_done.isSet());
try std.testing.expectEqual(AppUpdateState.none, appUpdateState());
}
}
2 changes: 0 additions & 2 deletions build/app.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1108,8 +1108,6 @@ fn addTests(
// /Applications, and what happens to the copy it leaves. std-only (see
// install_location.zig); `macos_bundle.zig` asks the system and acts on it.
.{ "fizzy-install-location-tests", "app/update/install_location.zig" },
// Quit's bounded wait on the launch update check's thread. std-only (see bounded_join.zig).
.{ "fizzy-bounded-join-tests", "app/update/bounded_join.zig" },
// The command palette's recently used commands: order, re-use, the cap. std-only
// (see RecentCommands.zig); `Recents` holds it and stores it in recents.zon.
.{ "fizzy-recent-commands-tests", "app/RecentCommands.zig" },
Expand Down
Loading