forked from Mirror/Ryujinx
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:
parent
b2623dc27d
commit
c05c688ee8
1 changed files with 28 additions and 9 deletions
|
@ -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;
|
||||||
|
|
||||||
|
@ -76,8 +78,11 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddPort(int serverPortHandle, Func<IpcService> objectFactory)
|
private void AddPort(int serverPortHandle, Func<IpcService> objectFactory)
|
||||||
|
{
|
||||||
|
lock (_handleLock)
|
||||||
{
|
{
|
||||||
_portHandles.Add(serverPortHandle);
|
_portHandles.Add(serverPortHandle);
|
||||||
|
}
|
||||||
_ports.Add(serverPortHandle, objectFactory);
|
_ports.Add(serverPortHandle, objectFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +96,11 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSessionObj(int serverSessionHandle, IpcService obj)
|
public void AddSessionObj(int serverSessionHandle, IpcService obj)
|
||||||
|
{
|
||||||
|
lock (_handleLock)
|
||||||
{
|
{
|
||||||
_sessionHandles.Add(serverSessionHandle);
|
_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)
|
||||||
|
{
|
||||||
|
portHandleCount = _portHandles.Count;
|
||||||
|
handleCount = portHandleCount + _sessionHandles.Count;
|
||||||
|
|
||||||
|
handles = ArrayPool<int>.Shared.Rent(handleCount);
|
||||||
|
|
||||||
_portHandles.CopyTo(handles, 0);
|
_portHandles.CopyTo(handles, 0);
|
||||||
_sessionHandles.CopyTo(handles, _portHandles.Count);
|
_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);
|
||||||
|
lock (_handleLock)
|
||||||
|
{
|
||||||
_sessionHandles.Remove(serverSessionHandle);
|
_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);
|
||||||
|
|
Reference in a new issue