/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IIOProcessor.hpp Date: 2022-6-6 Author: Reece ***/ #pragma once namespace Aurora::IO::Loop { struct ILoopQueue; struct ILoopSource; } namespace Aurora::IO { struct IIOProcessor { // Local thread: // note: IOProcessors running over an AuAsync runner or is getting pumped by an external loop queue (NewIOProcessor(...), NewIOProcessorOnThread(...)) need not use the following apis: virtual AuUInt32 TryTick () = 0; virtual AuUInt32 RunTick () = 0; virtual AuUInt32 RunTickEx (AuUInt32 dwTimeout) = 0; virtual AuUInt32 TickFor (const AuSPtr &pIoEvent) = 0; /** * @brief force a tick */ virtual AuUInt32 ManualTick () = 0; /** * @brief to be used with bTickOnly primarily. wakes up the thread at a set frequency. */ virtual AuUInt64 SetRefreshRate (AuUInt64 ns) = 0; /** * @brief to be used with bTickOnly primarily. wakes up the thread at a set frequency. */ virtual bool HasRefreshRate () = 0; /** * @brief returns the aurora threadid of the intended caller (see: AuThreads::GetThreadId()) */ virtual AuUInt64 GetOwnedThreadId () = 0; // The following apis are thread safe: /** * @brief Used to poll if there are any items worth [try/blocking] ticking over. * @return returns true if there are callbacks, watches, or other registered work available. * @note you can use me as a while (AuIsThreadRunning() && pIoProcessor->[IsAlive/HasItems]()) { pIoProcessor->[RunTickEx(uTimeout); } */ virtual bool HasItems() = 0; // the following are apis used to register triggers (usually loop sources) on the thread/processor/loop queue/whatever /** * @brief low level wait api */ virtual AuSPtr StartIOWatch (const AuSPtr &pSource, const AuSPtr &pEventListener) = 0; /** * @brief low level wait api */ virtual AuSPtr StartIOWatchEx (const AuSPtr &pSource, const AuSPtr &pEventListener, bool bSingleshot) = 0; /** * @brief low level wait api with simple callback */ virtual AuSPtr StartSimpleIOWatch (const AuSPtr &pSource, const AuSPtr &pEventListener) = 0; /** * @brief low level wait api with simple callback */ virtual AuSPtr StartSimpleIOWatchEx(const AuSPtr &pSource, const AuSPtr &pEventListener, bool bSingleshot) = 0; /** * @brief Registers a callback given a loopsource (multi-trigger) * @param pSource * @param pEventListener * @return */ virtual AuSPtr StartSimpleLSWatch (const AuSPtr &pSource, const AuSPtr &pEventListener) = 0; /** * @brief Registers an optionally singleshot callback given a loopsource * @param pSource * @param pEventListener * @param dwMsTimeout optional timeout * @return */ virtual AuSPtr StartSimpleLSWatchEx(const AuSPtr &pSource, const AuSPtr &pEventListener, bool bSingleshot, AuUInt32 dwMsTimeout = 0) = 0; // general purpose work callbacks /** * @brief Dispatches an abortable callback to the processor thread * @param pWork * @return */ virtual bool SubmitIOWorkItem (const AuSPtr &pWork) = 0; // wake up /** * @brief you almost certainly will not need me. so far i've come across one legitmate use case for glib-io interop and thats about it. */ virtual void WakeupThread () = 0; // io sequence callbacks /** * @brief Register an inter-frame callback indicating point of execution throughout the [START](optional [yield])[IO][IO TICK][WORK ITEMS][EPILOGUE][END OF FRAME] frame * @param eventListener * @return */ virtual bool AddEventListener (const AuSPtr &pEventListener) = 0; /** * @brief Deregisters an inter-frame callback listener * @param pEventListener */ virtual void RemoveEventListener (const AuSPtr &pEventListener) = 0; // factories backed by this processor to provide additional functionality /** * @brief provides an IO pipe processor for creating pipe requests * @return */ virtual AuSPtr ToPipeProcessor () = 0; // internal and utility apis /** * @brief Utility proprety access to the underlying IO wait surface: a loop queue * @return * @warning Do not use me unless you know what you're doing. * There is very little reason to pull the underlying loop queue from here. * You are probably doing something wrong. IOProcessors are meant to sit on top of * queues as an abstraction layer for intelligent work dispatch, global stream processing * and dispatch of io work callbacks. pulling a loopqueue from such a layer of abstraction * would be like pulling the state of an upcoming WaitMultipleObjects call; it makes no sense. * * [note to future deadbeat maintainers: that doesnt mean you should remove it either] */ virtual AuSPtr ToQueue () = 0; virtual bool MultiplexRefreshRateWithIOEvents() = 0; /** * @brief resets the io processors footprint in ::ToQueue() */ virtual void ReleaseAllWatches () = 0; /** * @warning: do not use me. this is a niche hack for nested ui modal loops. */ virtual bool ConfigureNoDeferredTicks(bool bOption) = 0; }; /** * @brief Creates an IOProcessor to execute tasks on a given loop queue * @param bTickOnly True if kernel yielding on IO objects is disabled in favor of forced TPS. * Do note that the throughput of a tick will differ per platform. Accept rate, * throughput, etc may need tweaking, if you wish to drive an IIOProcessor using * a timer or the manual tick functions. * @param pQueue * @return */ AUKN_SYM AuSPtr NewIOProcessor(bool bTickOnly, const AuSPtr &pQueue); /** * @brief Creates an IOProcessor to execute tasks on the loop queue of a given AuAsync thread id * @param bTickOnly True if kernel yielding on IO objects is disabled in favor of forced TPS. * Do note that the throughput of a tick will differ per platform. Accept rate, * throughput, etc may need tweaking, if you wish to drive an IIOProcessor using * a timer or the manual tick functions. * @param pQueue * @return */ AUKN_SYM AuSPtr NewIOProcessorOnThread(bool bTickOnly, Async::WorkerPId_t id); AUKN_SYM AuSPtr NewIOProcessorNoQueue(bool bTickOnly); }