KClientPort.cs 4.0 KB

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