forked from Mirror/Ryujinx
ba5c0cf5d8
* bsd: Add gdkchan's Select implementation Co-authored-by: TSRBerry <20988865+tsrberry@users.noreply.github.com> * bsd: Fix Select() causing a crash with an ArgumentException .NET Sockets have to be used for the Select() call * bsd: Make Select more generic * bsd: Adjust namespaces and remove unused imports * bsd: Fix NullReferenceException in Select Co-authored-by: gdkchan <gab.dark.100@gmail.com>
184 lines
No EOL
4.4 KiB
C#
184 lines
No EOL
4.4 KiB
C#
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
|
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|
{
|
|
class BsdContext
|
|
{
|
|
private static ConcurrentDictionary<ulong, BsdContext> _registry = new ConcurrentDictionary<ulong, BsdContext>();
|
|
|
|
private readonly object _lock = new object();
|
|
|
|
private List<IFileDescriptor> _fds;
|
|
|
|
private BsdContext()
|
|
{
|
|
_fds = new List<IFileDescriptor>();
|
|
}
|
|
|
|
public ISocket RetrieveSocket(int socketFd)
|
|
{
|
|
IFileDescriptor file = RetrieveFileDescriptor(socketFd);
|
|
|
|
if (file is ISocket socket)
|
|
{
|
|
return socket;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public IFileDescriptor RetrieveFileDescriptor(int fd)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (fd >= 0 && _fds.Count > fd)
|
|
{
|
|
return _fds[fd];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public List<IFileDescriptor> RetrieveFileDescriptorsFromMask(ReadOnlySpan<byte> mask)
|
|
{
|
|
List<IFileDescriptor> fds = new();
|
|
|
|
for (int i = 0; i < mask.Length; i++)
|
|
{
|
|
byte current = mask[i];
|
|
|
|
while (current != 0)
|
|
{
|
|
int bit = BitOperations.TrailingZeroCount(current);
|
|
current &= (byte)~(1 << bit);
|
|
int fd = i * 8 + bit;
|
|
|
|
fds.Add(RetrieveFileDescriptor(fd));
|
|
}
|
|
}
|
|
|
|
return fds;
|
|
}
|
|
|
|
public int RegisterFileDescriptor(IFileDescriptor file)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
for (int fd = 0; fd < _fds.Count; fd++)
|
|
{
|
|
if (_fds[fd] == null)
|
|
{
|
|
_fds[fd] = file;
|
|
|
|
return fd;
|
|
}
|
|
}
|
|
|
|
_fds.Add(file);
|
|
|
|
return _fds.Count - 1;
|
|
}
|
|
}
|
|
|
|
public void BuildMask(List<IFileDescriptor> fds, Span<byte> mask)
|
|
{
|
|
foreach (IFileDescriptor descriptor in fds)
|
|
{
|
|
int fd = _fds.IndexOf(descriptor);
|
|
|
|
mask[fd >> 3] |= (byte)(1 << (fd & 7));
|
|
}
|
|
}
|
|
|
|
public int DuplicateFileDescriptor(int fd)
|
|
{
|
|
IFileDescriptor oldFile = RetrieveFileDescriptor(fd);
|
|
|
|
if (oldFile != null)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
oldFile.Refcount++;
|
|
|
|
return RegisterFileDescriptor(oldFile);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public bool CloseFileDescriptor(int fd)
|
|
{
|
|
IFileDescriptor file = RetrieveFileDescriptor(fd);
|
|
|
|
if (file != null)
|
|
{
|
|
file.Refcount--;
|
|
|
|
if (file.Refcount <= 0)
|
|
{
|
|
file.Dispose();
|
|
}
|
|
|
|
lock (_lock)
|
|
{
|
|
_fds[fd] = null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public LinuxError ShutdownAllSockets(BsdSocketShutdownFlags how)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
foreach (IFileDescriptor file in _fds)
|
|
{
|
|
if (file is ISocket socket)
|
|
{
|
|
LinuxError errno = socket.Shutdown(how);
|
|
|
|
if (errno != LinuxError.SUCCESS)
|
|
{
|
|
return errno;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return LinuxError.SUCCESS;
|
|
}
|
|
|
|
public static BsdContext GetOrRegister(ulong processId)
|
|
{
|
|
BsdContext context = GetContext(processId);
|
|
|
|
if (context == null)
|
|
{
|
|
context = new BsdContext();
|
|
|
|
_registry.TryAdd(processId, context);
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
public static BsdContext GetContext(ulong processId)
|
|
{
|
|
if (!_registry.TryGetValue(processId, out BsdContext processContext))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return processContext;
|
|
}
|
|
}
|
|
} |