IPC refactor part 3+4: New server HIPC message processor (#4188)
* IPC refactor part 3 + 4: New server HIPC message processor with source generator based serialization * Make types match on calls to AlignUp/AlignDown * Formatting * Address some PR feedback * Move BitfieldExtensions to Ryujinx.Common.Utilities and consolidate implementations * Rename Reader/Writer to SpanReader/SpanWriter and move to Ryujinx.Common.Memory * Implement EventType * Address more PR feedback * Log request processing errors since they are not normal * Rename waitable to multiwait and add missing lock * PR feedback * Ac_K PR feedback
This commit is contained in:
parent
c6a139a6e7
commit
08831eecf7
213 changed files with 9762 additions and 1010 deletions
198
Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
Normal file
198
Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
Normal file
|
@ -0,0 +1,198 @@
|
|||
using Ryujinx.Horizon.Sdk.OsTypes;
|
||||
using Ryujinx.Horizon.Sdk.Sf.Cmif;
|
||||
using Ryujinx.Horizon.Sdk.Sm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||
{
|
||||
class ServerManager : ServerManagerBase, IDisposable
|
||||
{
|
||||
private readonly SmApi _sm;
|
||||
private readonly int _pointerBufferSize;
|
||||
private readonly bool _canDeferInvokeRequest;
|
||||
private readonly int _maxSessions;
|
||||
|
||||
private ulong _pointerBuffersBaseAddress;
|
||||
private ulong _savedMessagesBaseAddress;
|
||||
|
||||
private readonly object _resourceLock;
|
||||
private readonly ulong[] _sessionAllocationBitmap;
|
||||
private readonly HashSet<ServerSession> _sessions;
|
||||
private readonly HashSet<Server> _servers;
|
||||
|
||||
public ServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(sm, options)
|
||||
{
|
||||
_sm = sm;
|
||||
_pointerBufferSize = options.PointerBufferSize;
|
||||
_canDeferInvokeRequest = options.CanDeferInvokeRequest;
|
||||
_maxSessions = maxSessions;
|
||||
|
||||
if (allocator != null)
|
||||
{
|
||||
_pointerBuffersBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)options.PointerBufferSize);
|
||||
|
||||
if (options.CanDeferInvokeRequest)
|
||||
{
|
||||
_savedMessagesBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)Api.TlsMessageBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
_resourceLock = new object();
|
||||
_sessionAllocationBitmap = new ulong[(maxSessions + 63) / 64];
|
||||
_sessions = new HashSet<ServerSession>();
|
||||
_servers = new HashSet<Server>();
|
||||
}
|
||||
|
||||
private PointerAndSize GetObjectBySessionIndex(ServerSession session, ulong baseAddress, ulong size)
|
||||
{
|
||||
return new PointerAndSize(baseAddress + (ulong)session.SessionIndex * size, size);
|
||||
}
|
||||
|
||||
protected override ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
|
||||
{
|
||||
int sessionIndex = -1;
|
||||
|
||||
lock (_resourceLock)
|
||||
{
|
||||
if (_sessions.Count >= _maxSessions)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i <_sessionAllocationBitmap.Length; i++)
|
||||
{
|
||||
ref ulong mask = ref _sessionAllocationBitmap[i];
|
||||
|
||||
if (mask != ulong.MaxValue)
|
||||
{
|
||||
int bit = BitOperations.TrailingZeroCount(~mask);
|
||||
sessionIndex = i * 64 + bit;
|
||||
mask |= 1UL << bit;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionIndex == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ServerSession session = new ServerSession(sessionIndex, sessionHandle, obj);
|
||||
|
||||
_sessions.Add(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void FreeSession(ServerSession session)
|
||||
{
|
||||
if (session.ServiceObjectHolder.ServiceObject is IDisposable disposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
|
||||
lock (_resourceLock)
|
||||
{
|
||||
_sessionAllocationBitmap[session.SessionIndex / 64] &= ~(1UL << (session.SessionIndex & 63));
|
||||
_sessions.Remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Server AllocateServer(
|
||||
int portIndex,
|
||||
int portHandle,
|
||||
ServiceName name,
|
||||
bool managed,
|
||||
ServiceObjectHolder staticHoder)
|
||||
{
|
||||
lock (_resourceLock)
|
||||
{
|
||||
Server server = new Server(portIndex, portHandle, name, managed, staticHoder);
|
||||
|
||||
_servers.Add(server);
|
||||
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DestroyServer(Server server)
|
||||
{
|
||||
lock (_resourceLock)
|
||||
{
|
||||
server.UnlinkFromMultiWaitHolder();
|
||||
Os.FinalizeMultiWaitHolder(server);
|
||||
|
||||
if (server.Managed)
|
||||
{
|
||||
// We should AbortOnFailure, but sometimes SM is already gone when this is called,
|
||||
// so let's just ignore potential errors.
|
||||
_sm.UnregisterService(server.Name);
|
||||
|
||||
HorizonStatic.Syscall.CloseHandle(server.PortHandle);
|
||||
}
|
||||
|
||||
_servers.Remove(server);
|
||||
}
|
||||
}
|
||||
|
||||
protected override PointerAndSize GetSessionPointerBuffer(ServerSession session)
|
||||
{
|
||||
if (_pointerBufferSize > 0)
|
||||
{
|
||||
return GetObjectBySessionIndex(session, _pointerBuffersBaseAddress, (ulong)_pointerBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return PointerAndSize.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
|
||||
{
|
||||
if (_canDeferInvokeRequest)
|
||||
{
|
||||
return GetObjectBySessionIndex(session, _savedMessagesBaseAddress, Api.TlsMessageBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return PointerAndSize.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (_resourceLock)
|
||||
{
|
||||
ServerSession[] sessionsToClose = new ServerSession[_sessions.Count];
|
||||
|
||||
_sessions.CopyTo(sessionsToClose);
|
||||
|
||||
foreach (ServerSession session in sessionsToClose)
|
||||
{
|
||||
CloseSessionImpl(session);
|
||||
}
|
||||
|
||||
Server[] serversToClose = new Server[_servers.Count];
|
||||
|
||||
_servers.CopyTo(serversToClose);
|
||||
|
||||
foreach (Server server in serversToClose)
|
||||
{
|
||||
DestroyServer(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue