Skip to content

Commit 4a99b64

Browse files
authored
Fix issue where the IPC server can fully consume a CPU core and prevent incoming connections (dotnet#102413)
1 parent 761c9a5 commit 4a99b64

File tree

4 files changed

+41
-1
lines changed

4 files changed

+41
-1
lines changed

src/native/eventpipe/ds-ipc-pal-namedpipe.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,25 @@ ds_ipc_free (DiagnosticsIpc *ipc)
173173
ep_rt_object_free (ipc);
174174
}
175175

176+
void
177+
ds_ipc_reset (DiagnosticsIpc *ipc)
178+
{
179+
if (!ipc)
180+
return;
181+
182+
if (ipc->pipe != INVALID_HANDLE_VALUE) {
183+
CloseHandle (ipc->pipe);
184+
ipc->pipe = INVALID_HANDLE_VALUE;
185+
}
186+
187+
if (ipc->overlap.hEvent != INVALID_HANDLE_VALUE) {
188+
CloseHandle (ipc->overlap.hEvent);
189+
ipc->overlap.hEvent = INVALID_HANDLE_VALUE;
190+
}
191+
192+
ipc->is_listening = false;
193+
}
194+
176195
int32_t
177196
ds_ipc_poll (
178197
DiagnosticsIpcPollHandle *poll_handles_data,
@@ -192,6 +211,10 @@ ds_ipc_poll (
192211
// SERVER
193212
EP_ASSERT (poll_handles_data [i].ipc->mode == DS_IPC_CONNECTION_MODE_LISTEN);
194213
handles [i] = poll_handles_data [i].ipc->overlap.hEvent;
214+
if (handles [i] == INVALID_HANDLE_VALUE) {
215+
// Invalid handle, wait will fail. Signal error
216+
poll_handles_data [i].events = DS_IPC_POLL_EVENTS_ERR;
217+
}
195218
} else {
196219
// CLIENT
197220
bool success = true;

src/native/eventpipe/ds-ipc-pal-socket.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,11 @@ ds_ipc_free (DiagnosticsIpc *ipc)
10641064
ep_rt_object_free (ipc);
10651065
}
10661066

1067+
void
1068+
ds_ipc_reset (DiagnosticsIpc *ipc)
1069+
{
1070+
}
1071+
10671072
int32_t
10681073
ds_ipc_poll (
10691074
DiagnosticsIpcPollHandle *poll_handles_data,

src/native/eventpipe/ds-ipc-pal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ ds_ipc_alloc (
3535
void
3636
ds_ipc_free (DiagnosticsIpc *ipc);
3737

38+
void
39+
ds_ipc_reset (DiagnosticsIpc *ipc);
40+
3841
// Poll
3942
// Parameters:
4043
// - IpcPollHandle * poll_handles_data: Array of IpcPollHandles to poll

src/native/eventpipe/ds-ipc.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ ds_ipc_stream_factory_get_next_available_stream (ds_ipc_error_callback_func call
431431
DS_LOG_INFO_2 ("ds_ipc_stream_factory_get_next_available_stream - NON :: Poll attempt: %d, connection %d had no events.", poll_attempts, connection_id);
432432
break;
433433
default:
434+
ds_port_reset_vcall ((DiagnosticsPort *)ipc_poll_handle.user_data, callback);
434435
DS_LOG_INFO_2 ("ds_ipc_stream_factory_get_next_available_stream - UNK :: Poll attempt: %d, connection %d had invalid PollEvent.", poll_attempts, connection_id);
435436
saw_error = true;
436437
break;
@@ -441,6 +442,12 @@ ds_ipc_stream_factory_get_next_available_stream (ds_ipc_error_callback_func call
441442
}
442443

443444
if (!stream && saw_error) {
445+
// Some errors can cause the poll to return instantly, we want to delay if we see an error to avoid
446+
// runaway CPU usage.
447+
if (poll_timeout_ms == DS_IPC_TIMEOUT_INFINITE)
448+
poll_timeout_ms = DS_IPC_POLL_TIMEOUT_MAX_MS;
449+
DS_LOG_DEBUG_1 ("ds_ipc_stream_factory_get_next_available_stream - Saw error, sleeping using timeout: %dms.", poll_timeout_ms);
450+
ep_rt_thread_sleep ((uint64_t)poll_timeout_ms * NUM_NANOSECONDS_IN_1_MS);
444451
_ds_current_port = NULL;
445452
ep_raise_error ();
446453
}
@@ -839,7 +846,9 @@ listen_port_reset (
839846
ds_ipc_error_callback_func callback)
840847
{
841848
EP_ASSERT (object != NULL);
842-
return;
849+
DiagnosticsListenPort *listen_port = (DiagnosticsListenPort *)object;
850+
ds_ipc_reset (listen_port->port.ipc);
851+
ds_ipc_listen (listen_port->port.ipc, callback);
843852
}
844853

845854
static DiagnosticsPortVtable listen_port_vtable = {

0 commit comments

Comments
 (0)