2009-06-08 04:46:07 +02:00
/*
2018-11-23 21:29:54 +01:00
SteamDispatcher - Steam - Layer command dispatch and execution
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02:00
Copyright ( C ) Lumiera . org
2008 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2009-06-08 04:46:07 +02:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-23 21:29:54 +01:00
/** @file steam-dispatcher.cpp
2016-12-16 23:26:56 +01:00
* * Implementation details of running commands and the builder .
2018-11-23 21:29:54 +01:00
* * The SteamDispatcher is at the heart of the session subsystem and implements a
2016-12-22 19:35:42 +01:00
* * ( single ) session thread to perform commands and trigger builder runs . New commands
* * can be enqueued with a dedicated CommandQueue , while the details of operation control
* * logic are encapsulated in a [ logic component ] ( \ ref Looper ) .
* *
* * # Operational Semantics
2018-11-23 21:29:54 +01:00
* * We need to distinguish between the SteamDispatcher itself , which is a static ( singleton ) service ,
2016-12-22 19:35:42 +01:00
* * and the » Session Subsystem « plus the _Session proper . _ The subsystem has an application - global lifecycle ,
* * while the Session itself is a data structure and can be closed , opened or re - loaded . There is a singular
* * transactional access point to the Session datastructure , which can be switched to new session contents .
* * But external manipulation of the session contents is performed by commands , which are _dispatched_ - -
* * to manage this process is the concern of the » Session Subsystem « .
* *
* * Closing a session blocks further command processing , while the lifecycle of the _Session Subsystem_ is
2017-08-04 19:07:05 +02:00
* * actually linked to _running the \ ref DispatcherLoop_ - - implementation logic defined within this
* * translation unit . This loop implementation is performed in a dedicated thread , _the Session Loop Thread . _
* * And this also entails opening the public SessionCommandService interface .
2016-12-22 19:35:42 +01:00
* *
* * # # Loop operation control
2016-12-22 21:36:03 +01:00
* * The loop starts with a blocking wait state , bound to the condition Looper : : requireAction . Here , Looper
* * is a helper to encapsulate the control logic , separated from the actual control flow . In the loop body ,
* * depending on the Looper ' s decision , either the next command is fetched from the CommandQueue and dispatched ,
2016-12-23 07:26:00 +01:00
* * or a builder run is triggered , rebuilding the » Low - Level - Model « to reflect the executed command ' s effects .
2016-12-22 21:36:03 +01:00
* * After these working actions , a _ " check point " _ is reached in Looper : : markStateProcessed , which updates
2016-12-23 07:26:00 +01:00
* * the logic and manages a _dirty state_ to control builder runs . After that , the looping control flow
* * again enters the possibly blocking condition wait .
2016-12-22 21:36:03 +01:00
* * - after a command has been dispatched , the builder is _dirty_ and needs to run
* * - yet we continue to dispatch further commands , until the queue is emptied
* * - and only after a further small latency wait , the builder run is triggered
* * - but we _enforce a builder run_ after some extended timeout period , even
* * when the command queue is not yet emptied
* * - from the outside , it is possible to deactivate processing and place the
* * loop into dormant state . This is used while closing or loading the Session
* * - and of course we can request the Session Loop Thread to stop , for shutting
* * down the » Session Subsystem « as a whole
* * - in both cases the currently performed action ( command or builder ) is
* * finished , without interrupt
2016-12-22 19:35:42 +01:00
* *
2016-12-22 21:36:03 +01:00
* * # # Locking
2018-11-23 21:29:54 +01:00
* * The SteamDispatcher uses an " inner and outer capsule " design , and both layers are locked independently .
2016-12-22 21:36:03 +01:00
* * On the outer layer , locking ensures sanity of the control data structures , while locking on the inner
* * layer guards the communication with the Session Loop Thread , and coordinates sleep wait and notification .
* * As usual with Lumiera ' s Thread wrapper , the management of the thread ' s lifecycle itself , hand - over of
2016-12-23 07:26:00 +01:00
* * parameters , and starting / joining of the thread operation is protected by separate locking embedded
* * into the thread and threadpool handling code .
* * @ note most of the time , the Session Loop Thread does not hold any lock , most notably while performing
* * a command or running the builder . Likewise , evaluation of the control logic in the Looper helper
2016-12-22 21:36:03 +01:00
* * is a private detail of the performing thread . The lock is acquired solely for checking or leaving
2017-01-05 21:40:37 +01:00
* * the wait state and when fetching the next command from queue .
2016-12-16 23:26:56 +01:00
* *
2018-11-23 21:29:54 +01:00
* * @ see SteamDispatcher
2016-12-16 23:26:56 +01:00
* * @ see DispatcherLooper_test
* * @ see CommandQueue_test
* *
*/
2009-06-08 04:46:07 +02:00
2016-12-13 04:45:00 +01:00
# include "lib/error.hpp"
# include "include/logging.h"
2018-11-23 21:29:54 +01:00
# include "steam/control/steam-dispatcher.hpp"
2018-11-15 23:42:43 +01:00
# include "steam/control/command-dispatch.hpp"
# include "steam/control/command-queue.hpp"
# include "steam/control/looper.hpp"
# include "steam/control/session-command-service.hpp"
# include "steam/mobject/session.hpp"
2018-04-02 04:19:17 +02:00
# include "lib/depend-inject.hpp"
2023-09-30 03:12:55 +02:00
# include "lib/sync-barrier.hpp"
# include "lib/thread.hpp"
2017-01-11 06:09:34 +01:00
# include "lib/util.hpp" ///////////////TODO for test command invocation
2009-06-08 04:46:07 +02:00
2016-12-15 05:54:48 +01:00
# include <memory>
2016-12-13 04:34:28 +01:00
2016-12-14 04:18:58 +01:00
using lib : : Sync ;
using lib : : RecursiveLock_Waitable ;
2023-09-30 03:12:55 +02:00
using lib : : SyncBarrier ;
using lib : : Thread ;
2016-12-15 05:54:48 +01:00
using std : : unique_ptr ;
2009-06-08 04:46:07 +02:00
2018-11-15 23:55:13 +01:00
namespace steam {
2009-06-08 04:46:07 +02:00
namespace control {
2016-12-16 23:11:19 +01:00
namespace error = lumiera : : error ;
2017-01-05 23:36:42 +01:00
/********************************************************************/ /**
2018-11-23 21:29:54 +01:00
* PImpl within SteamDispatcher to implement the _Session Loop Thread . _
2017-01-05 23:36:42 +01:00
* During the lifetime of this object . . .
2016-12-23 07:26:00 +01:00
* - the SessionCommandService is offered to enqueue commands
* - the Session Loop thread dispatches commands and triggers the Builder
* @ see DispatcherLooper_test
*/
2016-12-13 04:34:28 +01:00
class DispatcherLoop
2023-09-30 03:12:55 +02:00
: public CommandDispatch
2016-12-14 04:18:58 +01:00
, public Sync < RecursiveLock_Waitable >
2016-12-13 04:34:28 +01:00
{
2018-04-02 04:19:17 +02:00
using ServiceHandle = lib : : DependInject < SessionCommandService > : : ServiceInstance < > ;
2017-01-05 23:36:42 +01:00
2016-12-22 19:35:42 +01:00
/** manage the primary public Session interface */
2018-04-02 04:19:17 +02:00
ServiceHandle commandService_ ;
2016-12-15 05:38:12 +01:00
2023-09-30 03:12:55 +02:00
SyncBarrier init_ ;
2016-12-15 20:48:35 +01:00
CommandQueue queue_ ;
Looper looper_ ;
2023-09-30 03:12:55 +02:00
Thread thread_ ;
2016-12-15 05:38:12 +01:00
2016-12-13 04:34:28 +01:00
public :
2017-01-04 01:44:35 +01:00
/** start the session loop thread
* @ param notification callback to invoke on thread termination
* @ remark _in theory_ this ctor could block , since it waits for the thread
* actually to get operational and it waits for the SessionCommand interface
2017-01-05 22:35:33 +01:00
* to be opened . The latter _better should not_ run into any obstacles , because
* in case it does , the main application thread will be deadlocked on startup .
2017-01-04 01:44:35 +01:00
* Such might happen indirectly , when something depends on " the Session "
*/
2016-12-13 04:34:28 +01:00
DispatcherLoop ( Subsys : : SigTerm notification )
2023-09-30 03:12:55 +02:00
: commandService_ { ServiceHandle : : NOT_YET_STARTED }
2018-04-02 04:19:17 +02:00
, queue_ { }
2016-12-16 19:21:06 +01:00
, looper_ ( [ & ] ( ) - > bool
{
return not queue_ . empty ( ) ;
} )
2023-09-30 03:12:55 +02:00
, thread_ { " Lumiera Session "
, & DispatcherLoop : : runSessionThread
, this , notification }
2016-12-13 04:34:28 +01:00
{
2023-09-30 03:12:55 +02:00
init_ . sync ( ) ; // done with setup; loop may run now....
2018-11-15 21:13:52 +01:00
INFO ( session , " Steam-Dispatcher running... " ) ;
2017-01-05 22:35:33 +01:00
{
2018-04-02 04:19:17 +02:00
Lock ( this ) ; // open public session interface:
commandService_ . createInstance ( * this ) ;
2017-01-05 22:35:33 +01:00
}
2016-12-13 04:34:28 +01:00
}
~ DispatcherLoop ( )
{
2016-12-15 05:54:48 +01:00
try {
2023-09-30 03:12:55 +02:00
commandService_ . shutdown ( ) ; // redundant call, to ensure session interface is closed reliably
2018-11-15 21:13:52 +01:00
INFO ( session , " Steam-Dispatcher stopped. " ) ;
2016-12-15 05:54:48 +01:00
}
2018-11-15 21:13:52 +01:00
ERROR_LOG_AND_IGNORE ( session , " Stopping the Steam-Dispatcher " ) ;
2016-12-13 04:34:28 +01:00
}
2016-12-14 04:57:08 +01:00
void
activateCommandProecssing ( )
{
Lock sync ( this ) ;
2017-01-05 23:36:42 +01:00
looper_ . enableProcessing ( true ) ;
2016-12-14 04:57:08 +01:00
INFO ( command , " Session command processing activated. " ) ;
2017-01-05 23:36:42 +01:00
sync . notifyAll ( ) ;
2016-12-14 04:57:08 +01:00
}
void
deactivateCommandProecssing ( )
{
Lock sync ( this ) ;
2017-01-05 23:36:42 +01:00
looper_ . enableProcessing ( false ) ;
2016-12-14 04:57:08 +01:00
INFO ( command , " Session command interface closed. " ) ;
2017-01-05 23:36:42 +01:00
sync . notifyAll ( ) ;
2016-12-14 04:57:08 +01:00
}
2016-12-15 05:21:03 +01:00
void
2017-01-05 20:43:53 +01:00
requestStop ( ) noexcept
2016-12-15 05:21:03 +01:00
{
Lock sync ( this ) ;
2018-04-02 04:19:17 +02:00
commandService_ . shutdown ( ) ; // closes Session interface
2017-01-05 20:43:53 +01:00
looper_ . triggerShutdown ( ) ;
2017-01-05 21:40:37 +01:00
sync . notifyAll ( ) ;
2016-12-15 05:21:03 +01:00
}
2016-12-23 23:42:27 +01:00
void
2017-01-05 21:40:37 +01:00
awaitStateProcessed ( ) const
2016-12-23 23:42:27 +01:00
{
2023-09-30 23:55:42 +02:00
Lock ( unConst ( this ) ) . wait ( unConst ( * this ) , & DispatcherLoop : : isStateSynched ) ; ///////////////////////TICKET #1051 : support bool-λ and fix the correctness-error in the »convenience shortcut«
////////////////////////TICKET #1057 : const correctness on wait predicate
2017-01-05 23:36:42 +01:00
// wake-up typically by updateState()
2016-12-23 23:42:27 +01:00
}
2016-12-15 05:21:03 +01:00
size_t
size ( ) const
{
2016-12-25 22:26:16 +01:00
Lock sync ( this ) ;
return queue_ . size ( ) ;
2016-12-15 05:21:03 +01:00
}
2017-01-05 20:43:53 +01:00
/* === CommandDispatch interface === */
2016-12-15 06:21:59 +01:00
void
2017-04-16 16:16:26 +02:00
enqueue ( Command & & cmd ) override
2016-12-15 06:21:59 +01:00
{
Lock sync ( this ) ;
2017-04-16 16:16:26 +02:00
queue_ . feed ( move ( cmd ) ) ;
2017-01-05 21:40:37 +01:00
sync . notifyAll ( ) ;
2016-12-15 06:21:59 +01:00
}
2016-12-16 23:11:19 +01:00
void
2017-01-05 20:43:53 +01:00
clear ( ) override
2016-12-16 23:11:19 +01:00
{
2017-01-05 20:43:53 +01:00
Lock sync ( this ) ;
queue_ . clear ( ) ;
2017-01-05 21:40:37 +01:00
sync . notifyAll ( ) ;
2016-12-16 23:11:19 +01:00
}
2016-12-13 04:34:28 +01:00
private :
2016-12-22 04:04:41 +01:00
/**
2017-01-05 20:43:53 +01:00
* any operation running in the Session thread is
* started from here . When this loop terminates ,
* the » session subsystem « shuts down .
2016-12-22 04:04:41 +01:00
*/
2016-12-13 04:34:28 +01:00
void
2017-01-05 20:43:53 +01:00
runSessionThread ( Subsys : : SigTerm notifyEnd )
2016-12-13 04:34:28 +01:00
{
2016-12-13 04:45:00 +01:00
string errorMsg ;
2023-09-30 03:12:55 +02:00
init_ . sync ( ) ;
2016-12-13 04:45:00 +01:00
try
{
2016-12-15 22:15:20 +01:00
while ( looper_ . shallLoop ( ) )
{
awaitAction ( ) ;
2016-12-22 21:36:03 +01:00
if ( looper_ . isDying ( ) )
break ;
2016-12-21 03:15:36 +01:00
if ( looper_ . runBuild ( ) )
2016-12-15 22:15:20 +01:00
startBuilder ( ) ;
else
2018-11-23 21:19:21 +01:00
if ( looper_ . isWorking ( ) )
processCommands ( ) ;
2016-12-22 21:36:03 +01:00
updateState ( ) ;
2016-12-15 22:15:20 +01:00
}
2016-12-13 04:45:00 +01:00
}
2018-10-01 03:49:54 +02:00
catch ( std : : exception & problem )
{ // could also be lumiera::Error
2016-12-13 04:45:00 +01:00
errorMsg = problem . what ( ) ;
lumiera_error ( ) ; // clear error flag
}
catch ( . . . )
{
errorMsg = string { lumiera_error ( ) } ;
}
2017-01-05 20:43:53 +01:00
// leave the Session thread...
// send notification of subsystem shutdown
notifyEnd ( & errorMsg ) ;
2016-12-13 04:34:28 +01:00
}
2016-12-15 22:15:20 +01:00
void
2016-12-22 21:36:03 +01:00
awaitAction ( ) ///< at begin of loop body...
2016-12-15 22:15:20 +01:00
{
2016-12-16 19:21:06 +01:00
Lock ( this ) . wait ( looper_ , & Looper : : requireAction ,
2016-12-15 22:15:20 +01:00
looper_ . getTimeout ( ) ) ;
}
2016-12-22 21:36:03 +01:00
void
updateState ( ) ///< at end of loop body...
{
looper_ . markStateProcessed ( ) ;
2017-01-05 23:36:42 +01:00
if ( looper_ . isDisabled ( ) ) // otherwise wake-up would not be safe
2016-12-22 21:36:03 +01:00
Lock ( this ) . notifyAll ( ) ;
}
2016-12-16 23:11:19 +01:00
bool
2018-11-23 21:19:21 +01:00
isStateSynched ( )
2016-12-16 23:11:19 +01:00
{
2023-09-30 03:12:55 +02:00
if ( thread_ . invokedWithinThread ( ) )
2016-12-16 23:11:19 +01:00
throw error : : Fatal ( " Possible Deadlock. "
" Attempt to synchronise to a command processing check point "
" from within the (single) session thread. "
, error : : LUMIERA_ERROR_LIFECYCLE ) ;
2016-12-21 03:15:36 +01:00
return not looper_ . hasPendingChanges ( ) ;
2016-12-16 23:11:19 +01:00
}
2016-12-15 22:15:20 +01:00
void
processCommands ( )
{
2017-01-05 20:43:53 +01:00
Command cmd ;
{
Lock sync ( this ) ;
if ( not queue_ . empty ( ) )
cmd = queue_ . pop ( ) ;
}
if ( cmd )
{
2018-08-04 18:45:58 +02:00
INFO ( command , " +++ dispatch %s " , util : : cStr ( cmd ) ) ; ///////////////////////////////TICKET #211 actually use a command logging and execution strategy here
2017-01-11 06:09:34 +01:00
//////////////////////////////////////////////////////TODO : magic to invoke commands from unit tests
2017-03-31 18:32:42 +02:00
if ( util : : startsWith ( string ( cmd . getID ( ) ) , " test " ) )
2017-01-11 06:09:34 +01:00
{
INFO ( command , " +++ -------->>> bang! " ) ;
2018-10-01 03:49:54 +02:00
auto resultState = cmd ( ) ;
resultState . maybeThrow ( ) ;
2017-01-11 06:09:34 +01:00
}
//////////////////////////////////////////////////////TODO : magic to invoke commands from unit tests
2017-01-05 20:43:53 +01:00
}
2016-12-15 22:15:20 +01:00
}
void
startBuilder ( )
{
2018-11-23 21:19:21 +01:00
INFO ( builder , " +++ start the Steam-Builder... " ) ;
2016-12-15 22:15:20 +01:00
}
2016-12-13 04:34:28 +01:00
} ;
2009-09-29 04:47:09 +02:00
2016-12-15 22:15:20 +01:00
2017-01-05 23:36:42 +01:00
2009-09-29 04:47:09 +02:00
/** storage for Singleton access */
2018-11-23 21:29:54 +01:00
lib : : Depend < SteamDispatcher > SteamDispatcher : : instance ;
2009-09-29 04:47:09 +02:00
2018-11-23 21:29:54 +01:00
/* ======== SteamDispatcher implementation ======== */
2016-12-13 04:34:28 +01:00
2018-11-23 21:29:54 +01:00
SteamDispatcher : : SteamDispatcher ( ) { }
SteamDispatcher : : ~ SteamDispatcher ( ) { }
2018-03-30 23:55:42 +02:00
2018-11-23 21:29:54 +01:00
/** starting the SteamDispatcher means to start the session subsystem.
2017-01-04 01:44:35 +01:00
* @ return ` false ` when _starting_ failed since it is already running . . .
* @ remark this function implements the start operation for the » session subsystem « .
* More specifically , this operation starts a new thread to perform the
* _session loop , _ which means to perform commands and trigger the builder .
* It might block temporarily for synchronisation with this new thread and
* while opening the SessionCommand facade .
*/
2016-12-13 04:34:28 +01:00
bool
2018-11-23 21:29:54 +01:00
SteamDispatcher : : start ( Subsys : : SigTerm termNotification )
2016-12-13 04:34:28 +01:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-13 04:34:28 +01:00
if ( runningLoop_ ) return false ;
runningLoop_ . reset (
new DispatcherLoop (
[ = ] ( string * problemMessage )
{
2018-11-23 21:29:54 +01:00
SteamDispatcher : : endRunningLoopState ( ) ;
2016-12-13 04:34:28 +01:00
termNotification ( problemMessage ) ;
} ) ) ;
2016-12-14 04:57:08 +01:00
if ( active_ )
runningLoop_ - > activateCommandProecssing ( ) ;
2016-12-13 04:34:28 +01:00
return true ;
}
2017-01-04 01:44:35 +01:00
/** whether the »session subsystem« is operational.
* @ return ` true ` if the session loop thread has been fully
* started and is not ( yet ) completely terminated .
*/
2016-12-13 04:34:28 +01:00
bool
2018-11-23 21:29:54 +01:00
SteamDispatcher : : isRunning ( )
2016-12-13 04:34:28 +01:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-13 04:34:28 +01:00
return bool ( runningLoop_ ) ;
}
2016-12-15 06:21:59 +01:00
/** signal to the loop thread that it needs to terminate.
2017-01-05 03:38:46 +01:00
* @ note the immediate consequence is to close SessionCommandService
2016-12-15 06:21:59 +01:00
*/
2016-12-13 04:34:28 +01:00
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : requestStop ( ) noexcept
2017-01-05 03:38:46 +01:00
{
try {
Lock sync ( this ) ;
if ( runningLoop_ )
runningLoop_ - > requestStop ( ) ;
}
ERROR_LOG_AND_IGNORE ( command , " Request for Session Loop Thread to terminate " ) ;
}
/** @internal clean-up when leaving the session loop thread.
* This function is hooked up in to the termination callback ,
* and is in fact the only one to delete the loop PImpl . We
2018-11-23 21:29:54 +01:00
* take the ( outer ) lock on SteamDispatcher to ensure no one
2017-01-05 03:38:46 +01:00
* commits anything to the DispatcherLoop object while being
* deleted . The call itself , while technically originating
* from within DispatcherLoop : : runSessionThread ( ) , relies
* solely on stack based context data and is a tail call .
*/
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : endRunningLoopState ( )
2016-12-13 04:34:28 +01:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-15 06:21:59 +01:00
if ( runningLoop_ )
2017-01-05 03:38:46 +01:00
runningLoop_ . reset ( ) ; // delete DispatcherLoop object
else
WARN ( command , " clean-up of DispatcherLoop invoked, "
2018-11-23 21:29:54 +01:00
" while SteamDispatcher is not marked as 'running'. "
2017-01-05 03:38:46 +01:00
" Likely an error in lifecycle logic, as the only one "
" intended to delete this object is the loop thread itself. " ) ;
2016-12-13 04:34:28 +01:00
}
2016-12-14 04:57:08 +01:00
/** activate processing of enqueued session commands.
* @ remarks command processing serves as public external interface
* to the session . This call is used by the session lifecycle ( SessManagerImpl )
* when the session is brought up ; any other invocation runs danger to mess up
* the session lifecycle state and process commands on a deconfigured session .
* In case the dispatcher loop is not actually running , the activation state
* is stored and applied accordingly later , when the loop is fired up .
*/
2009-09-29 04:47:09 +02:00
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : activate ( )
2009-09-29 04:47:09 +02:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-14 04:57:08 +01:00
active_ = true ;
if ( runningLoop_ )
runningLoop_ - > activateCommandProecssing ( ) ;
2009-09-29 04:47:09 +02:00
}
2017-01-05 23:36:42 +01:00
/** halt further processing of session commands
* @ note the processing itself runs in a separate thread , thus any currently
* ongoing command or builder execution will be completed prior to this setting
* to take effect . If the intention is to halt processing because the session is
* about to dismantled , it is mandatory to awaitDeactivation ( )
*/
2009-09-29 04:47:09 +02:00
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : deactivate ( )
2009-09-29 04:47:09 +02:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-14 04:57:08 +01:00
active_ = false ;
if ( runningLoop_ )
runningLoop_ - > deactivateCommandProecssing ( ) ;
2009-09-29 04:47:09 +02:00
}
2016-12-16 23:11:19 +01:00
/** block until the dispatcher has actually reached disabled state.
* @ warning beware of invoking this function from within the session thread ,
* since the waiting relies on the very lock also used to coordinate
* command processing and builder runs within that thread .
* @ throw error : : Fatal when a deadlock due to such a recursive call can be detected
*/
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : awaitDeactivation ( )
2016-12-16 23:11:19 +01:00
{
Lock sync ( this ) ;
if ( runningLoop_ )
2016-12-22 21:36:03 +01:00
runningLoop_ - > awaitStateProcessed ( ) ;
2016-12-16 23:11:19 +01:00
}
2009-09-29 04:47:09 +02:00
2017-01-05 03:38:46 +01:00
/** discard any commands waiting in the dispatcher queue */
2009-09-29 04:47:09 +02:00
void
2018-11-23 21:29:54 +01:00
SteamDispatcher : : clear ( )
2009-09-29 04:47:09 +02:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-14 04:57:08 +01:00
if ( not empty ( ) )
2016-12-15 05:21:03 +01:00
{
WARN ( command , " DISCARDING pending Session commands. " ) ;
REQUIRE ( runningLoop_ ) ;
runningLoop_ - > clear ( ) ;
}
2009-09-29 04:47:09 +02:00
}
bool
2018-11-23 21:29:54 +01:00
SteamDispatcher : : empty ( ) const
2009-09-29 04:47:09 +02:00
{
2016-12-14 04:18:58 +01:00
Lock sync ( this ) ;
2016-12-15 05:21:03 +01:00
return not runningLoop_
or 0 = = runningLoop_ - > size ( ) ;
2009-09-29 04:47:09 +02:00
}
2009-06-08 04:46:07 +02:00
2018-11-15 23:55:13 +01:00
} } // namespace steam::control