IPC refactor part 3+4: New server HIPC message processor (#4188)
* IPC refactor part 3 + 4: New server HIPC message processor with source generator based serialization * Make types match on calls to AlignUp/AlignDown * Formatting * Address some PR feedback * Move BitfieldExtensions to Ryujinx.Common.Utilities and consolidate implementations * Rename Reader/Writer to SpanReader/SpanWriter and move to Ryujinx.Common.Memory * Implement EventType * Address more PR feedback * Log request processing errors since they are not normal * Rename waitable to multiwait and add missing lock * PR feedback * Ac_K PR feedback
This commit is contained in:
parent
c6a139a6e7
commit
08831eecf7
213 changed files with 9762 additions and 1010 deletions
246
Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
Normal file
246
Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
Normal file
|
@ -0,0 +1,246 @@
|
|||
using Ryujinx.Horizon.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Sf.Cmif
|
||||
{
|
||||
class ServerDomainManager
|
||||
{
|
||||
private class EntryManager
|
||||
{
|
||||
public class Entry
|
||||
{
|
||||
public int Id { get; }
|
||||
public Domain Owner { get; set; }
|
||||
public ServiceObjectHolder Obj { get; set; }
|
||||
public LinkedListNode<Entry> Node { get; set; }
|
||||
|
||||
public Entry(int id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly LinkedList<Entry> _freeList;
|
||||
private readonly Entry[] _entries;
|
||||
|
||||
public EntryManager(int count)
|
||||
{
|
||||
_freeList = new LinkedList<Entry>();
|
||||
_entries = new Entry[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_freeList.AddLast(_entries[i] = new Entry(i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
public Entry AllocateEntry()
|
||||
{
|
||||
lock (_freeList)
|
||||
{
|
||||
if (_freeList.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var entry = _freeList.First.Value;
|
||||
_freeList.RemoveFirst();
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
public void FreeEntry(Entry entry)
|
||||
{
|
||||
lock (_freeList)
|
||||
{
|
||||
DebugUtil.Assert(entry.Owner == null);
|
||||
DebugUtil.Assert(entry.Obj == null);
|
||||
_freeList.AddFirst(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public Entry GetEntry(int id)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = id - 1;
|
||||
|
||||
if ((uint)index >= (uint)_entries.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _entries[index];
|
||||
}
|
||||
}
|
||||
|
||||
private class Domain : DomainServiceObject, IDisposable
|
||||
{
|
||||
private readonly ServerDomainManager _manager;
|
||||
private readonly LinkedList<EntryManager.Entry> _entries;
|
||||
|
||||
public Domain(ServerDomainManager manager)
|
||||
{
|
||||
_manager = manager;
|
||||
_entries = new LinkedList<EntryManager.Entry>();
|
||||
}
|
||||
|
||||
public override ServiceObjectHolder GetObject(int id)
|
||||
{
|
||||
var entry = _manager._entryManager.GetEntry(id);
|
||||
if (entry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_manager._entryOwnerLock)
|
||||
{
|
||||
if (entry.Owner != this)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return entry.Obj.Clone();
|
||||
}
|
||||
|
||||
public override ServerDomainBase GetServerDomain()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void RegisterObject(int id, ServiceObjectHolder obj)
|
||||
{
|
||||
var entry = _manager._entryManager.GetEntry(id);
|
||||
DebugUtil.Assert(entry != null);
|
||||
|
||||
lock (_manager._entryOwnerLock)
|
||||
{
|
||||
DebugUtil.Assert(entry.Owner == null);
|
||||
entry.Owner = this;
|
||||
entry.Node = _entries.AddLast(entry);
|
||||
}
|
||||
|
||||
entry.Obj = obj;
|
||||
}
|
||||
|
||||
public override Result ReserveIds(Span<int> outIds)
|
||||
{
|
||||
for (int i = 0; i < outIds.Length; i++)
|
||||
{
|
||||
var entry = _manager._entryManager.AllocateEntry();
|
||||
if (entry == null)
|
||||
{
|
||||
return SfResult.OutOfDomainEntries;
|
||||
}
|
||||
|
||||
DebugUtil.Assert(entry.Owner == null);
|
||||
|
||||
outIds[i] = entry.Id;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override ServiceObjectHolder UnregisterObject(int id)
|
||||
{
|
||||
var entry = _manager._entryManager.GetEntry(id);
|
||||
if (entry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceObjectHolder obj;
|
||||
|
||||
lock (_manager._entryOwnerLock)
|
||||
{
|
||||
if (entry.Owner != this)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
entry.Owner = null;
|
||||
obj = entry.Obj;
|
||||
entry.Obj = null;
|
||||
_entries.Remove(entry.Node);
|
||||
entry.Node = null;
|
||||
}
|
||||
|
||||
_manager._entryManager.FreeEntry(entry);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override void UnreserveIds(ReadOnlySpan<int> ids)
|
||||
{
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
var entry = _manager._entryManager.GetEntry(ids[i]);
|
||||
|
||||
DebugUtil.Assert(entry != null);
|
||||
DebugUtil.Assert(entry.Owner == null);
|
||||
|
||||
_manager._entryManager.FreeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
if (entry.Obj.ServiceObject is IDisposable disposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_manager.FreeDomain(this);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly EntryManager _entryManager;
|
||||
private readonly object _entryOwnerLock;
|
||||
private readonly HashSet<Domain> _domains;
|
||||
private int _maxDomains;
|
||||
|
||||
public ServerDomainManager(int entryCount, int maxDomains)
|
||||
{
|
||||
_entryManager = new EntryManager(entryCount);
|
||||
_entryOwnerLock = new object();
|
||||
_domains = new HashSet<Domain>();
|
||||
_maxDomains = maxDomains;
|
||||
}
|
||||
|
||||
public DomainServiceObject AllocateDomainServiceObject()
|
||||
{
|
||||
lock (_domains)
|
||||
{
|
||||
if (_domains.Count == _maxDomains)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var domain = new Domain(this);
|
||||
_domains.Add(domain);
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyDomainServiceObject(DomainServiceObject obj)
|
||||
{
|
||||
((Domain)obj).Dispose();
|
||||
}
|
||||
|
||||
private void FreeDomain(Domain domain)
|
||||
{
|
||||
lock (_domains)
|
||||
{
|
||||
_domains.Remove(domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue