AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
tocker.cpp
/* T O C K E R
* Module name:
TOCKER
* Function:
A simple DRAMA message sending test program.
* Description:
Finds the program TICKER and sends the TICK message too
it <n> times. It then sends the EXIT message to it and then
exits itself.
<n> is set on the command line. Defaults to 100.
On exit, print stats.
* 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
* @(#) $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>
#include <chrono>
// This thread is used to send the messages. This is a DRAMA2 UFACE thread.
void MyThread(drama::Task *task, unsigned count, bool regtest)
{
// Use this type to maintain clock.
typedef std::chrono::high_resolution_clock::time_point myClock;
try
{
// We must create a ufaceHandler at this point. Only then can
// we send DRAMA messages.
drama::thread::TUface ufaceHandler(task->TaskPtr());
// Find the path to the TICKER program, loading it if needed.
drama::Path ticker(task->TaskPtr(), "TICKER" , "", "./ticker");
ticker.GetPath(&ufaceHandler);
// Grab time now.
myClock initClock = std::chrono::high_resolution_clock::now();
for (unsigned i = 0; i < count ; ++i)
{
ticker.Obey(&ufaceHandler, "TICK");
}
// Determine time since first TICK.
std::chrono::duration<double> duration =
std::chrono::high_resolution_clock::now() - initClock;
ticker.Obey(&ufaceHandler, "EXIT");
if (regtest)
{
// Regression test mode - simple output that we have done.
// Can't output times as they change and mess up regression
// test diffs.
std::cout << "TOCKER:Completed "
<< count
<< " ticks"
<< std::endl;
}
else
{
// Output times - as per DramaDits/tocker.c
std::cout << "TOCKER:Total time for "
<< count
<< " ticks is "
<< std::fixed << std::showpoint
<< std::setw(6)
<< std::setprecision(2)
<< duration.count()
<< "s, Ave Time = "
<< std::setprecision(4)
<< (duration.count()*1000.0/count)
<< "ms"
<< std::endl;
}
}
catch (...)
{
// Ensure the DRAMA loop exits and re-throw the exception.
throw;
}
}
class Tocker : public drama::Task {
private:
std::future<void> _ufaceThreadFuture;
public:
Tocker(unsigned count, bool regtest) : drama::Task("TOCKER") {
/*
* 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.
*/
/*
* Launch the thread.
*/
_ufaceThreadFuture = std::async(std::launch::async, MyThread, this, count, regtest);
}
/*
* Used to wait for the thread started in the constructor to exit.
* Timeout in seconds supplied
*/
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 async thread did.
}
~Tocker() {
}
};
int main(int argc, char *argv[])
{
int count = 0;
bool regtest = false;
bool delay_loop_start = false;
if (argc > 1)
{
// Flag of -regtest says we are running in test mode, don't
// output stuff that may change.
if (strcmp(argv[1], "-regtest") == 0)
regtest = true;
else
count = atoi(argv[1]);
}
if (count < 0)
{
delay_loop_start = true;
regtest = true;
}
if (count <= 0) count = 100;
try
{
// Make this program a DRAMA task named TOCKER
Tocker task(count, regtest);
// Process DRAMA messages.
// If the use specified a negative count, then this is enabled.
// What we are testing is a problem that used to happen if
// the running of RunDrama() occurred after the first message
// was sent. All we really need is to force a context switch
// such that MyThread is invoked.
if (delay_loop_start)
{
fprintf(stderr,"Delaying start of DRAMA loop to check that works\n");
std::this_thread::sleep_for (std::chrono::seconds(1));
}
task.RunDrama();
// Wait for the threads to exit.
task.WaitThreadExit(3);
}
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:428
virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const
Print exception details to a file.
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:168
void Obey(thread::TMessHandler *action, const std::string &name, const sds::Id &argIn=sds::Id::CreateNullItem(), sds::IdPtr *const argOut=nullptr, MessageEventHandler *const eventProcessor=&_simpleEventProcessor)
Sends an obey message to a task and blocks the current thread until the action is complete.
Definition path.hh:1372
void GetPath(thread::TMessHandler *action, thread::TransEvtProcessor *const eventProcessor=&_getPathEventProcessor)
Get a path to a the task.
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
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
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.