KClientPort.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using Ryujinx.HLE.HOS.Kernel.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Process;
  3. using Ryujinx.Horizon.Common;
  4. using System.Threading;
  5. namespace Ryujinx.HLE.HOS.Kernel.Ipc
  6. {
  7. class KClientPort : KSynchronizationObject
  8. {
  9. private int _sessionsCount;
  10. private readonly int _maxSessions;
  11. private readonly KPort _parent;
  12. public bool IsLight => _parent.IsLight;
  13. public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
  14. {
  15. _maxSessions = maxSessions;
  16. _parent = parent;
  17. }
  18. public Result Connect(out KClientSession clientSession)
  19. {
  20. clientSession = null;
  21. KProcess currentProcess = KernelStatic.GetCurrentProcess();
  22. if (currentProcess.ResourceLimit != null &&
  23. !currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
  24. {
  25. return KernelResult.ResLimitExceeded;
  26. }
  27. if (!IncrementSessionsCount())
  28. {
  29. currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
  30. return KernelResult.SessionCountExceeded;
  31. }
  32. KSession session = new KSession(KernelContext, this);
  33. Result result = _parent.EnqueueIncomingSession(session.ServerSession);
  34. if (result != Result.Success)
  35. {
  36. session.ClientSession.DecrementReferenceCount();
  37. session.ServerSession.DecrementReferenceCount();
  38. return result;
  39. }
  40. clientSession = session.ClientSession;
  41. return result;
  42. }
  43. public Result ConnectLight(out KLightClientSession clientSession)
  44. {
  45. clientSession = null;
  46. KProcess currentProcess = KernelStatic.GetCurrentProcess();
  47. if (currentProcess.ResourceLimit != null &&
  48. !currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
  49. {
  50. return KernelResult.ResLimitExceeded;
  51. }
  52. if (!IncrementSessionsCount())
  53. {
  54. currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
  55. return KernelResult.SessionCountExceeded;
  56. }
  57. KLightSession session = new KLightSession(KernelContext);
  58. Result result = _parent.EnqueueIncomingLightSession(session.ServerSession);
  59. if (result != Result.Success)
  60. {
  61. session.ClientSession.DecrementReferenceCount();
  62. session.ServerSession.DecrementReferenceCount();
  63. return result;
  64. }
  65. clientSession = session.ClientSession;
  66. return result;
  67. }
  68. private bool IncrementSessionsCount()
  69. {
  70. while (true)
  71. {
  72. int currentCount = _sessionsCount;
  73. if (currentCount < _maxSessions)
  74. {
  75. if (Interlocked.CompareExchange(ref _sessionsCount, currentCount + 1, currentCount) == currentCount)
  76. {
  77. return true;
  78. }
  79. }
  80. else
  81. {
  82. return false;
  83. }
  84. }
  85. }
  86. public void Disconnect()
  87. {
  88. KernelContext.CriticalSection.Enter();
  89. SignalIfMaximumReached(Interlocked.Decrement(ref _sessionsCount));
  90. KernelContext.CriticalSection.Leave();
  91. }
  92. private void SignalIfMaximumReached(int value)
  93. {
  94. if (value == _maxSessions)
  95. {
  96. Signal();
  97. }
  98. }
  99. public new static Result RemoveName(KernelContext context, string name)
  100. {
  101. KAutoObject foundObj = FindNamedObject(context, name);
  102. if (!(foundObj is KClientPort))
  103. {
  104. return KernelResult.NotFound;
  105. }
  106. return KAutoObject.RemoveName(context, name);
  107. }
  108. }
  109. }