Add ManagedProxySocketPollManager impl

This commit is contained in:
TSR Berry 2024-08-14 03:54:37 +02:00
parent fe0c34c639
commit f14df5cbb8
No known key found for this signature in database
GPG key ID: 52353C0A4CCA15E2
2 changed files with 212 additions and 0 deletions

View file

@ -21,6 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{
EventFileDescriptorPollManager.Instance,
ManagedSocketPollManager.Instance,
ManagedProxySocketPollManager.Instance,
};
private BsdContext _context;

View file

@ -0,0 +1,211 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System.Collections.Generic;
using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
class ManagedProxySocketPollManager : IPollManager
{
private static ManagedProxySocketPollManager _instance;
public static ManagedProxySocketPollManager Instance
{
get
{
_instance ??= new ManagedProxySocketPollManager();
return _instance;
}
}
public bool IsCompatible(PollEvent evnt)
{
return evnt.FileDescriptor is ManagedProxySocket;
}
public LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount)
{
Dictionary<SelectMode, List<ManagedProxySocket>> eventDict = new()
{
{ SelectMode.SelectRead, [] },
{ SelectMode.SelectWrite, [] },
{ SelectMode.SelectError, [] },
};
updatedCount = 0;
foreach (PollEvent evnt in events)
{
ManagedProxySocket socket = (ManagedProxySocket)evnt.FileDescriptor;
bool isValidEvent = evnt.Data.InputEvents == 0;
eventDict[SelectMode.SelectError].Add(socket);
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
{
eventDict[SelectMode.SelectRead].Add(socket);
isValidEvent = true;
}
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
{
eventDict[SelectMode.SelectRead].Add(socket);
isValidEvent = true;
}
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
{
eventDict[SelectMode.SelectWrite].Add(socket);
isValidEvent = true;
}
if (!isValidEvent)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}");
return LinuxError.EINVAL;
}
}
try
{
int actualTimeoutMicroseconds = timeoutMilliseconds == -1 ? -1 : timeoutMilliseconds * 1000;
int totalEvents = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
// TODO: Maybe check all events first, wait for the timeout and then check the failed ones again?
int timeoutMicrosecondsPerEvent = actualTimeoutMicroseconds == -1 ? -1 : actualTimeoutMicroseconds / totalEvents;
foreach ((SelectMode selectMode, List<ManagedProxySocket> eventList) in eventDict)
{
List<ManagedProxySocket> newEventList = [];
foreach (ManagedProxySocket eventSocket in eventList)
{
if (eventSocket.Poll(timeoutMicrosecondsPerEvent, selectMode))
{
newEventList.Add(eventSocket);
}
}
eventDict[selectMode] = newEventList;
}
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
foreach (PollEvent evnt in events)
{
ManagedProxySocket socket = ((ManagedProxySocket)evnt.FileDescriptor);
PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents;
if (eventDict[SelectMode.SelectError].Contains(socket))
{
outputEvents |= PollEventTypeMask.Error;
// TODO: Check ProxyClient.Connected and ProxyClient.IsBound when implemented.
// See ManagedSocketPollManager
}
if (eventDict[SelectMode.SelectRead].Contains(socket))
{
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
{
outputEvents |= PollEventTypeMask.Input;
}
}
if (eventDict[SelectMode.SelectWrite].Contains(socket))
{
outputEvents |= PollEventTypeMask.Output;
}
evnt.Data.OutputEvents = outputEvents;
}
updatedCount = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
return LinuxError.SUCCESS;
}
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
{
Dictionary<SelectMode, List<ManagedProxySocket>> eventDict = new()
{
{ SelectMode.SelectRead, [] },
{ SelectMode.SelectWrite, [] },
{ SelectMode.SelectError, [] },
};
updatedCount = 0;
foreach (PollEvent pollEvent in events)
{
ManagedProxySocket socket = (ManagedProxySocket)pollEvent.FileDescriptor;
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
{
eventDict[SelectMode.SelectRead].Add(socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
{
eventDict[SelectMode.SelectWrite].Add(socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error))
{
eventDict[SelectMode.SelectError].Add(socket);
}
}
int totalEvents = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
// TODO: Maybe check all events first, wait for the timeout and then check the failed ones again?
int timeoutMicrosecondsPerEvent = timeout == -1 ? -1 : timeout / totalEvents;
foreach ((SelectMode selectMode, List<ManagedProxySocket> eventList) in eventDict)
{
List<ManagedProxySocket> newEventList = [];
foreach (ManagedProxySocket eventSocket in eventList)
{
if (eventSocket.Poll(timeoutMicrosecondsPerEvent, selectMode))
{
newEventList.Add(eventSocket);
}
}
eventDict[selectMode] = newEventList;
}
updatedCount = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
foreach (PollEvent pollEvent in events)
{
ManagedProxySocket socket = (ManagedProxySocket)pollEvent.FileDescriptor;
if (eventDict[SelectMode.SelectRead].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Input;
}
if (eventDict[SelectMode.SelectWrite].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Output;
}
if (eventDict[SelectMode.SelectError].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Error;
}
}
return LinuxError.SUCCESS;
}
}
}