The function pthread_setname_np takes only one argument on macOS and sets the thread name of the current thread. Basically what it does is call the proc_info syscall as follows (code from the Apple open-source page):
__proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, 0, name, length);
But NSThread's setName method is a (only) way to set the thread's name in another thread (Xcode and lldb show the new name). As there is no source available for the NSThread's implementation, I disassembled the Foundation framework (/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation) and found this code:

As you can see it uses only the pthread_setname_np (it seems that it is being called only if self == [NSThread currentThread]) and does not call the proc_info directly. I tried to debug the setName with a dtruss and found out that proc_info syscall is actually being called on setName event if called from different thread, I got the following line when the call to setName is added to the code:
proc_info(0x5, 0x15496, 0x2) = 0 0
So is there actually a way to set the threads name in a different thread? How is it done? And why the disassembly of the setName has only the pthread_setname_np call?
PS. I know that workaround (trampoline) can be made to pass the name from different thread and then call the pthread_setname_np inside the thread whose name has to be changed but I am interested how setName is actually implemented.
EDIT: I called setName from two different threads and dtruss outputs the following (the first column is pid/tid), 0x4f800a (5210122) is the tid of the thread I am changing the name of:
37555/0x4f800a: 37 6 0 thread_selfid(0x0, 0x0, 0x0) = 5210122 0
37555/0x4f800a: 218 11 5 proc_info(0x5, 0x92B3, 0x2) = 0 0
37555/0x4f800a: 243 6 2 proc_info(0x5, 0x92B3, 0x2) = 0 0
That means that the proc_info call is somehow hooked in the thread's code. Seems like an Objective-C runtime feature.
I added a breakpoint on __proc_info and run the test app with lldb, got the following stack on break:
frame #0: 0x00007fff78401c3c libsystem_kernel.dylib`__proc_info
frame #1: 0x00007fff7853e0b0 libsystem_pthread.dylib`pthread_setname_np + 88
frame #2: 0x00007fff52a7ae88 Foundation`__NSThread__start__ + 1101
frame #3: 0x00007fff7853d6c1 libsystem_pthread.dylib`_pthread_body + 340
frame #4: 0x00007fff7853d56d libsystem_pthread.dylib`_pthread_start + 377
frame #5: 0x00007fff7853cc5d libsystem_pthread.dylib`thread_start + 13
That means that the pthread_setname_np is actually being called in NSThread start method. I added a sleep after starting the NSThread and then called the setName and the name wasn't changed because the thread was already started. That explains everything. So it is impossible to change thread name on a different thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With