Preserve READY ordering after successful native initialization
Reserve the lifecycle event before startup and publish it first only after startup succeeds. This keeps initial macOS and Windows preferences behind READY while failed Wayland initialization emits no READY. Verified 18 core tests, Plasma native lifecycle/pixel tests, and Windows compilation.
This commit is contained in:
parent
685985e9cd
commit
7a7a3493d6
|
|
@ -59,9 +59,13 @@ pub export fn uhdk_app_run(
|
||||||
const application = runtime.fromAppHandle(handle);
|
const application = runtime.fromAppHandle(handle);
|
||||||
if (application.has_run) return abi.UNAVAILABLE;
|
if (application.has_run) return abi.UNAVAILABLE;
|
||||||
profile.thread("UHDK platform");
|
profile.thread("UHDK platform");
|
||||||
|
const ready = runtime.prepareReady(application) catch return abi.OOM;
|
||||||
const status = c.z_native_start(handle, abi.textSpan(application.name));
|
const status = c.z_native_start(handle, abi.textSpan(application.name));
|
||||||
if (status != abi.OK) return status;
|
if (status != abi.OK) {
|
||||||
runtime.simpleEvent(application, c.UHDK_EVENT_READY);
|
runtime.destroyEvent(ready);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
runtime.publishReady(application, ready);
|
||||||
application.entry = entry;
|
application.entry = entry;
|
||||||
application.user = user;
|
application.user = user;
|
||||||
application.running = true;
|
application.running = true;
|
||||||
|
|
|
||||||
|
|
@ -164,3 +164,21 @@ test "poll allocation failure keeps queued terminal completion retryable" {
|
||||||
try std.testing.expectEqual(@as(abi.Status, abi.OK), app_api.uhdk_app_poll_events(handle, 0, &batch));
|
try std.testing.expectEqual(@as(abi.Status, abi.OK), app_api.uhdk_app_poll_events(handle, 0, &batch));
|
||||||
try std.testing.expectEqual(@as(u64, 0), batch.len);
|
try std.testing.expectEqual(@as(u64, 0), batch.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "READY precedes native startup events without being published on failed startup" {
|
||||||
|
const application = try Application.create(std.testing.allocator, std.testing.io, "startup");
|
||||||
|
defer destroyApplication(application);
|
||||||
|
const failed = try runtime.prepareReady(application);
|
||||||
|
try std.testing.expect(application.pending_head == null);
|
||||||
|
runtime.destroyEvent(failed);
|
||||||
|
const ready = try runtime.prepareReady(application);
|
||||||
|
runtime.simpleEvent(application, c.UHDK_EVENT_PREFERENCES_CHANGED);
|
||||||
|
const preferences = application.pending_head.?;
|
||||||
|
runtime.publishReady(application, ready);
|
||||||
|
runtime.simpleEvent(application, c.UHDK_EVENT_WAKE);
|
||||||
|
try std.testing.expectEqual(@as(u32, c.UHDK_EVENT_READY), application.pending_head.?.event.type);
|
||||||
|
try std.testing.expect(ready.next == preferences);
|
||||||
|
try std.testing.expect(ready.event.time_ns <= preferences.event.time_ns);
|
||||||
|
try std.testing.expectEqual(@as(u32, c.UHDK_EVENT_WAKE), preferences.next.?.event.type);
|
||||||
|
try std.testing.expect(application.pending_tail == preferences.next);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,27 @@ pub fn copyPayload(node: *Event) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reserve READY before native initialization, but expose it only after startup
|
||||||
|
// succeeds. Initial preferences/open-file events may arrive during that call.
|
||||||
|
pub fn prepareReady(application: *Application) !*Event {
|
||||||
|
const node = try application.gpa.create(Event);
|
||||||
|
node.* = .{ .gpa = application.gpa, .arena = .init(application.gpa) };
|
||||||
|
node.event.type = c.UHDK_EVENT_READY;
|
||||||
|
node.event.struct_size = @sizeOf(c.z_event);
|
||||||
|
node.event.time_ns = now(application.io) - application.epoch;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn publishReady(application: *Application, node: *Event) void {
|
||||||
|
std.debug.assert(node.event.type == c.UHDK_EVENT_READY);
|
||||||
|
application.lock();
|
||||||
|
defer application.unlock();
|
||||||
|
node.next = application.pending_head;
|
||||||
|
application.pending_head = node;
|
||||||
|
if (application.pending_tail == null) application.pending_tail = node;
|
||||||
|
application.notify();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn simpleEvent(application: *Application, typ: u32) void {
|
pub fn simpleEvent(application: *Application, typ: u32) void {
|
||||||
var event = std.mem.zeroes(c.z_event);
|
var event = std.mem.zeroes(c.z_event);
|
||||||
event.type = typ;
|
event.type = typ;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue