AuroraRuntime/Include/Aurora/IO/IIOProcessor.hpp

189 lines
7.9 KiB
C++

/***
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<IIOProcessorItem> &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<IIOProcessorItem> StartIOWatch (const AuSPtr<IIOWaitableItem> &pSource, const AuSPtr<IIOEventListener> &pEventListener) = 0;
/**
* @brief low level wait api
*/
virtual AuSPtr<IIOProcessorItem> StartIOWatchEx (const AuSPtr<IIOWaitableItem> &pSource, const AuSPtr<IIOEventListener> &pEventListener, bool bSingleshot) = 0;
/**
* @brief low level wait api with simple callback
*/
virtual AuSPtr<IIOProcessorItem> StartSimpleIOWatch (const AuSPtr<IIOWaitableItem> &pSource, const AuSPtr<IIOSimpleEventListener> &pEventListener) = 0;
/**
* @brief low level wait api with simple callback
*/
virtual AuSPtr<IIOProcessorItem> StartSimpleIOWatchEx(const AuSPtr<IIOWaitableItem> &pSource, const AuSPtr<IIOSimpleEventListener> &pEventListener, bool bSingleshot) = 0;
/**
* @brief Registers a callback given a loopsource (multi-trigger)
* @param pSource
* @param pEventListener
* @return
*/
virtual AuSPtr<IIOProcessorItem> StartSimpleLSWatch (const AuSPtr<Loop::ILoopSource> &pSource, const AuSPtr<IIOSimpleEventListener> &pEventListener) = 0;
/**
* @brief Registers an optionally singleshot callback given a loopsource
* @param pSource
* @param pEventListener
* @param dwMsTimeout optional timeout
* @return
*/
virtual AuSPtr<IIOProcessorItem> StartSimpleLSWatchEx(const AuSPtr<Loop::ILoopSource> &pSource, const AuSPtr<IIOSimpleEventListener> &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<IIOProcessorWorkUnit> &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<IIOProcessorEventListener> &pEventListener) = 0;
/**
* @brief Deregisters an inter-frame callback listener
* @param pEventListener
*/
virtual void RemoveEventListener (const AuSPtr<IIOProcessorEventListener> &pEventListener) = 0;
// factories backed by this processor to provide additional functionality
/**
* @brief provides an IO pipe processor for creating pipe requests
* @return
*/
virtual AuSPtr<IIOPipeProcessor> 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<Loop::ILoopQueue> 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<IIOProcessor> NewIOProcessor(bool bTickOnly, const AuSPtr<Loop::ILoopQueue> &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<IIOProcessor> NewIOProcessorOnThread(bool bTickOnly, Async::WorkerPId_t id);
AUKN_SYM AuSPtr<IIOProcessor> NewIOProcessorNoQueue(bool bTickOnly);
}