/ src / Ryujinx.HLE / HOS / Services / Sockets / Bsd / Impl / EventFileDescriptorPollManager.cs
EventFileDescriptorPollManager.cs
  1  using Ryujinx.Common.Logging;
  2  using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
  3  using System.Collections.Generic;
  4  using System.Threading;
  5  
  6  namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
  7  {
  8      class EventFileDescriptorPollManager : IPollManager
  9      {
 10          private static EventFileDescriptorPollManager _instance;
 11  
 12          public static EventFileDescriptorPollManager Instance
 13          {
 14              get
 15              {
 16                  _instance ??= new EventFileDescriptorPollManager();
 17  
 18                  return _instance;
 19              }
 20          }
 21  
 22          public bool IsCompatible(PollEvent evnt)
 23          {
 24              return evnt.FileDescriptor is EventFileDescriptor;
 25          }
 26  
 27          public LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount)
 28          {
 29              updatedCount = 0;
 30  
 31              List<ManualResetEvent> waiters = new();
 32  
 33              for (int i = 0; i < events.Count; i++)
 34              {
 35                  PollEvent evnt = events[i];
 36  
 37                  EventFileDescriptor socket = (EventFileDescriptor)evnt.FileDescriptor;
 38  
 39                  bool isValidEvent = false;
 40  
 41                  if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input) ||
 42                      evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
 43                  {
 44                      waiters.Add(socket.ReadEvent);
 45  
 46                      isValidEvent = true;
 47                  }
 48                  if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
 49                  {
 50                      waiters.Add(socket.WriteEvent);
 51  
 52                      isValidEvent = true;
 53                  }
 54  
 55                  if (!isValidEvent)
 56                  {
 57                      Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}");
 58  
 59                      return LinuxError.EINVAL;
 60                  }
 61              }
 62  
 63              int index = WaitHandle.WaitAny(waiters.ToArray(), timeoutMilliseconds);
 64  
 65              if (index != WaitHandle.WaitTimeout)
 66              {
 67                  for (int i = 0; i < events.Count; i++)
 68                  {
 69                      PollEventTypeMask outputEvents = 0;
 70  
 71                      PollEvent evnt = events[i];
 72  
 73                      EventFileDescriptor socket = (EventFileDescriptor)evnt.FileDescriptor;
 74  
 75                      if (socket.ReadEvent.WaitOne(0))
 76                      {
 77                          if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
 78                          {
 79                              outputEvents |= PollEventTypeMask.Input;
 80                          }
 81  
 82                          if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
 83                          {
 84                              outputEvents |= PollEventTypeMask.UrgentInput;
 85                          }
 86                      }
 87  
 88                      if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
 89                          && socket.WriteEvent.WaitOne(0))
 90                      {
 91                          outputEvents |= PollEventTypeMask.Output;
 92                      }
 93  
 94  
 95                      if (outputEvents != 0)
 96                      {
 97                          evnt.Data.OutputEvents = outputEvents;
 98  
 99                          updatedCount++;
100                      }
101                  }
102              }
103              else
104              {
105                  return LinuxError.ETIMEDOUT;
106              }
107  
108              return LinuxError.SUCCESS;
109          }
110  
111          public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
112          {
113              // TODO: Implement Select for event file descriptors
114              updatedCount = 0;
115  
116              return LinuxError.EOPNOTSUPP;
117          }
118      }
119  }