This reworks `set_native_thread_name()` for macOS to not rely on mach thread ports returned server side (which were potentially colliding cross-process anyways) and re-implements what `pthread_setname_np()` would do on wines side, with additionally allowing setting threadnames cross-process.
On the kernel side `bsd_setthreadname()` is apparently "known to race with regards to the contents of the thread name", so that is only exposed for the thread calling it on itself.
Since the pthread struct is private, the location of the thread name is determined at runtime (although in practice, it is constant (80 bytes) from at least 10.15 up to 14.0).
This has an effect on both `pthread_getname_np()` and the `NSThread` implementation on top a native library would use.
Cross-thread naming is only not visible to external debuggers, which have acquired a mach port right and calling `thread_info()` with `THREAD_EXTENDED_INFO`
-- v2: ntdll: Reimplement set_native_thread_name() for macOS.
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/thread.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-)
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 9e84ec3cc96..e1161d28932 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1911,30 +1911,21 @@ static void set_native_thread_name( HANDLE handle, const UNICODE_STRING *name ) close( fd ); } #elif defined(__APPLE__) - /* pthread_setname_np() silently fails if the name is longer than 63 characters + null terminator */ - char nameA[64]; - NTSTATUS status; - int unix_pid, unix_tid, len, current_tid; + char nameA[MAXTHREADNAMESIZE]; + int len; + THREAD_BASIC_INFORMATION info;
- SERVER_START_REQ( get_thread_times ) - { - req->handle = wine_server_obj_handle( handle ); - status = wine_server_call( req ); - if (status == STATUS_SUCCESS) - { - unix_pid = reply->unix_pid; - unix_tid = reply->unix_tid; - } - } - SERVER_END_REQ; - - if (status != STATUS_SUCCESS || unix_pid == -1 || unix_tid == -1) + if (NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL )) return;
- current_tid = mach_thread_self(); - mach_port_deallocate(mach_task_self(), current_tid); + if (HandleToULong( info.ClientId.UniqueProcess ) != GetCurrentProcessId()) + { + static int once; + if (!once++) FIXME("cross-process native thread naming not supported\n"); + return; + }
- if (unix_tid != current_tid) + if (HandleToULong( info.ClientId.UniqueThread ) != GetCurrentThreadId()) { static int once; if (!once++) FIXME("setting other thread name not supported\n"); @@ -1943,7 +1934,7 @@ static void set_native_thread_name( HANDLE handle, const UNICODE_STRING *name )
len = ntdll_wcstoumbs( name->Buffer, name->Length / sizeof(WCHAR), nameA, sizeof(nameA) - 1, FALSE ); nameA[len] = '\0'; - pthread_setname_np(nameA); + pthread_setname_np( nameA ); #else static int once; if (!once++) FIXME("not implemented on this platform\n");
Ah wasn't too sure where these native thread names would be needed and got a bit carried away with the implementation.
If they are just needed for debugging purposes that was indeed overkill, did simplify it so it pretty much only gets rid of the mach port usage.
Thanks, I tested this out and it looks good to me.