Improve kernel IPC implementation (#550)
* Implement some IPC related kernel SVCs properly * Fix BLZ decompression when the segment also has a uncompressed chunck * Set default cpu core on process start from ProgramLoader, remove debug message * Load process capabilities properly on KIPs * Fix a copy/paste error in UnmapPhysicalMemory64 * Implement smarter switching between old and new IPC system to support the old HLE services implementation without the manual switch * Implement RegisterService on sm and AcceptSession (partial) * Misc fixes and improvements on new IPC methods * Move IPC related SVCs into a separate file, and logging on RegisterService (sm) * Some small fixes related to receive list buffers and error cases * Load NSOs using the correct pool partition * Fix corner case on GetMaskFromMinMax where range is 64, doesn't happen in pratice however * Fix send static buffer copy * Session release, implement closing requests on client disconnect * Implement ConnectToPort SVC * KLightSession init
This commit is contained in:
parent
3731d0ce84
commit
22bacc6188
51 changed files with 4310 additions and 840 deletions
10
Ryujinx.HLE/HOS/Kernel/Ipc/ChannelState.cs
Normal file
10
Ryujinx.HLE/HOS/Kernel/Ipc/ChannelState.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
enum ChannelState
|
||||
{
|
||||
NotInitialized,
|
||||
Open,
|
||||
ClientDisconnected,
|
||||
ServerDisconnected
|
||||
}
|
||||
}
|
20
Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptor.cs
Normal file
20
Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptor.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KBufferDescriptor
|
||||
{
|
||||
public ulong ClientAddress { get; }
|
||||
public ulong ServerAddress { get; }
|
||||
public ulong Size { get; }
|
||||
public MemoryState State { get; }
|
||||
|
||||
public KBufferDescriptor(ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
ClientAddress = src;
|
||||
ServerAddress = dst;
|
||||
Size = size;
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
}
|
216
Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
Normal file
216
Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
Normal file
|
@ -0,0 +1,216 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KBufferDescriptorTable
|
||||
{
|
||||
private const int MaxInternalBuffersCount = 8;
|
||||
|
||||
private List<KBufferDescriptor> _sendBufferDescriptors;
|
||||
private List<KBufferDescriptor> _receiveBufferDescriptors;
|
||||
private List<KBufferDescriptor> _exchangeBufferDescriptors;
|
||||
|
||||
public KBufferDescriptorTable()
|
||||
{
|
||||
_sendBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
|
||||
_receiveBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
|
||||
_exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
|
||||
}
|
||||
|
||||
public KernelResult AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
return Add(_sendBufferDescriptors, src, dst, size, state);
|
||||
}
|
||||
|
||||
public KernelResult AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
return Add(_receiveBufferDescriptors, src, dst, size, state);
|
||||
}
|
||||
|
||||
public KernelResult AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
return Add(_exchangeBufferDescriptors, src, dst, size, state);
|
||||
}
|
||||
|
||||
private KernelResult Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
if (list.Count < MaxInternalBuffersCount)
|
||||
{
|
||||
list.Add(new KBufferDescriptor(src, dst, size, state));
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
public KernelResult CopyBuffersToClient(KMemoryManager memoryManager)
|
||||
{
|
||||
KernelResult result = CopyToClient(memoryManager, _receiveBufferDescriptors);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return CopyToClient(memoryManager, _exchangeBufferDescriptors);
|
||||
}
|
||||
|
||||
private KernelResult CopyToClient(KMemoryManager memoryManager, List<KBufferDescriptor> list)
|
||||
{
|
||||
foreach (KBufferDescriptor desc in list)
|
||||
{
|
||||
MemoryState stateMask;
|
||||
|
||||
switch (desc.State)
|
||||
{
|
||||
case MemoryState.IpcBuffer0: stateMask = MemoryState.IpcSendAllowedType0; break;
|
||||
case MemoryState.IpcBuffer1: stateMask = MemoryState.IpcSendAllowedType1; break;
|
||||
case MemoryState.IpcBuffer3: stateMask = MemoryState.IpcSendAllowedType3; break;
|
||||
|
||||
default: return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
|
||||
|
||||
if (desc.State == MemoryState.IpcBuffer0)
|
||||
{
|
||||
attributeMask |= MemoryAttribute.DeviceMapped;
|
||||
}
|
||||
|
||||
ulong clientAddrTruncated = BitUtils.AlignDown(desc.ClientAddress, KMemoryManager.PageSize);
|
||||
ulong clientAddrRounded = BitUtils.AlignUp (desc.ClientAddress, KMemoryManager.PageSize);
|
||||
|
||||
//Check if address is not aligned, in this case we need to perform 2 copies.
|
||||
if (clientAddrTruncated != clientAddrRounded)
|
||||
{
|
||||
ulong copySize = clientAddrRounded - desc.ClientAddress;
|
||||
|
||||
if (copySize > desc.Size)
|
||||
{
|
||||
copySize = desc.Size;
|
||||
}
|
||||
|
||||
KernelResult result = memoryManager.CopyDataFromCurrentProcess(
|
||||
desc.ClientAddress,
|
||||
copySize,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None,
|
||||
desc.ServerAddress);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
ulong clientEndAddr = desc.ClientAddress + desc.Size;
|
||||
ulong serverEndAddr = desc.ServerAddress + desc.Size;
|
||||
|
||||
ulong clientEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KMemoryManager.PageSize);
|
||||
ulong clientEndAddrRounded = BitUtils.AlignUp (clientEndAddr, KMemoryManager.PageSize);
|
||||
ulong serverEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KMemoryManager.PageSize);
|
||||
|
||||
if (clientEndAddrTruncated < clientAddrRounded)
|
||||
{
|
||||
KernelResult result = memoryManager.CopyDataToCurrentProcess(
|
||||
clientEndAddrTruncated,
|
||||
clientEndAddr - clientEndAddrTruncated,
|
||||
serverEndAddrTruncated,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult UnmapServerBuffers(KMemoryManager memoryManager)
|
||||
{
|
||||
KernelResult result = UnmapServer(memoryManager, _sendBufferDescriptors);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = UnmapServer(memoryManager, _receiveBufferDescriptors);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return UnmapServer(memoryManager, _exchangeBufferDescriptors);
|
||||
}
|
||||
|
||||
private KernelResult UnmapServer(KMemoryManager memoryManager, List<KBufferDescriptor> list)
|
||||
{
|
||||
foreach (KBufferDescriptor descriptor in list)
|
||||
{
|
||||
KernelResult result = memoryManager.UnmapNoAttributeIfStateEquals(
|
||||
descriptor.ServerAddress,
|
||||
descriptor.Size,
|
||||
descriptor.State);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult RestoreClientBuffers(KMemoryManager memoryManager)
|
||||
{
|
||||
KernelResult result = RestoreClient(memoryManager, _sendBufferDescriptors);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = RestoreClient(memoryManager, _receiveBufferDescriptors);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return RestoreClient(memoryManager, _exchangeBufferDescriptors);
|
||||
}
|
||||
|
||||
private KernelResult RestoreClient(KMemoryManager memoryManager, List<KBufferDescriptor> list)
|
||||
{
|
||||
foreach (KBufferDescriptor descriptor in list)
|
||||
{
|
||||
KernelResult result = memoryManager.UnmapIpcRestorePermission(
|
||||
descriptor.ClientAddress,
|
||||
descriptor.Size,
|
||||
descriptor.State);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
|
@ -10,12 +12,116 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
private KPort _parent;
|
||||
|
||||
public KClientPort(Horizon system) : base(system) { }
|
||||
public bool IsLight => _parent.IsLight;
|
||||
|
||||
public void Initialize(KPort parent, int maxSessions)
|
||||
private object _countIncLock;
|
||||
|
||||
//TODO: Remove that, we need it for now to allow HLE
|
||||
//SM implementation to work with the new IPC system.
|
||||
public IpcService Service { get; set; }
|
||||
|
||||
public KClientPort(Horizon system, KPort parent, int maxSessions) : base(system)
|
||||
{
|
||||
_maxSessions = maxSessions;
|
||||
_parent = parent;
|
||||
|
||||
_countIncLock = new object();
|
||||
}
|
||||
|
||||
public KernelResult Connect(out KClientSession clientSession)
|
||||
{
|
||||
clientSession = null;
|
||||
|
||||
KProcess currentProcess = System.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (currentProcess.ResourceLimit != null &&
|
||||
!currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
lock (_countIncLock)
|
||||
{
|
||||
if (_sessionsCount < _maxSessions)
|
||||
{
|
||||
_sessionsCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
|
||||
|
||||
return KernelResult.SessionCountExceeded;
|
||||
}
|
||||
|
||||
if (_currentCapacity < _sessionsCount)
|
||||
{
|
||||
_currentCapacity = _sessionsCount;
|
||||
}
|
||||
}
|
||||
|
||||
KSession session = new KSession(System);
|
||||
|
||||
if (Service != null)
|
||||
{
|
||||
session.ClientSession.Service = Service;
|
||||
}
|
||||
|
||||
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
session.ClientSession.DecrementReferenceCount();
|
||||
session.ServerSession.DecrementReferenceCount();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
clientSession = session.ClientSession;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ConnectLight(out KLightClientSession clientSession)
|
||||
{
|
||||
clientSession = null;
|
||||
|
||||
KProcess currentProcess = System.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (currentProcess.ResourceLimit != null &&
|
||||
!currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
lock (_countIncLock)
|
||||
{
|
||||
if (_sessionsCount < _maxSessions)
|
||||
{
|
||||
_sessionsCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
|
||||
|
||||
return KernelResult.SessionCountExceeded;
|
||||
}
|
||||
}
|
||||
|
||||
KLightSession session = new KLightSession(System);
|
||||
|
||||
KernelResult result = _parent.EnqueueIncomingLightSession(session.ServerSession);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
session.ClientSession.DecrementReferenceCount();
|
||||
session.ServerSession.DecrementReferenceCount();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
clientSession = session.ClientSession;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public new static KernelResult RemoveName(Horizon system, string name)
|
||||
|
|
60
Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
Normal file
60
Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KClientSession : KSynchronizationObject
|
||||
{
|
||||
public KProcess CreatorProcess { get; }
|
||||
|
||||
private KSession _parent;
|
||||
|
||||
public ChannelState State { get; set; }
|
||||
|
||||
//TODO: Remove that, we need it for now to allow HLE
|
||||
//services implementation to work with the new IPC system.
|
||||
public IpcService Service { get; set; }
|
||||
|
||||
public KClientSession(Horizon system, KSession parent) : base(system)
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
State = ChannelState.Open;
|
||||
|
||||
CreatorProcess = system.Scheduler.GetCurrentProcess();
|
||||
|
||||
CreatorProcess.IncrementReferenceCount();
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
|
||||
{
|
||||
KThread currentThread = System.Scheduler.GetCurrentThread();
|
||||
|
||||
KSessionRequest request = new KSessionRequest(currentThread, customCmdBuffAddr, customCmdBuffSize);
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = KernelResult.Success;
|
||||
|
||||
KernelResult result = _parent.ServerSession.EnqueueRequest(request);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
result = currentThread.ObjSyncResult;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
_parent.DisconnectClient();
|
||||
_parent.DecrementReferenceCount();
|
||||
}
|
||||
}
|
||||
}
|
14
Ryujinx.HLE/HOS/Kernel/Ipc/KLightClientSession.cs
Normal file
14
Ryujinx.HLE/HOS/Kernel/Ipc/KLightClientSession.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KLightClientSession : KAutoObject
|
||||
{
|
||||
private KLightSession _parent;
|
||||
|
||||
public KLightClientSession(Horizon system, KLightSession parent) : base(system)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
14
Ryujinx.HLE/HOS/Kernel/Ipc/KLightServerSession.cs
Normal file
14
Ryujinx.HLE/HOS/Kernel/Ipc/KLightServerSession.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KLightServerSession : KAutoObject
|
||||
{
|
||||
private KLightSession _parent;
|
||||
|
||||
public KLightServerSession(Horizon system, KLightSession parent) : base(system)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
20
Ryujinx.HLE/HOS/Kernel/Ipc/KLightSession.cs
Normal file
20
Ryujinx.HLE/HOS/Kernel/Ipc/KLightSession.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KLightSession : KAutoObject
|
||||
{
|
||||
public KLightServerSession ServerSession { get; }
|
||||
public KLightClientSession ClientSession { get; }
|
||||
|
||||
private bool _hasBeenInitialized;
|
||||
|
||||
public KLightSession(Horizon system) : base(system)
|
||||
{
|
||||
ServerSession = new KLightServerSession(system, this);
|
||||
ClientSession = new KLightClientSession(system, this);
|
||||
|
||||
_hasBeenInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,25 +4,68 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
{
|
||||
class KPort : KAutoObject
|
||||
{
|
||||
public KServerPort ServerPort { get; private set; }
|
||||
public KClientPort ClientPort { get; private set; }
|
||||
public KServerPort ServerPort { get; }
|
||||
public KClientPort ClientPort { get; }
|
||||
|
||||
private long _nameAddress;
|
||||
private bool _isLight;
|
||||
|
||||
public KPort(Horizon system) : base(system)
|
||||
private ChannelState _state;
|
||||
|
||||
public bool IsLight { get; private set; }
|
||||
|
||||
public KPort(Horizon system, int maxSessions, bool isLight, long nameAddress) : base(system)
|
||||
{
|
||||
ServerPort = new KServerPort(system);
|
||||
ClientPort = new KClientPort(system);
|
||||
ServerPort = new KServerPort(system, this);
|
||||
ClientPort = new KClientPort(system, this, maxSessions);
|
||||
|
||||
IsLight = isLight;
|
||||
_nameAddress = nameAddress;
|
||||
|
||||
_state = ChannelState.Open;
|
||||
}
|
||||
|
||||
public void Initialize(int maxSessions, bool isLight, long nameAddress)
|
||||
public KernelResult EnqueueIncomingSession(KServerSession session)
|
||||
{
|
||||
ServerPort.Initialize(this);
|
||||
ClientPort.Initialize(this, maxSessions);
|
||||
KernelResult result;
|
||||
|
||||
_isLight = isLight;
|
||||
_nameAddress = nameAddress;
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
if (_state == ChannelState.Open)
|
||||
{
|
||||
ServerPort.EnqueueIncomingSession(session);
|
||||
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = KernelResult.PortClosed;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult EnqueueIncomingLightSession(KLightServerSession session)
|
||||
{
|
||||
KernelResult result;
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
if (_state == ChannelState.Open)
|
||||
{
|
||||
ServerPort.EnqueueIncomingLightSession(session);
|
||||
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = KernelResult.PortClosed;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,87 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KServerPort : KSynchronizationObject
|
||||
{
|
||||
private LinkedList<KServerSession> _incomingConnections;
|
||||
private LinkedList<KLightServerSession> _lightIncomingConnections;
|
||||
|
||||
private KPort _parent;
|
||||
|
||||
public KServerPort(Horizon system) : base(system) { }
|
||||
public bool IsLight => _parent.IsLight;
|
||||
|
||||
public void Initialize(KPort parent)
|
||||
public KServerPort(Horizon system, KPort parent) : base(system)
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
_incomingConnections = new LinkedList<KServerSession>();
|
||||
_lightIncomingConnections = new LinkedList<KLightServerSession>();
|
||||
}
|
||||
|
||||
public void EnqueueIncomingSession(KServerSession session)
|
||||
{
|
||||
AcceptIncomingConnection(_incomingConnections, session);
|
||||
}
|
||||
|
||||
public void EnqueueIncomingLightSession(KLightServerSession session)
|
||||
{
|
||||
AcceptIncomingConnection(_lightIncomingConnections, session);
|
||||
}
|
||||
|
||||
private void AcceptIncomingConnection<T>(LinkedList<T> list, T session)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
list.AddLast(session);
|
||||
|
||||
if (list.Count == 1)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
public KServerSession AcceptIncomingConnection()
|
||||
{
|
||||
return AcceptIncomingConnection(_incomingConnections);
|
||||
}
|
||||
|
||||
public KLightServerSession AcceptIncomingLightConnection()
|
||||
{
|
||||
return AcceptIncomingConnection(_lightIncomingConnections);
|
||||
}
|
||||
|
||||
private T AcceptIncomingConnection<T>(LinkedList<T> list)
|
||||
{
|
||||
T session = default(T);
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
if (list.Count != 0)
|
||||
{
|
||||
session = list.First.Value;
|
||||
|
||||
list.RemoveFirst();
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public override bool IsSignaled()
|
||||
{
|
||||
if (_parent.IsLight)
|
||||
{
|
||||
return _lightIncomingConnections.Count != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _incomingConnections.Count != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1262
Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
Normal file
1262
Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,40 @@
|
|||
using Ryujinx.HLE.HOS.Services;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KSession : IDisposable
|
||||
class KSession : KAutoObject, IDisposable
|
||||
{
|
||||
public IpcService Service { get; private set; }
|
||||
public KServerSession ServerSession { get; }
|
||||
public KClientSession ClientSession { get; }
|
||||
|
||||
public string ServiceName { get; private set; }
|
||||
private bool _hasBeenInitialized;
|
||||
|
||||
public KSession(IpcService service, string serviceName)
|
||||
public KSession(Horizon system) : base(system)
|
||||
{
|
||||
Service = service;
|
||||
ServiceName = serviceName;
|
||||
ServerSession = new KServerSession(system, this);
|
||||
ClientSession = new KClientSession(system, this);
|
||||
|
||||
_hasBeenInitialized = true;
|
||||
}
|
||||
|
||||
public void DisconnectClient()
|
||||
{
|
||||
if (ClientSession.State == ChannelState.Open)
|
||||
{
|
||||
ClientSession.State = ChannelState.ClientDisconnected;
|
||||
|
||||
ServerSession.CancelAllRequestsClientDisconnected();
|
||||
}
|
||||
}
|
||||
|
||||
public void DisconnectServer()
|
||||
{
|
||||
if (ClientSession.State == ChannelState.Open)
|
||||
{
|
||||
ClientSession.State = ChannelState.ServerDisconnected;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -22,10 +44,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && Service is IDisposable disposableService)
|
||||
if (disposing && ClientSession.Service is IDisposable disposableService)
|
||||
{
|
||||
disposableService.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
if (_hasBeenInitialized)
|
||||
{
|
||||
KProcess creatorProcess = ClientSession.CreatorProcess;
|
||||
|
||||
creatorProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
|
||||
|
||||
creatorProcess.DecrementReferenceCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
Ryujinx.HLE/HOS/Kernel/Ipc/KSessionRequest.cs
Normal file
31
Ryujinx.HLE/HOS/Kernel/Ipc/KSessionRequest.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KSessionRequest
|
||||
{
|
||||
public KBufferDescriptorTable BufferDescriptorTable { get; }
|
||||
|
||||
public KThread ClientThread { get; }
|
||||
|
||||
public KProcess ServerProcess { get; set; }
|
||||
|
||||
public KWritableEvent AsyncEvent { get; }
|
||||
|
||||
public ulong CustomCmdBuffAddr { get; }
|
||||
public ulong CustomCmdBuffSize { get; }
|
||||
|
||||
public KSessionRequest(
|
||||
KThread clientThread,
|
||||
ulong customCmdBuffAddr,
|
||||
ulong customCmdBuffSize)
|
||||
{
|
||||
ClientThread = clientThread;
|
||||
CustomCmdBuffAddr = customCmdBuffAddr;
|
||||
CustomCmdBuffSize = customCmdBuffSize;
|
||||
|
||||
BufferDescriptorTable = new KBufferDescriptorTable();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue