# UNDF: UNDF-2026-000001053 # UNDF: UNDF-2026-XXXXXXXXX --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net.Sockets; namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl @@ -71,13 +71,19 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl try { int actualTimeoutMicroseconds = timeoutMilliseconds == -1 ? -1 : timeoutMilliseconds * 1000; Socket.Select(readEvents, writeEvents, errorEvents, actualTimeoutMicroseconds); } catch (SocketException exception) { return WinSockHelper.ConvertError((WsaError)exception.ErrorCode); } + // Convert to HashSet after Socket.Select() trims each list to ready sockets. + // List.Contains() is O(S) per call; HashSet.Contains() is O(1). + // Without this, the result loop below is O(E * S) where E = event count, + // S = ready-socket count in each list. At E=500 sockets, cost is ~250,000 ops. + HashSet readSet = new(readEvents); + HashSet writeSet = new(writeEvents); + HashSet errorSet = new(errorEvents); + foreach (PollEvent evnt in events) { Socket socket = ((ManagedSocket)evnt.FileDescriptor).Socket; @@ -85,17 +91,17 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents; - if (errorEvents.Contains(socket)) + if (errorSet.Contains(socket)) { outputEvents |= PollEventTypeMask.Error; if (!socket.Connected || !socket.IsBound) { outputEvents |= PollEventTypeMask.Disconnected; } } - if (readEvents.Contains(socket)) + if (readSet.Contains(socket)) { if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0) { outputEvents |= PollEventTypeMask.Input; } } - if (writeEvents.Contains(socket)) + if (writeSet.Contains(socket)) { outputEvents |= PollEventTypeMask.Output; } @@ -119,6 +125,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl Socket.Select(readEvents, writeEvents, errorEvents, timeout); + // Same O(E*S) -> O(E+S) fix for Select(). + HashSet readSet = new(readEvents); + HashSet writeSet = new(writeEvents); + HashSet errorSet = new(errorEvents); + updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count; foreach (PollEvent pollEvent in events) @@ -126,15 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor; - if (readEvents.Contains(socket.Socket)) + if (readSet.Contains(socket.Socket)) { pollEvent.Data.OutputEvents |= PollEventTypeMask.Input; } - if (writeEvents.Contains(socket.Socket)) + if (writeSet.Contains(socket.Socket)) { pollEvent.Data.OutputEvents |= PollEventTypeMask.Output; } - if (errorEvents.Contains(socket.Socket)) + if (errorSet.Contains(socket.Socket)) { pollEvent.Data.OutputEvents |= PollEventTypeMask.Error; }