Callback high-res timer C++ class

  • Thread starter Dmitri Sologoubenko
  • Start date
D

Dmitri Sologoubenko

Hi, guys!

I need a C++ class (Linux/POSIX/GNU C++), which can be started and stopped,
and calls a virtual callback instance method (e.g. "expired()") when a
given time has elapsed. High resolution means that expire time should be
measured in microseconds, or at least in milliseconds.

I had a look on Gnu C <sys/time.h>'s functions getitimer and setitimer, but
these all use a signal (SIGALRM) to notify expiration, and I don't know the
way to handle this signal from an instance class method.

So, the questions are the following:

1) Is there a way to safely encapsulate a C signal handler in a not-static
C++ class method?
2) Is there any class library that implements this feature?
3) Is there any, other than signal handling, to implement such a timer?

Thanks in advance for your help,

Dmitri S.
 
V

Victor Bazarov

Dmitri said:
[..]
So, the questions are the following:

1) Is there a way to safely encapsulate a C signal handler in a
not-static C++ class method?

What do you mean by "safely encapsulate"? A non-static member function
cannot be used as a C signal handler (and that's in the FAQ, IIRC).
A static member can, but then you still need an instance of the class
to call a non-static member, AFAIUI. If you only have one instance
(a singleton), it should be no big deal, but if you have more than one,
there is no C solution to this C++ problem.
2) Is there any class library that implements this feature?

Which feature? A signal hander?
3) Is there any, other than signal handling, to implement such a
timer?

I would probably start by asking in a Linux/POSIX/GNU C++ newsgroup.

V
 
W

werasm

Victor said:
Dmitri said:
[..]
So, the questions are the following:

1) Is there a way to safely encapsulate a C signal handler in a
not-static C++ class method?

What do you mean by "safely encapsulate"? A non-static member function
cannot be used as a C signal handler (and that's in the FAQ, IIRC).
A static member can, but then you still need an instance of the class
to call a non-static member, AFAIUI. If you only have one instance
(a singleton), it should be no big deal, but if you have more than one,
there is no C solution to this C++ problem.

I realize this is OT in this newsgroup, but to respond to what you've
answered...

In general most API functions (used for signal registration) allows one
to specify the signal handler and arguments that will get passed to the
handler when the signal occurs. If the instance is known at the time of
the signal handler registration, then the pointer of the instance need
only be translated into the call parameters. This in itself is not a
standard exercise :), but often as easy as reinterpret casting the
pointer to an integer value. The translation can be abstracted (using a
virtual cast..., so to speak) if one is required to do this cross
platform. Although usually this type of code is so specific already
that abstraction (trying to make it cross platfor) has no added
benefit. The signal handler then translates the argument/s back to the
pointer. The signal handler may know the pointer type expected. A
typical test to verify whether the translation was correct, would be to
hide and additional this pointer in the class, and compare after
translation.

I'm sure there is. We have implemented similar things for Windows and
VxWorks. Unfortunately our timer is built on a whole callback
(intertask communication) architecture.

We have implemented a timer that fires a callback (cmd pattern style).
The callback is executed in the context of a thread associated with it.
Unfortunately I don't see why you want it to have resolution up to 1
micros. Typically system timers have a resolution of 20 millisecs. If
you are lucky, 1milli. If you want any faster than that, you have to
start doing processor specific things (Posix won't help you there). I
may be wrong though, but that is IME.

Regards,

Werner
 
D

Dmitri Sologoubenko

werasm said:
Victor said:
Dmitri said:
[..]
So, the questions are the following:

1) Is there a way to safely encapsulate a C signal handler in a
not-static C++ class method?

What do you mean by "safely encapsulate"? A non-static member function
cannot be used as a C signal handler (and that's in the FAQ, IIRC).
A static member can, but then you still need an instance of the class
to call a non-static member, AFAIUI. If you only have one instance
(a singleton), it should be no big deal, but if you have more than one,
there is no C solution to this C++ problem.

I realize this is OT in this newsgroup, but to respond to what you've
answered...

In general most API functions (used for signal registration) allows one
to specify the signal handler and arguments that will get passed to the
handler when the signal occurs. If the instance is known at the time of
the signal handler registration, then the pointer of the instance need
only be translated into the call parameters. This in itself is not a
standard exercise :), but often as easy as reinterpret casting the
pointer to an integer value. The translation can be abstracted (using a
virtual cast..., so to speak) if one is required to do this cross
platform. Although usually this type of code is so specific already
that abstraction (trying to make it cross platfor) has no added
benefit. The signal handler then translates the argument/s back to the
pointer. The signal handler may know the pointer type expected. A
typical test to verify whether the translation was correct, would be to
hide and additional this pointer in the class, and compare after
translation.

I'm sure there is. We have implemented similar things for Windows and
VxWorks. Unfortunately our timer is built on a whole callback


(intertask communication) architecture.
We have implemented a timer that fires a callback (cmd pattern style).
The callback is executed in the context of a thread associated with it.
Unfortunately I don't see why you want it to have resolution up to 1
micros. Typically system timers have a resolution of 20 millisecs. If
you are lucky, 1milli. If you want any faster than that, you have to
start doing processor specific things (Posix won't help you there). I
may be wrong though, but that is IME.

Regards,

Werner

I think I have partially solved the problem: see this code:

#include <iostream>
#include <string>
#include <csignal>
#include <list>
#include <map>

using namespace std;

class SignalListener
{
public:
virtual void onSignal(int signal) {}
virtual ~SignalListener();
};

class L: public SignalListener
{
protected:
string name;
public:
L(string n) : name(n) {}
virtual void onSignal(int signal)
{
cout << "L[" << name << "] received SIGNAL[" << signal << "]" << endl;
}
};

class T: public L
{
public:
T(string n) : L(n) {}
virtual void onSignal(int signal)
{
cout << "T[" << name << "] received SIGNAL[" << signal << "]" << endl;
}
};

/****************************************************
* SIGNAL HANDLER CLASS
****************************************************/

class SignalHandler
{
protected:
static bool initialized;
static bool mustExit;
static int exitSignal;

static map<int,sighandler_t> old;
static list<SignalListener*> lst;
static list<int> handled;

static void setIgnore(int sig, bool ignore)
{
if (ignore) {
signal(sig, SIG_IGN);
} else {
signal(sig, broadcast);
}
}

public:
static void init(int *signals, int nsignals, int exit_signal=SIGQUIT)
{
if (!initialized) {
initialized = true;
exitSignal = exit_signal;
if (signals && nsignals) {
for (int i=0; i<nsignals; i++) {
cout << "\tsignals[" << i << "] = [" << signals << "]" << endl;
handled.push_back(signals);
old[signals] = signal(signals, broadcast);
}
}
}
}

static void destroy()
{
if (initialized) {
initialized = false;
for(list<int>::iterator i=handled.begin(); i!=handled.end(); i++ ) {
cout << "\tsignal(" << *i << "," << old[*i] << ")" << endl;
signal(*i, old[*i]);
}
}
}

static void broadcast(int sig)
{
setIgnore(sig, true);
for(list<SignalListener*>::iterator i=lst.begin(); i!=lst.end(); i++)
if (*i) (*i)->onSignal(sig);
if (sig==exitSignal) mustExit = true;
setIgnore(sig, false);
}

static void addListener(SignalListener *l)
{
lst.push_front(l);
}

static void removeListener(SignalListener *l)
{
lst.remove(l);
}

static bool mustQuit()
{
return mustExit;
}

};

bool SignalHandler::initialized = false;
bool SignalHandler::mustExit = false;
int SignalHandler::exitSignal = 0;
list<SignalListener*> SignalHandler::lst;
map<int,sighandler_t> SignalHandler::eek:ld;
list<int> SignalHandler::handled;

SignalListener::~SignalListener()
{
SignalHandler::removeListener(this);
}


int main (int argc, char* argv[])
{
int signals[] = {SIGALRM, SIGQUIT};
SignalHandler::init(signals, 2);

L l1("uno");
L l2("due");
T t1("tiuno");

SignalHandler::addListener(&l1);
SignalHandler::addListener(&l2);
SignalHandler::addListener(&t1);

while (!SignalHandler::mustQuit()) {
sleep(1);
}

SignalHandler::destroy();

exit(0);
}

If you run this and then send via "kill" SIGALRM and SIGQUIT, it works
great.

Another problem: in multi-threaded applications of these classes, have I to
use Mutexes? Is this possible to use Mutexes (posix) to protect static
methods. Will be any side-effect caused by asynchronous (and thread
handling - indipendent) nature of signals?

Thanks a lot.
Dmitri S.
 
W

werasm

Dmitri said:
I think I have partially solved the problem: see this code:
[snip]

My solution would have involved real time signals that allow arguments
to the callback.

I have looked at the code. I will only comment on it from a std C++
perspective. My first comment is that I noticed that lack of
qualification when using components in the std namespace...
Another problem: in multi-threaded applications of these classes, have I to
use Mutexes? Is this possible to use Mutexes (posix) to protect static
methods. Will be any side-effect caused by asynchronous (and thread
handling - indipendent) nature of signals?

Yes it is...

Refer your questions to comp.programming.threads as it bears no
relevance here.

Kind regards,

Werner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top