reports icon indicating copy to clipboard operation
reports copied to clipboard

FB9922280: Deadlock in thread_suspend() under Rosetta

Open nickdowell opened this issue 3 years ago • 0 comments

  • Date: 2022-02-22
  • Resolution: Open
  • Area: ‌Something else not on this list
  • OS: macOS 11, 12
  • Type: Incorrect/Unexpected Behavior

Description

The thread_suspend() Mach API will sometimes deadlock when called from an Intel process running on a Mac with Apple Silicon.

This can be replicated by the following code in a unit test class, and using Xcode's "Run Repeatedly..." functionality to run the test 1000 times:

- (void)testThreadDeadlock {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    const int threadCount = 1000;
    for (int i = 0; i < threadCount; i++) {
        [NSThread detachNewThreadSelector:@selector(waitForSemaphore:) toTarget:self withObject:semaphore];
    }
    
    thread_t thisThread = mach_thread_self();
    thread_t *threads = NULL;
    mach_msg_type_number_t numThreads = 0;
    task_threads(mach_task_self(), &threads, &numThreads);
    
    for (mach_msg_type_number_t i = 0; i < numThreads; i++) {
        if (threads[i] != thisThread) {
            thread_suspend(threads[i]); // <--- this call will sometimes deadlock
        }
    }
    
    for (mach_msg_type_number_t i = 0; i < numThreads; i++) {
        if (threads[i] != thisThread) {
            thread_resume(threads[i]);
        }
    }
    
    vm_deallocate(mach_task_self(), threads, sizeof(*threads) * numThreads);
    
    for (int i = 0; i < threadCount; i++) {
        dispatch_semaphore_signal(semaphore);
    }
}

- (void)waitForSemaphore:(dispatch_semaphore_t)semaphore {
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

I was not able to reproduce the deadlock if spawning the threads with pthread_create() instead of +[NSThread detachNewThreadSelector:toTarget:withObject:]

A demonstrative spindump of a deadlocked xctest process is attached.

A similar deadlock can also occur in thread_info() if it is used after the threads are suspended.

Files

xctest_34470.spindump.txt

nickdowell avatar Feb 23 '22 08:02 nickdowell