AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
monitor2.cpp
/* M O N I T O R 2
* Module name:
MONITOR2
* Function:
A simple DRAMA program demonstrating parameter monitors.
* Description:
Finds the program TESTTASK and monitors parameters within it.
This example uses a monitor based on the drama::thread::MonitorByType
class, which provides for methods to be invoked when events on
parameters of given types are received.
* Language:
C++
* Copyright (c) Australian Astronomical Observatory, 2014.
Not to be used for commercial purposes without permission.
No warranty of any form unless subject to a specific agreement.
* Support: Tony Farrell, AAO
* History:
08-May-2014 - TJF - Original version
* @(#) $Id$
*/
static const char *rcsId="@(#) $Id$";
static void *use_rcsId = (0 ? (void *)(&use_rcsId) : (void *) &rcsId);
#include "drama.hh"
#include "drama/path.hh"
#include <iostream>
/*
* Create a class used to implement our monitors. In particular, methods
* we declare here will be invoked when parameter values change. This
* implementation is a sub-class of MonitorByType.
*/
class MyMonitor : public drama::thread::MonitorByType {
// Use the MonitorByType constructors.
using drama::thread::MonitorByType::MonitorByType;
/*
* Each of these override methods in MonitorByType.
* Mark them as "override" to ensure we have the signature correct.
*/
// Invoked when a signed integer parameter is changed.
void ParamChanged(const std::string &name, long value) override;
// Invoked when a string parameter is changed, also for any of
// int/unsigned int/real which we have not overriden, so in this case,
// real/unsigned int cases as well.
void ParamChanged(const std::string &name, const std::string & value) override;
// Invoked when some complex parameter (array of items or structured item)
// is changed.
void ParamChanged(const std::string &name, const drama::sds::IdPtr &value) override;
};
/*
* MyMonitor method implementations.
*
* Invoked when an integer parameter being monitored changed.
*/
void MyMonitor::ParamChanged(const std::string &name, long value)
{
std::cerr << "*** MyMonitor:ParamChanged (int) \""
<< name
<< "\" to \""
<< value
<< "\""
<< std::endl;
}
/*
* Invoked when a string parameter being monitored changed.
* Also invoked for any of int/unsigned/real which we don't explicitly
* support.
*/
void MyMonitor::ParamChanged(
const std::string &name,
const std::string & value)
{
std::cerr << "*** MyMonitor:ParamChanged (string) \""
<< name
<< "\" to \""
<< value
<< "\""
<< std::endl;
}
/*
* Invoked when a complex parameter changes.
*/
void MyMonitor::ParamChanged(
const std::string &name,
const drama::sds::IdPtr &value)
{
std::cerr << "*** MyMonitor:ParamChanged (complex) \""
<< name
<< "\""
<< std::endl;
value->List(std::cerr);
}
/*
* This function is invoked in a thread, to initiate and run the monitor.
*/
void MonitorThread(drama::Task *task)
{
try
{
/*
* We are not part of a DRAMA action, so we need a UFACE handler to
* deal with the messages.
*/
drama::thread::TUface ufaceHandler(task->TaskPtr());
/*
* Set up access to the testtask program.
*/
drama::Path testtask(task->TaskPtr(), "TESTTASK@mynode", "", "./testtask");
/*
* Get path to TESTTASK (loading if required and possible).
*/
testtask.GetPath(&ufaceHandler);
/*
* Create a monitor object, specifying a list of parameters in
* the TESTTASK task to be monitored.
*/
MyMonitor myMonitor(task->TaskPtr(), { "PARAM1" , "PARAM2", "PARAM3",
"PARAM4" , "STRUCT_PARAM" });
try
{
ufaceHandler.MessageUser("About to run monitor");
myMonitor.Run(&testtask, &ufaceHandler);
}
catch (const drama::Exception &e)
{
/*
* If the above threw a DRAMA Run loop exit error, then
* this task was shutdown whilst we were running the monitor.
* In this case, we are not that worried and allow the thread
* to close down without error messages. But for any other
* reason, we re-throw the exception.
*/
if (e.dramaStatus() != DRAMA2__RUN_LOOP_EXIT)
throw e;
}
}
catch (...)
{
/*
* Ensure the DRAMA loop exits and re-throw the exception. The
* exception will be reported by the main program.
*/
throw;
}
/*
* If the thread completes (through it should not unless an exception occurs)
* signal DRAMA to exit.
*/
}
class Monitor : public drama::Task {
private:
std::future<void> _ufaceThreadFuture;
public:
Monitor() : drama::Task("MONITOR2") {
/*
* Our only action is the EXIT action.
*/
/*
* By constructing one of these, we block all signals whilst
* the thread is being created, to avoid race conditions. The
* thread will block signals itself once it starts running. The
* destructor restores the signal mask.
*/
/*
* Start the thread which will do the monitors. This returns a future
* we can use to wait for the thread to exit.
*/
_ufaceThreadFuture = std::async(std::launch::async, MonitorThread, this);
}
/*
* This method will wait for a thread to exit and will throw if the
* monitor thread threw an exception.
*/
void WaitThreadExit(unsigned seconds) {
if (_ufaceThreadFuture.wait_for(std::chrono::seconds(seconds)) !=
std::future_status::ready)
{
DramaTHROW(DRAMA2__THREAD_TIMEOUT,
"UFACE Thread did not complete");
}
_ufaceThreadFuture.get(); // Will throw if thread did.
}
~Monitor() {
}
};
int main()
{
try
{
/*
* Make this program a DRAMA task named MONITOR.
*/
Monitor task;
/*
* Process DRAMA messages.
*/
task.RunDrama();
/*
* Wait for the threads to exit (3 seconds only, timeout causes exception).
*/
task.WaitThreadExit(3);
}
/*
* Deal with any exceptions.
*/
catch (const drama::Exception &e)
{
e.Print();
exit (e.statusAsSysExitCode());
}
catch (const std::exception &e)
{
std::cerr << "std::exception thrown by task.RunDrama"
<< e.what()
<< std::endl;
exit(1);
}
return 0;
}
virtual int statusAsSysExitCode() const
Return a system exit code based on the DRAMA Status.
Definition exception.hh:424
virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const
Print exception details to a file.
virtual StatusType dramaStatus() const
Return the DRAMA Status code associated with the exception.
Definition exception.hh:404
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:164
A Class which provides access to DRAMA's message sending facilities.
Definition path.hh:689
virtual void Add(const std::string &name, MessageHandlerPtr obj, const std::string &descr="")
Add an action to the task.
Definition task.hh:696
std::weak_ptr< Task > TaskPtr()
Returns a weak pointer to the task.
Definition task.hh:975
A class which implements a DRAMA task.
Definition task.hh:441
virtual void ParamChanged(const std::string &name, long value)
Method invoked when the value of a signed integer type parameter has been changed.
A class implementing Monitor which invokes particular methods for parameters of given base types.
Definition threadmonitor.hh:486
Constructing an object of this type will block all blockable UNIX signals in the current thread.
Definition thread.hh:586
A class which allows threads running in a User Interface or similar environments to send DRAMA messag...
Definition threaduface.hh:93
DRAMA 2 main include file.
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:93
std::shared_ptr< Id > IdPtr
A shared pointer for sds::Id items.
Definition sds.hh:3318
void SignalDramaToExit(std::weak_ptr< Task > dramaTask, StatusType exitStatus=STATUS__OK)
Signal to DRAMA that this task should exit.
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1322
Request SimpleExitAction(drama::MessageHandler *messageHandler)
A function which implements a simple exit action.
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:93
DRAMA 2 include file.
DRAMA 2 include file - Threaded monitoring classes.