ReviewOS

also looking at this

craft-native/craft

fix(ios): report async pool exhaustion as busy

#267
Merged glennmichael123 wants to merge codex/ios-busy-error-code into main
19 files +53 -65

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/zig/src/bridge_mobile_calendar.zigmodified+2-5
Changes to packages/zig/src/bridge_mobile_calendar.zig
@@ -419,16 +419,13 @@ fn requestAccess(store: Id, sels: Sels, ticket: ios_async.Ticket) void {
419419 request(store, sels.request_access, ek_entity_type_event, accessBlock(ticket));
420420}
421421
422/// The answer for a full block pool, copied from `bridge_mobile_location`:
423/// `BridgeError` has no "Busy", `INVALID_PARAMETER` is the migration notes'
424/// designated stand-in, and the point is that the caller gets an explicit
425/// rejection instead of a promise that never settles.
422/// Reject a call when every asynchronous reply slot is already in use.
426423fn poolFull(action: []const u8) bridge_error.BridgeError {
427424 std.log.warn(
428425 "{s} refused: all {d} async slots are in flight",
429426 .{ action, ios_async.max_in_flight },
430427 );
431 return bridge_error.BridgeError.InvalidParameter;
428 return bridge_error.BridgeError.Busy;
432429}
433430
434431// =============================================================================
packages/zig/src/bridge_mobile_contacts.zigmodified+2-5
Changes to packages/zig/src/bridge_mobile_contacts.zig
@@ -343,16 +343,13 @@ pub const ContactsBridge = struct {
343343 }
344344};
345345
346/// The answer for a full block pool, copied from `bridge_mobile_location` and
347/// the picker: `BridgeError` has no "Busy", `INVALID_PARAMETER` is the
348/// migration notes' designated stand-in, and the point is that the caller gets
349/// an explicit rejection instead of a promise that never settles.
346/// Reject a call when every asynchronous reply slot is already in use.
350347fn poolFull(action: []const u8) bridge_error.BridgeError {
351348 std.log.warn(
352349 "{s} refused: all {d} async slots are in flight",
353350 .{ action, ios_async.max_in_flight },
354351 );
355 return bridge_error.BridgeError.InvalidParameter;
352 return bridge_error.BridgeError.Busy;
356353}
357354
358355// =============================================================================
packages/zig/src/bridge_mobile_display.zigmodified+1-1
Changes to packages/zig/src/bridge_mobile_display.zig
@@ -268,7 +268,7 @@ fn requireBundleIdentifier() !void {
268268
269269fn poolFull(action: []const u8) bridge_error.BridgeError {
270270 std.log.warn("{s} refused: all {d} async slots in flight", .{ action, ios_async.max_in_flight });
271 return bridge_error.BridgeError.InvalidParameter;
271 return bridge_error.BridgeError.Busy;
272272}
273273
274274/// What a slot's block will answer. The ticket is stored, not rebuilt from the
packages/zig/src/bridge_mobile_filepicker.zigmodified+4-7
Changes to packages/zig/src/bridge_mobile_filepicker.zig
@@ -428,7 +428,7 @@ pub const FilePickerBridge = struct {
428428 "pending reply; refusing the second call rather than stranding the first",
429429 .{},
430430 );
431 return BridgeError.InvalidParameter;
431 return BridgeError.Busy;
432432 }
433433
434434 const PresentFn = *const fn (Id, Id, Id, bool, Id) callconv(.c) void;
@@ -543,7 +543,7 @@ pub const FilePickerBridge = struct {
543543 "downloadFile: no free reply slot; {d} native calls are already awaiting one",
544544 .{ios_async.max_in_flight},
545545 );
546 return BridgeError.NativeCallFailed;
546 return BridgeError.Busy;
547547 };
548548 errdefer ios_async.abandon(ticket);
549549
@@ -562,13 +562,10 @@ pub const FilePickerBridge = struct {
562562 }
563563};
564564
565/// The answer for a full block pool, in the shape `bridge_mobile_location.zig`
566/// uses: `BridgeError` has no "Busy", `INVALID_PARAMETER` is the migration
567/// notes' designated stand-in, and the point is that the seventeenth concurrent
568/// call gets an explicit rejection instead of a promise that never settles.
565/// Reject a call when every asynchronous reply slot is already in use.
569566fn poolFull() BridgeError {
570567 std.log.warn("pickFile refused: all {d} async slots in flight", .{ios_async.max_in_flight});
571 return BridgeError.InvalidParameter;
568 return BridgeError.Busy;
572569}
573570
574571fn selector(name: [*:0]const u8) !Id {