EventFileDescriptor.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading;
  4. namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
  5. {
  6. class EventFileDescriptor : IFileDescriptor
  7. {
  8. private ulong _value;
  9. private readonly EventFdFlags _flags;
  10. private object _lock = new object();
  11. public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); }
  12. public ManualResetEvent WriteEvent { get; }
  13. public ManualResetEvent ReadEvent { get; }
  14. public EventFileDescriptor(ulong value, EventFdFlags flags)
  15. {
  16. // FIXME: We should support blocking operations.
  17. // Right now they can't be supported because it would cause the
  18. // service to lock up as we only have one thread processing requests.
  19. flags |= EventFdFlags.NonBlocking;
  20. _value = value;
  21. _flags = flags;
  22. WriteEvent = new ManualResetEvent(true);
  23. ReadEvent = new ManualResetEvent(true);
  24. }
  25. public int Refcount { get; set; }
  26. public void Dispose()
  27. {
  28. WriteEvent.Dispose();
  29. ReadEvent.Dispose();
  30. }
  31. public LinuxError Read(out int readSize, Span<byte> buffer)
  32. {
  33. if (buffer.Length < sizeof(ulong))
  34. {
  35. readSize = 0;
  36. return LinuxError.EINVAL;
  37. }
  38. ReadEvent.Reset();
  39. lock (_lock)
  40. {
  41. ref ulong count = ref MemoryMarshal.Cast<byte, ulong>(buffer)[0];
  42. if (_value == 0)
  43. {
  44. if (Blocking)
  45. {
  46. while (_value == 0)
  47. {
  48. Monitor.Wait(_lock);
  49. }
  50. }
  51. else
  52. {
  53. readSize = 0;
  54. return LinuxError.EAGAIN;
  55. }
  56. }
  57. readSize = sizeof(ulong);
  58. if (_flags.HasFlag(EventFdFlags.Semaphore))
  59. {
  60. --_value;
  61. count = 1;
  62. }
  63. else
  64. {
  65. count = _value;
  66. _value = 0;
  67. }
  68. ReadEvent.Set();
  69. return LinuxError.SUCCESS;
  70. }
  71. }
  72. public LinuxError Write(out int writeSize, ReadOnlySpan<byte> buffer)
  73. {
  74. if (!MemoryMarshal.TryRead(buffer, out ulong count) || count == ulong.MaxValue)
  75. {
  76. writeSize = 0;
  77. return LinuxError.EINVAL;
  78. }
  79. WriteEvent.Reset();
  80. lock (_lock)
  81. {
  82. if (_value > _value + count)
  83. {
  84. if (Blocking)
  85. {
  86. Monitor.Wait(_lock);
  87. }
  88. else
  89. {
  90. writeSize = 0;
  91. return LinuxError.EAGAIN;
  92. }
  93. }
  94. writeSize = sizeof(ulong);
  95. _value += count;
  96. Monitor.Pulse(_lock);
  97. WriteEvent.Set();
  98. return LinuxError.SUCCESS;
  99. }
  100. }
  101. }
  102. }