ProcDispatcher: integrate queue and finish preliminary implementation draft

TODO: the wakeup / notification on changes still needs to be done consistently
This commit is contained in:
Fischlurch 2016-12-25 22:26:16 +01:00
parent 3010c87008
commit 282829956b
5 changed files with 63 additions and 31 deletions

View file

@ -23,10 +23,11 @@
/** @file command-queue.hpp
** Implementation building block of ProcDispatcher to organise commands.
** This is the actual implementation of the command queue and additionally
** supports some management tasks pertaining to the queue as a whole.
** This is the actual implementation of the command queue to allow for
** strictly sequential dispatch of commands to work on the session.
**
** @todo WIP-WIP as of 12/2016
** @todo as of 12/2016 this is fully functional, but we may want to add
** some further management functions like purging of expired commands
**
** @see CommandQueue_test
** @see proc-dispatcher.hpp
@ -43,26 +44,23 @@
#include "proc/control/command.hpp"
#include "lib/iter-stack.hpp"
//#include "common/subsys.hpp"
//#include "lib/depend.hpp"
#include "lib/format-string.hpp"
#include "lib/util.hpp"
//#include <memory>
//#include <functional>
namespace proc {
namespace control {
// using lib::Symbol;
// using std::bind;
namespace error = lumiera::error;
using util::_Fmt;
using lib::unConst;
/**
* @todo Type-comment
* Implementation of the Session's command queue.
* @see DispatcherLoop
*/
class CommandQueue
: public lib::IterQueue<Command>
@ -73,12 +71,25 @@ namespace control {
{ }
CommandQueue&
feed (Command const& cmd)
{
if (not cmd.canExec())
throw error::Logic(_Fmt("Reject '%s'. Not suitably prepared for invocation: %s")
% cmd.getID() % cmd
, LUMIERA_ERROR_UNBOUND_ARGUMENTS);
lib::IterQueue<Command>::feed(cmd);
return *this;
}
void
clear()
{
this->stateCore().clear();
}
/* == diagnostics == */
size_t
@ -94,8 +105,6 @@ namespace control {
}
};
////////////////TODO 12/16 currently just fleshing out the API....

View file

@ -26,10 +26,16 @@
** This helper encapsulates the loop control logic to separate it from actual
** implementation of timing and waiting (per pthread condition variables).
** It exposes a combined condition (to be used for waiting) plus any further
** controls to manage the operation of the actual queue. The actual tasks to
** be controlled are installed as functors.
**
** @todo WIP-WIP as of 12/2016
** state predicates necessary to manage the state transitions regarding the
** ProcDispatcher implementation:
** - detect working state, based on a closure to detect an non empty CommandQueue
** - handle the disabling and shutdown of the dispatching task
** - detect an idle state to allow the DispatcherLoop to go to sleep
** - detect the need to run the builder after handling a command
** - manage timeout to run the builder with a slight latency
** - manage an extended timeout to enforce builder run eventually.
** - offer a "check point" where all state is balanced, which can be
** used as a synchronisation point to halt the loop.
**
** @see DispatcherLooper_test
** @see proc-dispatcher.hpp

View file

@ -92,12 +92,10 @@
#include "proc/control/session-command-service.hpp"
#include "proc/mobject/session.hpp"
#include "backend/thread-wrapper.hpp"
#include "lib/format-string.hpp"
#include <memory>
using backend::ThreadJoinable;
using util::_Fmt;
using lib::Sync;
using lib::RecursiveLock_Waitable;
using std::unique_ptr;
@ -181,26 +179,23 @@ namespace control {
clear() override
{
Lock sync(this);
UNIMPLEMENTED ("clear the queue");
queue_.clear();
//////////////////////////////////////////TODO notify!!!!
}
void
enqueue (Command cmd) override
{
if (not cmd.canExec())
throw error::Logic(_Fmt("Reject '%s'. Not suitably prepared for invocation: %s")
% cmd.getID() % cmd
, LUMIERA_ERROR_UNBOUND_ARGUMENTS);
UNIMPLEMENTED ("enqueue command");
Lock sync(this);
queue_.feed (cmd);
//////////////////////////////////////////TODO notify!!!!
}
size_t
size() const
{
TODO ("implement command processing queue");
return 0;
Lock sync(this);
return queue_.size();
}
void
@ -217,7 +212,7 @@ namespace control {
awaitStateProcessed()
{
Lock blockWaiting(this, &DispatcherLoop::stateIsSynched);
//////////////////////////////////////////TODO find out who will notify us!!!!
//////////////////////////////////////////TODO eternal sleep.... find out who will wake us!!!!
}
private:

View file

@ -117,11 +117,11 @@ return: 0
END
PLANNED "Dispatcher loop control logic" DispatcherLooper_test <<END
TEST "Dispatcher loop control logic" DispatcherLooper_test <<END
return: 0
END
PLANNED "Dispatcher command queue" CommandQueue_test <<END
TEST "Dispatcher command queue" CommandQueue_test <<END
return: 0
END

View file

@ -100,6 +100,7 @@ namespace test {
run (Arg)
{
verifyBasics();
verifyExecutabilityCheck();
}
@ -128,6 +129,27 @@ namespace test {
CHECK (0 == queue.size());
CHECK (queue.empty());
}
void
verifyExecutabilityCheck()
{
Command com11 = Command(COMMAND_1).newInstance();
Command com12 = Command(COMMAND_1).newInstance();
com11.bind(42);
// NOT binding the second command...
CommandQueue queue;
queue.feed (com11);
CHECK (1 == queue.size());
VERIFY_ERROR (UNBOUND_ARGUMENTS, queue.feed (com12));
CHECK (1 == queue.size());
queue.pop().execSync();
VERIFY_ERROR (UNBOUND_ARGUMENTS, com12.execSync());
}
};