Repository navigation
Fix Computer Use onboarding and preference notification deadlocks #12565
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
f9587a5
Fix Computer Use companion review findings
lawrencecchen 68840ea
Fix current-main surface provider visibility
lawrencecchen 8a6d5da
fix: restore cloud receipt helpers after recovery revert
austinywang 5d29051
fix: restore Cloud provider ownership after recovery revert
austinywang aec49e0
Merge current main into Computer Use follow-up
lawrencecchen b06d37c
Remove duplicate pending mutation helpers
lawrencecchen 7ce2914
fix: stabilize Cloud row view actor isolation
austinywang c6a685c
Fix Cloud drag test window override
lawrencecchen dde61c9
Keep Cloud row formatters nonisolated
lawrencecchen a54a0fd
Fix Cloud hover pointer coordinate conversion
lawrencecchen 10d8f39
Merge latest main into Computer Use follow-up
lawrencecchen a8ea33d
Merge remote-tracking branch 'origin/main' into fix-computer-use-review
lawrencecchen 9bd572f
test: cover background defaults notification deadlock
lawrencecchen add1e7c
fix: prevent preference observers from blocking background writers
lawrencecchen 467ea51
test: cover missing window visibility and repeated onboarding layout
lawrencecchen d036a22
Use main’s scoped Cloud row actor isolation fix
lawrencecchen b650ddb
fix: preserve offscreen window metadata with raw window IDs
lawrencecchen 5f157e0
test: isolate invalid relay ownership selectors
lawrencecchen 9f68cca
Merge remote-tracking branch 'origin/main' into fix-computer-use-review
lawrencecchen cd2f743
Merge remote-tracking branch 'origin/main' into fix-computer-use-review
lawrencecchen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
29 changes: 29 additions & 0 deletions
29
Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/NotificationCenter+UserDefaults.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| public import Foundation | ||
|
|
||
| extension NotificationCenter { | ||
| /// Observes preference changes on the main actor without blocking background writers. | ||
| /// | ||
| /// Main-thread posts retain synchronous delivery. Background posts schedule | ||
| /// the callback and return before it runs. Foundation's `queue: .main` | ||
| /// observer blocks the posting thread, which can deadlock a lazy initializer | ||
| /// when the main thread is waiting for its value. | ||
| /// | ||
| /// - Parameters: | ||
| /// - object: The preferences object to observe, or `nil` for all objects. | ||
| /// - handler: The main-actor action that re-reads the current preferences. | ||
| /// - Returns: An observer token to remove with `removeObserver(_:)` at teardown. | ||
| public func addUserDefaultsObserver( | ||
| object: AnyObject? = nil, | ||
| using handler: @escaping @MainActor @Sendable () -> Void | ||
| ) -> any NSObjectProtocol { | ||
| // This callback is the Foundation notification boundary. Never make a | ||
| // preference writer wait for an operation on the main queue. | ||
| addObserver(forName: UserDefaults.didChangeNotification, object: object, queue: nil) { _ in | ||
| if Thread.isMainThread { | ||
| MainActor.assumeIsolated { handler() } | ||
| } else { | ||
| Task { @MainActor in handler() } | ||
| } | ||
| } | ||
| } | ||
| } |
61 changes: 61 additions & 0 deletions
61
...acOS/CmuxFoundation/Tests/CmuxFoundationTests/UserDefaultsNotificationDeliveryTests.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import Foundation | ||
| import Testing | ||
| @testable import CmuxFoundation | ||
|
|
||
| @Suite("Preference notification delivery") | ||
| struct UserDefaultsNotificationDeliveryTests { | ||
| @Test @MainActor func mainThreadPostsDeliverSynchronously() { | ||
| let center = NotificationCenter() | ||
| var deliveries = 0 | ||
| let observer = center.addUserDefaultsObserver { deliveries += 1 } | ||
| defer { center.removeObserver(observer) } | ||
|
|
||
| center.post(name: UserDefaults.didChangeNotification, object: nil) | ||
|
|
||
| #expect(deliveries == 1) | ||
| } | ||
|
|
||
| @Test(.timeLimit(.minutes(1))) @MainActor | ||
| func backgroundWriterReturnsWhileMainThreadIsOccupied() async { | ||
| let center = NotificationCenter() | ||
| let (deliveries, continuation) = AsyncStream<Void>.makeStream() | ||
| let observer = center.addUserDefaultsObserver { | ||
| MainActor.preconditionIsolated() | ||
| continuation.yield() | ||
| } | ||
| defer { | ||
| center.removeObserver(observer) | ||
| continuation.finish() | ||
| } | ||
| let posted = DispatchSemaphore(value: 0) | ||
| Thread.detachNewThread { | ||
| center.post(name: UserDefaults.didChangeNotification, object: nil) | ||
| posted.signal() | ||
| } | ||
| // Hold main until the writer returns, with a finite failure deadline. | ||
| // A synchronous main-queue observer cannot complete this sequence. | ||
| #expect(Self.waitForPostWhileMainThreadIsOccupied(posted)) | ||
| var iterator = deliveries.makeAsyncIterator() | ||
| #expect(await iterator.next() != nil) | ||
| } | ||
|
|
||
| @MainActor private static func waitForPostWhileMainThreadIsOccupied(_ posted: DispatchSemaphore) -> Bool { | ||
| posted.wait(timeout: .now() + 1) == .success | ||
| } | ||
|
|
||
| @Test @MainActor func objectFilteringAndRemovalRemainEffective() { | ||
| let center = NotificationCenter() | ||
| let expected = NSObject() | ||
| let other = NSObject() | ||
| var deliveries = 0 | ||
| let observer = center.addUserDefaultsObserver(object: expected) { deliveries += 1 } | ||
| center.post(name: UserDefaults.didChangeNotification, object: other) | ||
| #expect(deliveries == 0) | ||
| center.post(name: UserDefaults.didChangeNotification, object: expected) | ||
| #expect(deliveries == 1) | ||
|
|
||
| center.removeObserver(observer) | ||
| center.post(name: UserDefaults.didChangeNotification, object: expected) | ||
| #expect(deliveries == 1) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.