Compare commits

...

3 Commits

Author SHA1 Message Date
&Olga
475fa4d390 Fix "UI" abbreviation being miscapitalized (#4093) 2022-12-12 15:11:55 +01:00
Andrey Sukharev
edf7e628ca Use method overloads that support trimming. Mark some types to be trimming friendly (#4083)
* Use method overloads that support trimming. Mark some types to be trimming friendly

* Use generic version of marshalling method
2022-12-12 15:10:05 +01:00
TSRBerry
ba5c0cf5d8 Bsd: Implement Select (#4017)
* 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>
2022-12-12 14:59:31 +01:00
39 changed files with 290 additions and 66 deletions

View File

@@ -280,7 +280,7 @@
"ControllerSettingsRemoveProfileToolTip": "Remove Profile", "ControllerSettingsRemoveProfileToolTip": "Remove Profile",
"ControllerSettingsSaveProfileToolTip": "Save Profile", "ControllerSettingsSaveProfileToolTip": "Save Profile",
"MenuBarFileToolsTakeScreenshot": "Take Screenshot", "MenuBarFileToolsTakeScreenshot": "Take Screenshot",
"MenuBarFileToolsHideUi": "Hide Ui", "MenuBarFileToolsHideUi": "Hide UI",
"GameListContextMenuToggleFavorite": "Toggle Favorite", "GameListContextMenuToggleFavorite": "Toggle Favorite",
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game", "GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
"SettingsTabGeneralTheme": "Theme", "SettingsTabGeneralTheme": "Theme",

View File

@@ -7,8 +7,7 @@ namespace Ryujinx.Ava.Input
{ {
internal static class AvaloniaKeyboardMappingHelper internal static class AvaloniaKeyboardMappingHelper
{ {
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count] private static readonly AvaKey[] _keyMapping = {
{
// NOTE: Invalid // NOTE: Invalid
AvaKey.None, AvaKey.None,
@@ -151,16 +150,16 @@ namespace Ryujinx.Ava.Input
static AvaloniaKeyboardMappingHelper() static AvaloniaKeyboardMappingHelper()
{ {
var inputKeys = Enum.GetValues(typeof(Key)); var inputKeys = Enum.GetValues<Key>();
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array. // NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
_avaKeyMapping = new Dictionary<AvaKey, Key>(); _avaKeyMapping = new Dictionary<AvaKey, Key>();
foreach (var key in inputKeys) foreach (var key in inputKeys)
{ {
if (TryGetAvaKey((Key)key, out var index)) if (TryGetAvaKey(key, out var index))
{ {
_avaKeyMapping[index] = (Key)key; _avaKeyMapping[index] = key;
} }
} }
} }

View File

@@ -152,7 +152,7 @@ namespace Ryujinx.Common.GraphicsDriver
if (ptr != IntPtr.Zero) if (ptr != IntPtr.Zero)
{ {
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; return Marshal.GetDelegateForFunctionPointer<T>(ptr);
} }
else else
{ {

View File

@@ -60,7 +60,7 @@ namespace Ryujinx.Common.SystemInfo
public MemoryStatusEx() public MemoryStatusEx()
{ {
Length = (uint)Marshal.SizeOf(typeof(MemoryStatusEx)); Length = (uint)Marshal.SizeOf<MemoryStatusEx>();
} }
} }

View File

@@ -1,12 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Device namespace Ryujinx.Graphics.Device
{ {
public class DeviceState<TState> : IDeviceState where TState : unmanaged public class DeviceState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged
{ {
private const int RegisterSize = sizeof(int); private const int RegisterSize = sizeof(int);

View File

@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Device;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Engine namespace Ryujinx.Graphics.Gpu.Engine
@@ -21,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// Represents a device's state, with a additional shadow state. /// Represents a device's state, with a additional shadow state.
/// </summary> /// </summary>
/// <typeparam name="TState">Type of the state</typeparam> /// <typeparam name="TState">Type of the state</typeparam>
class DeviceStateWithShadow<TState> : IDeviceState where TState : unmanaged, IShadowState class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState
{ {
private readonly DeviceState<TState> _state; private readonly DeviceState<TState> _state;
private readonly DeviceState<TState> _shadowState; private readonly DeviceState<TState> _shadowState;

View File

@@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -39,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// GPU state update tracker. /// GPU state update tracker.
/// </summary> /// </summary>
/// <typeparam name="TState">State type</typeparam> /// <typeparam name="TState">State type</typeparam>
class StateUpdateTracker<TState> class StateUpdateTracker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState>
{ {
private const int BlockSize = 0xe00; private const int BlockSize = 0xe00;
private const int RegisterSize = sizeof(uint); private const int RegisterSize = sizeof(uint);

View File

@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
_errorStorage = _normalSession.Pop(); _errorStorage = _normalSession.Pop();
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage); _errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
_errorStorage = _errorStorage.Skip(Marshal.SizeOf(typeof(ErrorCommonHeader))).ToArray(); _errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
switch (_errorCommonHeader.Type) switch (_errorCommonHeader.Type)
{ {

View File

@@ -9,6 +9,7 @@ using Ryujinx.HLE.Ui.Input;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -797,7 +798,7 @@ namespace Ryujinx.HLE.HOS.Applets
return sb.ToString(); return sb.ToString();
} }
private static T ReadStruct<T>(byte[] data) private static T ReadStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(byte[] data)
where T : struct where T : struct
{ {
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);

View File

@@ -589,9 +589,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
ulong outputPosition = context.Request.RecvListBuff[0].Position; ulong outputPosition = context.Request.RecvListBuff[0].Position;
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(TagInfo))); context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<TagInfo>());
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(TagInfo))); MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<TagInfo>());
uint deviceHandle = (uint)context.RequestData.ReadUInt64(); uint deviceHandle = (uint)context.RequestData.ReadUInt64();
@@ -665,9 +665,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
ulong outputPosition = context.Request.RecvListBuff[0].Position; ulong outputPosition = context.Request.RecvListBuff[0].Position;
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(RegisterInfo))); context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<RegisterInfo>());
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(RegisterInfo))); MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<RegisterInfo>());
uint deviceHandle = (uint)context.RequestData.ReadUInt64(); uint deviceHandle = (uint)context.RequestData.ReadUInt64();
@@ -728,9 +728,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
ulong outputPosition = context.Request.RecvListBuff[0].Position; ulong outputPosition = context.Request.RecvListBuff[0].Position;
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(CommonInfo))); context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<CommonInfo>());
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(CommonInfo))); MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<CommonInfo>());
uint deviceHandle = (uint)context.RequestData.ReadUInt64(); uint deviceHandle = (uint)context.RequestData.ReadUInt64();
@@ -788,9 +788,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
ulong outputPosition = context.Request.RecvListBuff[0].Position; ulong outputPosition = context.Request.RecvListBuff[0].Position;
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(ModelInfo))); context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ModelInfo>());
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(ModelInfo))); MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<ModelInfo>());
uint deviceHandle = (uint)context.RequestData.ReadUInt64(); uint deviceHandle = (uint)context.RequestData.ReadUInt64();

View File

@@ -1,5 +1,8 @@
using System.Collections.Concurrent; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
@@ -41,6 +44,27 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return null; 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) public int RegisterFileDescriptor(IFileDescriptor file)
{ {
lock (_lock) lock (_lock)
@@ -61,6 +85,16 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
} }
} }
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) public int DuplicateFileDescriptor(int fd)
{ {
IFileDescriptor oldFile = RetrieveFileDescriptor(fd); IFileDescriptor oldFile = RetrieveFileDescriptor(fd);

View File

@@ -1,10 +1,13 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
@@ -202,12 +205,122 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
} }
[CommandHipc(5)] [CommandHipc(5)]
// Select(u32 nfds, nn::socket::timeout timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in) -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out) // Select(u32 nfds, nn::socket::timeval timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in)
// -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out)
public ResultCode Select(ServiceCtx context) public ResultCode Select(ServiceCtx context)
{ {
WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); int fdsCount = context.RequestData.ReadInt32();
int timeout = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceBsd); (ulong readFdsInBufferPosition, ulong readFdsInBufferSize) = context.Request.GetBufferType0x21(0);
(ulong writeFdsInBufferPosition, ulong writeFdsInBufferSize) = context.Request.GetBufferType0x21(1);
(ulong errorFdsInBufferPosition, ulong errorFdsInBufferSize) = context.Request.GetBufferType0x21(2);
(ulong readFdsOutBufferPosition, ulong readFdsOutBufferSize) = context.Request.GetBufferType0x22(0);
(ulong writeFdsOutBufferPosition, ulong writeFdsOutBufferSize) = context.Request.GetBufferType0x22(1);
(ulong errorFdsOutBufferPosition, ulong errorFdsOutBufferSize) = context.Request.GetBufferType0x22(2);
List<IFileDescriptor> readFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(readFdsInBufferPosition, (int)readFdsInBufferSize));
List<IFileDescriptor> writeFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(writeFdsInBufferPosition, (int)writeFdsInBufferSize));
List<IFileDescriptor> errorFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(errorFdsInBufferPosition, (int)errorFdsInBufferSize));
int actualFdsCount = readFds.Count + writeFds.Count + errorFds.Count;
if (fdsCount == 0 || actualFdsCount == 0)
{
WriteBsdResult(context, 0);
return ResultCode.Success;
}
PollEvent[] events = new PollEvent[actualFdsCount];
int index = 0;
foreach (IFileDescriptor fd in readFds)
{
events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Input }, fd);
index++;
}
foreach (IFileDescriptor fd in writeFds)
{
events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Output }, fd);
index++;
}
foreach (IFileDescriptor fd in errorFds)
{
events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Error }, fd);
index++;
}
List<PollEvent>[] eventsByPollManager = new List<PollEvent>[_pollManagers.Count];
for (int i = 0; i < eventsByPollManager.Length; i++)
{
eventsByPollManager[i] = new List<PollEvent>();
foreach (PollEvent evnt in events)
{
if (_pollManagers[i].IsCompatible(evnt))
{
eventsByPollManager[i].Add(evnt);
}
}
}
int updatedCount = 0;
for (int i = 0; i < _pollManagers.Count; i++)
{
if (eventsByPollManager[i].Count > 0)
{
_pollManagers[i].Select(eventsByPollManager[i], timeout, out int updatedPollCount);
updatedCount += updatedPollCount;
}
}
readFds.Clear();
writeFds.Clear();
errorFds.Clear();
foreach (PollEvent pollEvent in events)
{
for (int i = 0; i < _pollManagers.Count; i++)
{
if (eventsByPollManager[i].Contains(pollEvent))
{
if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Input))
{
readFds.Add(pollEvent.FileDescriptor);
}
if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Output))
{
writeFds.Add(pollEvent.FileDescriptor);
}
if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Error))
{
errorFds.Add(pollEvent.FileDescriptor);
}
}
}
}
using var readFdsOut = context.Memory.GetWritableRegion(readFdsOutBufferPosition, (int)readFdsOutBufferSize);
using var writeFdsOut = context.Memory.GetWritableRegion(writeFdsOutBufferPosition, (int)writeFdsOutBufferSize);
using var errorFdsOut = context.Memory.GetWritableRegion(errorFdsOutBufferPosition, (int)errorFdsOutBufferSize);
_context.BuildMask(readFds, readFdsOut.Memory.Span);
_context.BuildMask(writeFds, writeFdsOut.Memory.Span);
_context.BuildMask(errorFds, errorFdsOut.Memory.Span);
WriteBsdResult(context, updatedCount);
return ResultCode.Success; return ResultCode.Success;
} }
@@ -320,14 +433,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
break; break;
} }
// If we are here, that mean nothing was availaible, sleep for 50ms // If we are here, that mean nothing was available, sleep for 50ms
context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000); context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000);
} }
while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds); while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds);
} }
else if (timeout == -1) else if (timeout == -1)
{ {
// FIXME: If we get a timeout of -1 and there is no fds to wait on, this should kill the KProces. (need to check that with re) // FIXME: If we get a timeout of -1 and there is no fds to wait on, this should kill the KProcess. (need to check that with re)
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
else else

View File

@@ -1,4 +1,5 @@
using System; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {

View File

@@ -1,4 +1,5 @@
using System; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;

View File

@@ -1,8 +1,9 @@
using System; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
class EventFileDescriptor : IFileDescriptor class EventFileDescriptor : IFileDescriptor
{ {

View File

@@ -1,8 +1,9 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
class EventFileDescriptorPollManager : IPollManager class EventFileDescriptorPollManager : IPollManager
{ {
@@ -109,5 +110,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
{
// TODO: Implement Select for event file descriptors
updatedCount = 0;
return LinuxError.EOPNOTSUPP;
}
} }
} }

View File

@@ -1,4 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -6,7 +7,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
class ManagedSocket : ISocket class ManagedSocket : ISocket
{ {

View File

@@ -1,8 +1,9 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
class ManagedSocketPollManager : IPollManager class ManagedSocketPollManager : IPollManager
{ {
@@ -117,5 +118,60 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
{
List<Socket> readEvents = new();
List<Socket> writeEvents = new();
List<Socket> errorEvents = new();
updatedCount = 0;
foreach (PollEvent pollEvent in events)
{
ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor;
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
{
readEvents.Add(socket.Socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
{
writeEvents.Add(socket.Socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error))
{
errorEvents.Add(socket.Socket);
}
}
Socket.Select(readEvents, writeEvents, errorEvents, timeout);
updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count;
foreach (PollEvent pollEvent in events)
{
ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor;
if (readEvents.Contains(socket.Socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Input;
}
if (writeEvents.Contains(socket.Socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Output;
}
if (errorEvents.Contains(socket.Socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Error;
}
}
return LinuxError.SUCCESS;
}
} }
} }

View File

@@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
[SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "InconsistentNaming")]
enum WsaError enum WsaError

View File

@@ -1,7 +1,8 @@
using System.Collections.Generic; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
static class WinSockHelper static class WinSockHelper
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdAddressFamily : uint enum BsdAddressFamily : uint
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdIoctl enum BsdIoctl
{ {

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
class BsdMMsgHdr class BsdMMsgHdr
{ {

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
class BsdMsgHdr class BsdMsgHdr
{ {

View File

@@ -3,7 +3,7 @@ using System;
using System.Net; using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)]
struct BsdSockAddr struct BsdSockAddr

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
[Flags] [Flags]
enum BsdSocketCreationFlags enum BsdSocketCreationFlags

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdSocketFlags enum BsdSocketFlags
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdSocketOption enum BsdSocketOption
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdSocketShutdownFlags enum BsdSocketShutdownFlags
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
enum BsdSocketType enum BsdSocketType
{ {

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
[Flags] [Flags]
enum EventFdFlags : uint enum EventFdFlags : uint

View File

@@ -1,11 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
interface IPollManager interface IPollManager
{ {
bool IsCompatible(PollEvent evnt); bool IsCompatible(PollEvent evnt);
LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount); LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount);
LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount);
} }
} }

View File

@@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
[SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "InconsistentNaming")]
enum LinuxError enum LinuxError

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
class PollEvent class PollEvent
{ {

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
struct PollEventData struct PollEventData
{ {

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
[Flags] [Flags]
enum PollEventTypeMask : ushort enum PollEventTypeMask : ushort

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types
{ {
public struct TimeVal public struct TimeVal
{ {

View File

@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Services.Sockets.Bsd; using Ryujinx.HLE.HOS.Services.Sockets.Bsd;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
using Ryujinx.HLE.HOS.Services.Ssl.Types; using Ryujinx.HLE.HOS.Services.Ssl.Types;
using System; using System;
using System.IO; using System.IO;

View File

@@ -1,5 +1,6 @@
using Ryujinx.Tests.Unicorn.Native.Const; using Ryujinx.Tests.Unicorn.Native.Const;
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -43,9 +44,9 @@ namespace Ryujinx.Tests.Unicorn.Native
} }
} }
public static void MarshalArrayOf<T>(IntPtr input, int length, out T[] output) public static void MarshalArrayOf<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(IntPtr input, int length, out T[] output)
{ {
int size = Marshal.SizeOf(typeof(T)); int size = Marshal.SizeOf<T>();
output = new T[length]; output = new T[length];