Avoid copying more handles than we have space for (#4564)

* Avoid copying more handles than we have space for

* Use locks instead

* Reduce nesting by combining the lock statements

* Add locks for other uses of _sessionHandles and _portHandles

* Use one object to lock instead of locking twice

* Release the lock as soon as possible
This commit is contained in:
TSRBerry 2023-03-19 11:30:04 +01:00 committed by GitHub
parent b2623dc27d
commit c05c688ee8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -32,6 +32,8 @@ namespace Ryujinx.HLE.HOS.Services
0x01007FFF 0x01007FFF
}; };
private readonly object _handleLock = new();
private readonly KernelContext _context; private readonly KernelContext _context;
private KProcess _selfProcess; private KProcess _selfProcess;
@ -77,7 +79,10 @@ namespace Ryujinx.HLE.HOS.Services
private void AddPort(int serverPortHandle, Func<IpcService> objectFactory) private void AddPort(int serverPortHandle, Func<IpcService> objectFactory)
{ {
_portHandles.Add(serverPortHandle); lock (_handleLock)
{
_portHandles.Add(serverPortHandle);
}
_ports.Add(serverPortHandle, objectFactory); _ports.Add(serverPortHandle, objectFactory);
} }
@ -92,7 +97,10 @@ namespace Ryujinx.HLE.HOS.Services
public void AddSessionObj(int serverSessionHandle, IpcService obj) public void AddSessionObj(int serverSessionHandle, IpcService obj)
{ {
_sessionHandles.Add(serverSessionHandle); lock (_handleLock)
{
_sessionHandles.Add(serverSessionHandle);
}
_sessions.Add(serverSessionHandle, obj); _sessions.Add(serverSessionHandle, obj);
} }
@ -126,12 +134,20 @@ namespace Ryujinx.HLE.HOS.Services
while (true) while (true)
{ {
int handleCount = _portHandles.Count + _sessionHandles.Count; int handleCount;
int portHandleCount;
int[] handles;
int[] handles = ArrayPool<int>.Shared.Rent(handleCount); lock (_handleLock)
{
_portHandles.CopyTo(handles, 0); portHandleCount = _portHandles.Count;
_sessionHandles.CopyTo(handles, _portHandles.Count); handleCount = portHandleCount + _sessionHandles.Count;
handles = ArrayPool<int>.Shared.Rent(handleCount);
_portHandles.CopyTo(handles, 0);
_sessionHandles.CopyTo(handles, portHandleCount);
}
// We still need a timeout here to allow the service to pick up and listen new sessions... // We still need a timeout here to allow the service to pick up and listen new sessions...
var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L); var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L);
@ -145,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Services
replyTargetHandle = 0; replyTargetHandle = 0;
if (rc == Result.Success && signaledIndex >= _portHandles.Count) if (rc == Result.Success && signaledIndex >= portHandleCount)
{ {
// We got a IPC request, process it, pass to the appropriate service if needed. // We got a IPC request, process it, pass to the appropriate service if needed.
int signaledHandle = handles[signaledIndex]; int signaledHandle = handles[signaledIndex];
@ -278,7 +294,10 @@ namespace Ryujinx.HLE.HOS.Services
else if (request.Type == IpcMessageType.HipcCloseSession || request.Type == IpcMessageType.TipcCloseSession) else if (request.Type == IpcMessageType.HipcCloseSession || request.Type == IpcMessageType.TipcCloseSession)
{ {
_context.Syscall.CloseHandle(serverSessionHandle); _context.Syscall.CloseHandle(serverSessionHandle);
_sessionHandles.Remove(serverSessionHandle); lock (_handleLock)
{
_sessionHandles.Remove(serverSessionHandle);
}
IpcService service = _sessions[serverSessionHandle]; IpcService service = _sessions[serverSessionHandle];
(service as IDisposable)?.Dispose(); (service as IDisposable)?.Dispose();
_sessions.Remove(serverSessionHandle); _sessions.Remove(serverSessionHandle);