BsdContext.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Numerics;
  6. using System.Threading;
  7. namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
  8. {
  9. class BsdContext
  10. {
  11. private static readonly ConcurrentDictionary<ulong, BsdContext> _registry = new();
  12. private readonly Lock _lock = new();
  13. private readonly List<IFileDescriptor> _fds;
  14. private BsdContext()
  15. {
  16. _fds = new List<IFileDescriptor>();
  17. }
  18. public ISocket RetrieveSocket(int socketFd)
  19. {
  20. IFileDescriptor file = RetrieveFileDescriptor(socketFd);
  21. if (file is ISocket socket)
  22. {
  23. return socket;
  24. }
  25. return null;
  26. }
  27. public IFileDescriptor RetrieveFileDescriptor(int fd)
  28. {
  29. lock (_lock)
  30. {
  31. if (fd >= 0 && _fds.Count > fd)
  32. {
  33. return _fds[fd];
  34. }
  35. }
  36. return null;
  37. }
  38. public List<IFileDescriptor> RetrieveFileDescriptorsFromMask(ReadOnlySpan<byte> mask)
  39. {
  40. List<IFileDescriptor> fds = new();
  41. for (int i = 0; i < mask.Length; i++)
  42. {
  43. byte current = mask[i];
  44. while (current != 0)
  45. {
  46. int bit = BitOperations.TrailingZeroCount(current);
  47. current &= (byte)~(1 << bit);
  48. int fd = i * 8 + bit;
  49. fds.Add(RetrieveFileDescriptor(fd));
  50. }
  51. }
  52. return fds;
  53. }
  54. public int RegisterFileDescriptor(IFileDescriptor file)
  55. {
  56. lock (_lock)
  57. {
  58. for (int fd = 0; fd < _fds.Count; fd++)
  59. {
  60. if (_fds[fd] == null)
  61. {
  62. _fds[fd] = file;
  63. return fd;
  64. }
  65. }
  66. _fds.Add(file);
  67. return _fds.Count - 1;
  68. }
  69. }
  70. public void BuildMask(List<IFileDescriptor> fds, Span<byte> mask)
  71. {
  72. foreach (IFileDescriptor descriptor in fds)
  73. {
  74. int fd = _fds.IndexOf(descriptor);
  75. mask[fd >> 3] |= (byte)(1 << (fd & 7));
  76. }
  77. }
  78. public int DuplicateFileDescriptor(int fd)
  79. {
  80. IFileDescriptor oldFile = RetrieveFileDescriptor(fd);
  81. if (oldFile != null)
  82. {
  83. lock (_lock)
  84. {
  85. oldFile.Refcount++;
  86. return RegisterFileDescriptor(oldFile);
  87. }
  88. }
  89. return -1;
  90. }
  91. public bool CloseFileDescriptor(int fd)
  92. {
  93. IFileDescriptor file = RetrieveFileDescriptor(fd);
  94. if (file != null)
  95. {
  96. file.Refcount--;
  97. if (file.Refcount <= 0)
  98. {
  99. file.Dispose();
  100. }
  101. lock (_lock)
  102. {
  103. _fds[fd] = null;
  104. }
  105. return true;
  106. }
  107. return false;
  108. }
  109. public LinuxError ShutdownAllSockets(BsdSocketShutdownFlags how)
  110. {
  111. lock (_lock)
  112. {
  113. foreach (IFileDescriptor file in _fds)
  114. {
  115. if (file is ISocket socket)
  116. {
  117. LinuxError errno = socket.Shutdown(how);
  118. if (errno != LinuxError.SUCCESS)
  119. {
  120. return errno;
  121. }
  122. }
  123. }
  124. }
  125. return LinuxError.SUCCESS;
  126. }
  127. public static BsdContext GetOrRegister(ulong processId)
  128. {
  129. BsdContext context = GetContext(processId);
  130. if (context == null)
  131. {
  132. context = new BsdContext();
  133. _registry.TryAdd(processId, context);
  134. }
  135. return context;
  136. }
  137. public static BsdContext GetContext(ulong processId)
  138. {
  139. if (!_registry.TryGetValue(processId, out BsdContext processContext))
  140. {
  141. return null;
  142. }
  143. return processContext;
  144. }
  145. }
  146. }