[PATCH v5 0/1] MR9579: ntdll: On macOS, convert the main thread into a Wine system thread on launch.
Currently, the process's main thread runs `main()` -> `__wine_main()` -> `apple_main_thread()` -> `CFRunLoopRun()`. A run loop source is added that creates the Wine main thread and runs `start_main_thread()`. With this MR, the Wine main thread calls `transform_mac_main_thread()` in `server_init_process()`. ~~That essentially calls `NtCreateThreadEx()`, but instead of creating a new pthread it adds a source to the main thread run loop to run `start_thread()`. This transforms the process main thread into a Wine thread, after that it calls the PE `__wine_mac_run_cfrunloop()` in ntdll. That does a run_mac_cfrunloop Unix call, which just runs `CFRunLoopRun()`. The process main thread is now a Wine thread, but is otherwise still a normal Mac application main thread (including the ability for winemac to transform into a Cocoa application).~~ ~~In theory it might be possible to avoid the initial `CFRunLoopRun()` and have `apple_main_thread()` just spawn the Wine main thread and wait to run `start_thread()`, but the extra `CFRunLoopRun()` on the stack doesn't hurt anything.~~ ~~An exception/crash on the process main thread will be caught like a normal syscall fault, but `__wine_mac_run_cfrunloop()` prints an error and terminates the process. I think this is an improvement over the current behavior, which is a segfault in the signal handler when it tries to access the non-existent TEB that results in the thread hanging and eating 100% CPU. (Arguably it would be even better to unregister the signal handler and re-throw the signal so the user gets a normal macOS crash report with a helpful backtrace, maybe this could be done later.)~~ ~~Besides exception handling,~~ having the main thread be a Wine thread will also allow the full use of Wine logging functions (!9503), and should allow winemac to be simplified (where many AppKit functions must be called from the main thread, and events are delivered to the main thread). **Update**: I've pushed a new version of this which is based on/an alternative to Rémi's !11333, just converting the macOS main thread to a Wine system thread at launch. There are no changes needed in winemac, and the conversion is done at process launch (in `server_init_process_done()`) so that winemac and other libraries (i.e. device notifications in winecoreaudio) can depend on the main thread being usable for Wine calls. I'll rebase !9503 next week so logging can be demonstrated too. -- v5: ntdll: Spawn a Wine system thread for the macOS main thread on launch. https://gitlab.winehq.org/wine/wine/-/merge_requests/9579
From: Brendan Shanks <bshanks@codeweavers.com> Based on patches from Rémi Bernon and Alexandre Julliard. --- dlls/ntdll/unix/server.c | 6 +++++- dlls/ntdll/unix/thread.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 1629ee63e63..06eb740914f 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1474,6 +1474,8 @@ static int server_connect(void) #include <mach/mach_error.h> #include <servers/bootstrap.h> +extern NTSTATUS apple_spawn_main_thread(void); + /* send our task port to the server */ static void send_server_task_port(void) { @@ -1754,6 +1756,8 @@ void server_init_process_done(void) #ifdef __APPLE__ send_server_task_port(); + if ((status = apple_spawn_main_thread())) + ERR("Failed to spawn main thread, status %x\n", status); #endif /* Install signal handlers; this cannot be done earlier, since we cannot @@ -1809,7 +1813,7 @@ void server_init_thread( struct thread_data *data ) init_teb_data( data ); signal_start_thread( data->start, data->param, data->teb ); } - else + else if (data->start) { void (*entry)(void *) = data->start; entry( data->param ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 55e52af402a..c6b99b747f8 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -63,6 +63,7 @@ #endif #ifdef __APPLE__ +#include <CoreFoundation/CoreFoundation.h> #include <mach/mach.h> #endif #ifdef __FreeBSD__ @@ -1581,6 +1582,34 @@ void wait_suspend( CONTEXT *context ) } +#ifdef __APPLE__ +/********************************************************************** + * apple_spawn_main_thread + */ +NTSTATUS apple_spawn_main_thread( void ) +{ + struct thread_data *data; + HANDLE handle; + NTSTATUS status; + ULONG flags = THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE; + CFRunLoopSourceContext context = { .perform = (void (*)(void *))server_init_thread }; + CFRunLoopSourceRef source; + + if ((status = create_server_thread( &handle, &data, THREAD_ALL_ACCESS, NULL, NULL, NULL, flags, TRUE ))) + return status; + NtClose( handle ); + + context.info = data; + source = CFRunLoopSourceCreate( NULL, 0, &context ); + CFRunLoopAddSource( CFRunLoopGetMain(), source, kCFRunLoopCommonModes ); + CFRunLoopSourceSignal( source ); + CFRunLoopWakeUp( CFRunLoopGetMain() ); + CFRelease( source ); + return STATUS_SUCCESS; +} +#endif + + /********************************************************************** * send_debug_event * -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9579
participants (2)
-
Brendan Shanks -
Brendan Shanks (@bshanks)