[src] Clean/consolidate runtime initialization code between platforms.#26131
[src] Clean/consolidate runtime initialization code between platforms.#26131rolfbjarne wants to merge 4 commits into
Conversation
* Add Runtime.EnsureUIThread (), and call this method from [NS|UI]Application.EnsureUIThread. Also move supporting code to the Runtime class. * Remove NSApplication.EnsureInitialized - this was necessary to ensure `xamarin_initialize` was called when Xamarin.Mac was hosted inside another application (such as Visual Studio for Mac). .NET for macOS no longer supports being hosted inside another application, so this code can be removed. * Remove Runtime.RegisterAssemblies () - it's no longer needed because .NET for macOS doesn't support being hosted inside another app. * Don't set MONO_CFG_DIR anymore - this is *old* code, and shouldn't be needed now. If anybody does, then they can set this variable themselves. * Remove NSApplication.ResetHandle () - it's no longer needed because .NET for macOS doesn't support being hosted inside another app. * Add NSApplication.Initialize () - this mirrors UIApplication.Initialize () * Remove NSApplication.InitDrawBridge () - this is not applicable for .NET for macOS (not fully removed until XAMCORE_5_0) * Remove NSApplication.Init () - this is not needed anymore in .NET for macOS (not fully removed until XAMCORE_5_0) * Make the various [NS|UI]Application.Main methods return 'int' in XAMCORE_5_0. * Misc other dead code fixes. * Misc xml documentation updates.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
The consolidated Runtime.EnsureUIThread returned early when CheckForIllegalCrossThreadCalls was true, which is exactly when the check should run. This meant the UIKit/AppKit cross-thread access exceptions were never thrown, breaking the monotouch-test DispatchTests on iOS/tvOS/Mac Catalyst (they got a NullReferenceException instead of a UIKitThreadAccessException). Invert the condition so the check runs when CheckForIllegalCrossThreadCalls is enabled. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The consolidation moved the AppKitSynchronizationContext setup out of NSApplication.Init and into Runtime.InitializePlatform, which runs during early native startup (xamarin_initialize). Hosts and the test runner (MacRunner) start the main run loop by calling NSApplication.Init followed by NSApplication.SharedApplication.Run, *without* going through NSApplication.Main. On base, NSApplication.Init established the synchronization context on that run-loop thread; after the consolidation it no longer did, so the context was no longer guaranteed to be current on the thread that actually runs the app. This is the same pattern iOS already uses (UIApplication.Main calls UIApplication.Initialize on the run-loop thread), and it fixes the link-all macOS PrintPreview_NSGraphicsContextCurrentContext hang, where the modal print operation could no longer be aborted via a continuation posted to the (missing) AppKit synchronization context. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
🔥 [CI Build #ce719bd] Test results 🔥Test results❌ Tests failed on VSTS: test results 3 tests crashed, 4 tests failed, 178 tests passed. Failures❌ cecil tests1 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ dotnettests tests (iOS)🔥 Failed catastrophically on VSTS: test results - dotnettests_ios (no summary found). Html Report (VSDrops) Download ❌ dotnettests tests (MacCatalyst)1 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ dotnettests tests (macOS)1 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ dotnettests tests (tvOS)1 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (macOS)🔥 Failed catastrophically on VSTS: test results - monotouch_macos (no summary found). Html Report (VSDrops) Download ❌ xtro tests🔥 Failed catastrophically on VSTS: test results - xtro (no summary found). Html Report (VSDrops) Download Successes✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
There was a problem hiding this comment.
Pull request overview
This PR consolidates cross-platform runtime/UI-thread initialization by moving UI-thread enforcement logic into ObjCRuntime.Runtime, and by simplifying AppKit/UIKit initialization paths now that .NET for macOS is no longer hostable inside other applications.
Changes:
- Centralized UI-thread enforcement in
ObjCRuntime.Runtime.EnsureUIThread (), and routedUIApplication.EnsureUIThread/NSApplication.EnsureUIThreadthrough it. - Introduced
NSApplication.Initialize ()(to mirrorUIApplication.Initialize ()) and adjusted macOS runtime platform initialization to call it. - Updated
UIApplication.Main/NSApplication.Mainto returnintunderXAMCORE_5_0and performed associated cleanup of older initialization code paths.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/UIKit/UIApplication.cs | Routes EnsureUIThread to Runtime.EnsureUIThread and updates Main overloads to return int in XAMCORE_5_0. |
| src/ObjCRuntime/Runtime.mac.cs | Calls NSApplication.Initialize () during platform initialization. |
| src/ObjCRuntime/Runtime.iOS.cs | Adds Mac Catalyst product/assembly naming constants and keeps UIApplication.Initialize () as the platform initializer. |
| src/ObjCRuntime/Runtime.cs | Stores main thread during runtime init and introduces centralized EnsureUIThread (). |
| src/AppKit/NSApplication.cs | Adds Initialize (), simplifies Init/Main, and routes EnsureUIThread to Runtime.EnsureUIThread. |
| static void Initialize () | ||
| { | ||
| // `class_ptr` is `readonly` so one can't simply do `class_ptr = Class.GetHandle ("NSApplication");` | ||
| typeof (NSApplication).GetField ("class_ptr", BindingFlags.Static | BindingFlags.NonPublic)?.SetValue (null, Class.GetHandle ("NSApplication")); | ||
| SynchronizationContext.SetSynchronizationContext (new AppKitSynchronizationContext ()); | ||
| } |
| #if TVOS | ||
| internal const string AssemblyName = "Microsoft.tvOS.dll"; | ||
| #elif __MACCATALYST__ | ||
| internal const string AssemblyName = "Microsoft.MacCatalyst"; | ||
| #elif IOS | ||
| internal const string AssemblyName = "Microsoft.iOS.dll"; |
| /// <summary>Assertion to ensure that this call is being done from the UIKit thread.</summary> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// This method is used internally by MonoTouch to ensure that | ||
| /// accesses done to UIKit classes and methods are only | ||
| /// performed from the UIKit thread. This is necessary because | ||
| /// the UIKit API is not thread-safe and accessing it from | ||
| /// multiple threads will corrupt the application state and will | ||
| /// likely lead to a crash that is hard to identify. | ||
| /// </para> | ||
| /// <para> | ||
| /// MonoTouch only performs the thread checks in debug builds. | ||
| /// Release builds have this feature disabled. | ||
| /// </para> | ||
| /// </remarks> |
xamarin_initializewas called when Xamarin.Mac was hosted inside another application (such as Visual Studio for Mac). .NET for macOS no longer supports being hosted inside another application, so this code can be removed.