bsd: Fix eventfd broken logic (#3647)

* bsd: Fix eventfd broken logic

This commit fix eventfd logic being broken.

The following changes were made:
- EventFd IPC definition had argument inverted
- EventFd events weren't fired correctly
- Poll logic was wrong and unfinished for eventfd
- Reintroduce workaround from #3385 but in a safer way, and spawn 4
  threads.

* ipc: Rework a bit for multithreads

* Clean up debug logs

* Make server thread yield when managed lock isn't availaible

* Fix replyTargetHandle not being added in the proper locking scope

* Simplify some scopes

* Address gdkchan's comments

* Revert IPC workaround for now

* Reintroduce the EventFileDescriptor workaround
This commit is contained in:
Mary-nyan 2022-11-27 21:18:05 +01:00 committed by GitHub
parent 18b61aff59
commit 1865ea87e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 17 deletions

View file

@ -315,6 +315,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
} }
} }
if (updateCount > 0)
{
break;
}
// If we are here, that mean nothing was availaible, sleep for 50ms // If we are here, that mean nothing was availaible, sleep for 50ms
context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000); context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000);
} }
@ -972,11 +977,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
} }
[CommandHipc(31)] // 7.0.0+ [CommandHipc(31)] // 7.0.0+
// EventFd(u64 initval, nn::socket::EventFdFlags flags) -> (i32 ret, u32 bsd_errno) // EventFd(nn::socket::EventFdFlags flags, u64 initval) -> (i32 ret, u32 bsd_errno)
public ResultCode EventFd(ServiceCtx context) public ResultCode EventFd(ServiceCtx context)
{ {
ulong initialValue = context.RequestData.ReadUInt64();
EventFdFlags flags = (EventFdFlags)context.RequestData.ReadUInt32(); EventFdFlags flags = (EventFdFlags)context.RequestData.ReadUInt32();
context.RequestData.BaseStream.Position += 4; // Padding
ulong initialValue = context.RequestData.ReadUInt64();
EventFileDescriptor newEventFile = new EventFileDescriptor(initialValue, flags); EventFileDescriptor newEventFile = new EventFileDescriptor(initialValue, flags);

View file

@ -26,8 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value = value; _value = value;
_flags = flags; _flags = flags;
WriteEvent = new ManualResetEvent(true); WriteEvent = new ManualResetEvent(false);
ReadEvent = new ManualResetEvent(true); ReadEvent = new ManualResetEvent(false);
UpdateEventStates();
} }
public int Refcount { get; set; } public int Refcount { get; set; }
@ -38,6 +39,25 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
ReadEvent.Dispose(); ReadEvent.Dispose();
} }
private void ResetEventStates()
{
WriteEvent.Reset();
ReadEvent.Reset();
}
private void UpdateEventStates()
{
if (_value > 0)
{
ReadEvent.Set();
}
if (_value != uint.MaxValue - 1)
{
WriteEvent.Set();
}
}
public LinuxError Read(out int readSize, Span<byte> buffer) public LinuxError Read(out int readSize, Span<byte> buffer)
{ {
if (buffer.Length < sizeof(ulong)) if (buffer.Length < sizeof(ulong))
@ -47,10 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.EINVAL; return LinuxError.EINVAL;
} }
ReadEvent.Reset();
lock (_lock) lock (_lock)
{ {
ResetEventStates();
ref ulong count = ref MemoryMarshal.Cast<byte, ulong>(buffer)[0]; ref ulong count = ref MemoryMarshal.Cast<byte, ulong>(buffer)[0];
if (_value == 0) if (_value == 0)
@ -66,6 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
readSize = 0; readSize = 0;
UpdateEventStates();
return LinuxError.EAGAIN; return LinuxError.EAGAIN;
} }
} }
@ -85,8 +106,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value = 0; _value = 0;
} }
ReadEvent.Set(); UpdateEventStates();
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
} }
@ -100,10 +120,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.EINVAL; return LinuxError.EINVAL;
} }
WriteEvent.Reset();
lock (_lock) lock (_lock)
{ {
ResetEventStates();
if (_value > _value + count) if (_value > _value + count)
{ {
if (Blocking) if (Blocking)
@ -114,6 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
writeSize = 0; writeSize = 0;
UpdateEventStates();
return LinuxError.EAGAIN; return LinuxError.EAGAIN;
} }
} }
@ -123,8 +144,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value += count; _value += count;
Monitor.Pulse(_lock); Monitor.Pulse(_lock);
WriteEvent.Set(); UpdateEventStates();
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
} }

View file

@ -68,20 +68,37 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
for (int i = 0; i < events.Count; i++) for (int i = 0; i < events.Count; i++)
{ {
PollEventTypeMask outputEvents = 0;
PollEvent evnt = events[i]; PollEvent evnt = events[i];
EventFileDescriptor socket = (EventFileDescriptor)evnt.FileDescriptor; EventFileDescriptor socket = (EventFileDescriptor)evnt.FileDescriptor;
if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input) || if (socket.ReadEvent.WaitOne(0))
evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
&& socket.ReadEvent.WaitOne(0))
{ {
waiters.Add(socket.ReadEvent); if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
{
outputEvents |= PollEventTypeMask.Input;
}
if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
{
outputEvents |= PollEventTypeMask.UrgentInput;
}
} }
if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Output)) if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
&& socket.WriteEvent.WaitOne(0)) && socket.WriteEvent.WaitOne(0))
{ {
waiters.Add(socket.WriteEvent); outputEvents |= PollEventTypeMask.Output;
}
if (outputEvents != 0)
{
evnt.Data.OutputEvents = outputEvents;
updatedCount++;
} }
} }
} }