Skip to content

Commit

Permalink
Fix debugger thread shutdown hang.
Browse files Browse the repository at this point in the history
The previous fix from the <= 2021.2 version of Unity/Mono was to call
mono_threads_suspend_abort_syscall inside transport_close1.
mono_threads_suspend_abort_syscall interrupts the debugger thread and
and forces the debugger thread to cancel pending IO (CancelIo.)
mono_threads_suspend_abort_syscall does not block.

This causes a race condition if the closesocket call in transport_close1
executes before CancelIo can be called on the debugger thread.

This fix moves the call to mono_threads_suspend_abort_syscall
stop_debugger_thread where we can use the existing wait code to ensure
we have cancelled the IO call.

fixes case 1374958

Previous fix: #574

fix formatting
  • Loading branch information
bholmes authored and UnityAlex committed Dec 9, 2021
1 parent 7084c05 commit 9987317
Showing 1 changed file with 32 additions and 10 deletions.
42 changes: 32 additions & 10 deletions mono/mini/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -1456,9 +1456,6 @@ socket_transport_close1 (void)
/* Close the read part only so it can still send back replies */
/* Also shut down the connection listener so that we can exit normally */
#ifdef HOST_WIN32
MonoThreadInfo* info = mono_thread_info_lookup(debugger_thread_id);
if (info)
mono_threads_suspend_abort_syscall(info);
/* SD_RECEIVE doesn't break the recv in the debugger thread */
shutdown (conn_fd, SD_BOTH);
shutdown (listen_fd, SD_BOTH);
Expand Down Expand Up @@ -1680,14 +1677,9 @@ transport_handshake (void)
}

static void
stop_debugger_thread (void)
wait_for_debugger_thread_to_stop ()
{
if (!agent_inited)
return;

transport_close1 ();

/*
/*
* Wait for the thread to exit.
*
* If we continue with the shutdown without waiting for it, then the client might
Expand All @@ -1704,6 +1696,36 @@ stop_debugger_thread (void)
if (debugger_thread_handle)
mono_thread_info_wait_one_handle (debugger_thread_handle, MONO_INFINITE_WAIT, TRUE);
}
}

static void
stop_debugger_thread (void)
{
if (!agent_inited)
return;

#ifdef HOST_WIN32
gboolean debuggerAttached = mono_is_debugger_attached ();

// We need to make the call to mono_threads_suspend_abort_syscall to break any
// hung accept calls on windows.
MonoThreadInfo* info = mono_thread_info_lookup (debugger_thread_id);
if (info) {
mono_threads_suspend_abort_syscall (info);

// On Windows we must wait for the debugger to stop before
// closing the transport. !debuggerAttached means we are not in
// socket accept, the problematic blocking call.
if (!debuggerAttached)
{
wait_for_debugger_thread_to_stop ();
}
}

#endif
transport_close1 ();

wait_for_debugger_thread_to_stop ();

transport_close2 ();
}
Expand Down

0 comments on commit 9987317

Please sign in to comment.