| #ifdef __APPLE__ |
| #include <mach/mach.h> |
| #include <pthread.h> |
| #include <thread> |
| |
| // Get the Mach thread port for a std::thread. Must be called before join(), |
| // because the native_handle is invalidated after join. |
| mach_port_t get_mach_thread(std::thread &t) { |
| return pthread_mach_thread_np(t.native_handle()); |
| } |
| |
| // After join returns, the underlying Mach thread may not have been terminated |
| // yet (pthread_join uses a semaphore that is signaled before the thread calls |
| // thread_terminate). If the debugger stops the process in this window it will |
| // freeze the dying thread, making it appear still alive in task_threads(). Poll |
| // until the specific Mach thread is gone from the task's thread list. |
| void wait_for_thread_cleanup(mach_port_t mach_thread) { |
| while (true) { |
| thread_array_t thread_list; |
| mach_msg_type_number_t count; |
| kern_return_t kr = task_threads(mach_task_self(), &thread_list, &count); |
| if (kr != KERN_SUCCESS) |
| break; |
| bool found = false; |
| for (mach_msg_type_number_t i = 0; i < count; i++) { |
| if (thread_list[i] == mach_thread) |
| found = true; |
| mach_port_deallocate(mach_task_self(), thread_list[i]); |
| } |
| vm_deallocate(mach_task_self(), (vm_address_t)thread_list, |
| count * sizeof(thread_t)); |
| if (!found) |
| break; |
| std::this_thread::yield(); |
| } |
| } |
| #else |
| #include <thread> |
| typedef unsigned int mach_port_t; |
| inline mach_port_t get_mach_thread(std::thread &t) { return 0; } |
| inline void wait_for_thread_cleanup(mach_port_t) {} |
| #endif |