| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- using Ryujinx.Horizon.Sdk.OsTypes;
- using Ryujinx.Horizon.Common;
- using Ryujinx.Horizon.Sdk.Sf.Cmif;
- using Ryujinx.Horizon.Sdk.Sm;
- using System;
- namespace Ryujinx.Horizon.Sdk.Sf.Hipc
- {
- class ServerManagerBase : ServerDomainSessionManager
- {
- private readonly SmApi _sm;
- private bool _canDeferInvokeRequest;
- private readonly MultiWait _multiWait;
- private readonly MultiWait _waitList;
- private readonly object _multiWaitSelectionLock;
- private readonly object _waitListLock;
- private readonly Event _requestStopEvent;
- private readonly Event _notifyEvent;
- private readonly MultiWaitHolderBase _requestStopEventHolder;
- private readonly MultiWaitHolderBase _notifyEventHolder;
- private enum UserDataTag
- {
- Server = 1,
- Session = 2
- }
- public ServerManagerBase(SmApi sm, ManagerOptions options) : base(options.MaxDomainObjects, options.MaxDomains)
- {
- _sm = sm;
- _canDeferInvokeRequest = options.CanDeferInvokeRequest;
- _multiWait = new MultiWait();
- _waitList = new MultiWait();
- _multiWaitSelectionLock = new object();
- _waitListLock = new object();
- _requestStopEvent = new Event(EventClearMode.ManualClear);
- _notifyEvent = new Event(EventClearMode.ManualClear);
- _requestStopEventHolder = new MultiWaitHolderOfEvent(_requestStopEvent);
- _multiWait.LinkMultiWaitHolder(_requestStopEventHolder);
- _notifyEventHolder = new MultiWaitHolderOfEvent(_notifyEvent);
- _multiWait.LinkMultiWaitHolder(_notifyEventHolder);
- }
- public void RegisterObjectForServer(IServiceObject staticObject, int portHandle)
- {
- RegisterServerImpl(0, new ServiceObjectHolder(staticObject), portHandle);
- }
- public Result RegisterObjectForServer(IServiceObject staticObject, ServiceName name, int maxSessions)
- {
- return RegisterServerImpl(0, new ServiceObjectHolder(staticObject), name, maxSessions);
- }
- public void RegisterServer(int portIndex, int portHandle)
- {
- RegisterServerImpl(portIndex, null, portHandle);
- }
- public Result RegisterServer(int portIndex, ServiceName name, int maxSessions)
- {
- return RegisterServerImpl(portIndex, null, name, maxSessions);
- }
- private void RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, int portHandle)
- {
- Server server = AllocateServer(portIndex, portHandle, ServiceName.Invalid, managed: false, staticHolder);
- RegisterServerImpl(server);
- }
- private Result RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, ServiceName name, int maxSessions)
- {
- Result result = _sm.RegisterService(out int portHandle, name, maxSessions, isLight: false);
- if (result.IsFailure)
- {
- return result;
- }
- Server server = AllocateServer(portIndex, portHandle, name, managed: true, staticHolder);
- RegisterServerImpl(server);
- return Result.Success;
- }
- private void RegisterServerImpl(Server server)
- {
- server.UserData = UserDataTag.Server;
- _multiWait.LinkMultiWaitHolder(server);
- }
- protected virtual Result OnNeedsToAccept(int portIndex, Server server)
- {
- throw new NotSupportedException();
- }
- protected Result AcceptImpl(Server server, IServiceObject obj)
- {
- return AcceptSession(server.PortHandle, new ServiceObjectHolder(obj));
- }
- public void ServiceRequests()
- {
- while (WaitAndProcessRequestsImpl());
- }
- public void WaitAndProcessRequests()
- {
- WaitAndProcessRequestsImpl();
- }
- private bool WaitAndProcessRequestsImpl()
- {
- try
- {
- MultiWaitHolder multiWait = WaitSignaled();
- if (multiWait == null)
- {
- return false;
- }
- DebugUtil.Assert(Process(multiWait).IsSuccess);
- return HorizonStatic.ThreadContext.Running;
- }
- catch (ThreadTerminatedException)
- {
- return false;
- }
- }
- private MultiWaitHolder WaitSignaled()
- {
- lock (_multiWaitSelectionLock)
- {
- while (true)
- {
- ProcessWaitList();
- MultiWaitHolder selected = _multiWait.WaitAny();
- if (selected == _requestStopEventHolder)
- {
- return null;
- }
- else if (selected == _notifyEventHolder)
- {
- _notifyEvent.Clear();
- }
- else
- {
- selected.UnlinkFromMultiWaitHolder();
- return selected;
- }
- }
- }
- }
- public void ResumeProcessing()
- {
- _requestStopEvent.Clear();
- }
- public void RequestStopProcessing()
- {
- _requestStopEvent.Signal();
- }
- protected override void RegisterSessionToWaitList(ServerSession session)
- {
- session.HasReceived = false;
- session.UserData = UserDataTag.Session;
- RegisterToWaitList(session);
- }
- private void RegisterToWaitList(MultiWaitHolder holder)
- {
- lock (_waitListLock)
- {
- _waitList.LinkMultiWaitHolder(holder);
- _notifyEvent.Signal();
- }
- }
- private void ProcessWaitList()
- {
- lock (_waitListLock)
- {
- _multiWait.MoveAllFrom(_waitList);
- }
- }
- private Result Process(MultiWaitHolder holder)
- {
- return (UserDataTag)holder.UserData switch
- {
- UserDataTag.Server => ProcessForServer(holder),
- UserDataTag.Session => ProcessForSession(holder),
- _ => throw new NotImplementedException(((UserDataTag)holder.UserData).ToString())
- };
- }
- private Result ProcessForServer(MultiWaitHolder holder)
- {
- DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Server);
- Server server = (Server)holder;
- try
- {
- if (server.StaticObject != null)
- {
- return AcceptSession(server.PortHandle, server.StaticObject.Clone());
- }
- else
- {
- return OnNeedsToAccept(server.PortIndex, server);
- }
- }
- finally
- {
- RegisterToWaitList(server);
- }
- }
- private Result ProcessForSession(MultiWaitHolder holder)
- {
- DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Session);
- ServerSession session = (ServerSession)holder;
- using var tlsMessage = HorizonStatic.AddressSpace.GetWritableRegion(HorizonStatic.ThreadContext.TlsAddress, Api.TlsMessageBufferSize);
- Result result;
- if (_canDeferInvokeRequest)
- {
- // If the request is deferred, we save the message on a temporary buffer to process it later.
- using var savedMessage = HorizonStatic.AddressSpace.GetWritableRegion(session.SavedMessage.Address, (int)session.SavedMessage.Size);
- DebugUtil.Assert(tlsMessage.Memory.Length == savedMessage.Memory.Length);
- if (!session.HasReceived)
- {
- result = ReceiveRequest(session, tlsMessage.Memory.Span);
- if (result.IsFailure)
- {
- return result;
- }
- session.HasReceived = true;
- tlsMessage.Memory.Span.CopyTo(savedMessage.Memory.Span);
- }
- else
- {
- savedMessage.Memory.Span.CopyTo(tlsMessage.Memory.Span);
- }
- result = ProcessRequest(session, tlsMessage.Memory.Span);
- if (result.IsFailure && !SfResult.Invalidated(result))
- {
- return result;
- }
- }
- else
- {
- if (!session.HasReceived)
- {
- result = ReceiveRequest(session, tlsMessage.Memory.Span);
- if (result.IsFailure)
- {
- return result;
- }
- session.HasReceived = true;
- }
- result = ProcessRequest(session, tlsMessage.Memory.Span);
- if (result.IsFailure)
- {
- // Those results are not valid because the service does not support deferral.
- if (SfResult.RequestDeferred(result) || SfResult.Invalidated(result))
- {
- result.AbortOnFailure();
- }
- return result;
- }
- }
- return Result.Success;
- }
- }
- }
|