EventFileDescriptor.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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 AutoResetEvent _event;
  11. private object _lock = new object();
  12. public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); }
  13. public ManualResetEvent WriteEvent { get; }
  14. public ManualResetEvent ReadEvent { get; }
  15. public EventFileDescriptor(ulong value, EventFdFlags flags)
  16. {
  17. _value = value;
  18. _flags = flags;
  19. _event = new AutoResetEvent(false);
  20. WriteEvent = new ManualResetEvent(true);
  21. ReadEvent = new ManualResetEvent(true);
  22. }
  23. public int Refcount { get; set; }
  24. public void Dispose()
  25. {
  26. _event.Dispose();
  27. WriteEvent.Dispose();
  28. ReadEvent.Dispose();
  29. }
  30. public LinuxError Read(out int readSize, Span<byte> buffer)
  31. {
  32. if (buffer.Length < sizeof(ulong))
  33. {
  34. readSize = 0;
  35. return LinuxError.EINVAL;
  36. }
  37. ReadEvent.Reset();
  38. lock (_lock)
  39. {
  40. ref ulong count = ref MemoryMarshal.Cast<byte, ulong>(buffer)[0];
  41. if (_value == 0)
  42. {
  43. if (Blocking)
  44. {
  45. while (_value == 0)
  46. {
  47. _event.WaitOne();
  48. }
  49. }
  50. else
  51. {
  52. readSize = 0;
  53. return LinuxError.EAGAIN;
  54. }
  55. }
  56. readSize = sizeof(ulong);
  57. if (_flags.HasFlag(EventFdFlags.Semaphore))
  58. {
  59. --_value;
  60. count = 1;
  61. }
  62. else
  63. {
  64. count = _value;
  65. _value = 0;
  66. }
  67. ReadEvent.Set();
  68. return LinuxError.SUCCESS;
  69. }
  70. }
  71. public LinuxError Write(out int writeSize, ReadOnlySpan<byte> buffer)
  72. {
  73. if (!MemoryMarshal.TryRead(buffer, out ulong count) || count == ulong.MaxValue)
  74. {
  75. writeSize = 0;
  76. return LinuxError.EINVAL;
  77. }
  78. WriteEvent.Reset();
  79. lock (_lock)
  80. {
  81. if (_value > _value + count)
  82. {
  83. if (Blocking)
  84. {
  85. _event.WaitOne();
  86. }
  87. else
  88. {
  89. writeSize = 0;
  90. return LinuxError.EAGAIN;
  91. }
  92. }
  93. writeSize = sizeof(ulong);
  94. _value += count;
  95. _event.Set();
  96. WriteEvent.Set();
  97. return LinuxError.SUCCESS;
  98. }
  99. }
  100. }
  101. }