SIGALRM in a class member?

R

Ron Eggler

Hi there,

I need to provide a heartbeat to a device cyclic after a specified time (~
1second range).
I do have a communication class and will need to use such in order to send
the heartbeat string to the client device.
Now I would have liked to use following functions:
signal( SIGALRM, sendHeartbeat );
alarm(atoi(INITSource::XMLread(inBufstr,"Cyclic").c_str()));
but the problem is signal wouldn't allow me to have a function pointer to a
member method like INITSource::sendHeartbeat. If I need to do it this way I
would end up in crazy static declarations and linker conflicts - I have
gone there already and apparently didn't solve it... So I went back and
came to ask here - any suggestions?

Thanks,
Ron
 
R

Ron Eggler

Ron said:
Hi there,

I need to provide a heartbeat to a device cyclic after a specified time (~
1second range).
I do have a communication class and will need to use such in order to send
the heartbeat string to the client device.
Now I would have liked to use following functions:
signal( SIGALRM, sendHeartbeat );
alarm(atoi(INITSource::XMLread(inBufstr,"Cyclic").c_str()));
but the problem is signal wouldn't allow me to have a function pointer to
a member method like INITSource::sendHeartbeat. If I need to do it this
way I would end up in crazy static declarations and linker conflicts - I
have gone there already and apparently didn't solve it... So I went back
and came to ask here - any suggestions?

Thanks,
Ron

Actually I figured out a way to do it. I don't know if it's a detour tho.
I just declared a C style pointer to my class and copy the pointer after
instancing the class into this pointer so I now have a C-style function
that gets called by SIGALRM and from there I call the method of my class
kinda like this:
signalhandler (int signal)
{
CopyOfInstance->ExecuteHeartbeat(signal);
}
Does this make sense? Is this a good solution or no?
Thanks for hints and tips!

Ron
 
R

Ron Eggler

R said:
You can do this with a forwarding function that is a static member (you
can also do it with a non-member function). Because signal does not
give you a way to attach some caller defined data, you will also need a
static member variable to hold a pointer to the instance of the class
you want to use:

foo.h:
class foo
{
public:
foo()
{
signal(SIGALRM, sighandler_trampoline);
singleton = this;
}

private:
static void sighandler_trampoline(int sig)
{
singleton->sighandler(sig);
}

void sighandler(int sig)
{
// add your logic here
}

static foo *singleton;
};

foo.cpp:
foo *foo::singleton = 0;

samuel
Hey Samuel,

This is kinda what I do -see my other posting except that I copy my instance
like this:
gps = new INITSource(source, 51001, log, gpsDataObj, false);
Glob_INIT_i = dynamic_cast<INITSource*>(gps);

I have to cast it again because gps is from a different type (mother class
of INITSource)
 
J

James Kanze

You can do this with a forwarding function that is a static
member (you can also do it with a non-member function).

Not according to the standard. "All signal handlers shall have C
linkage" (§18.7/5). And "A C language linkage is ignored for the
names of class members and the member function type of class
member functions" (§7.5/4). A compiler is required to diagnose
this error (and some do).
Because signal does not give you a way to attach some caller
defined data, you will also need a static member variable to
hold a pointer to the instance of the class you want to use:

Note, however, that it is implementation defined whether you can
access said variable. Typically, if it is a pointer, you can,
but calling a member function on it, etc., is less sure.

Since you can only deal with one instance this way (and since at
least under Unix, SIGALRM only manages a single timer), the best
solution is to declare a sig_atomic_t with static lifetime, and
test it. (Except that most systems, or at least Unix and
Windows, offer even better facilities for managing time.)
 
J

James Kanze

While you've made a number of important points:

[...]
Note the reference to the C signal handler definition, which states:
"If the signal occurs other than as the result of calling the
abort or raise function, the behavior is undefined if the
signal handler calls any function in the standard library
other than the signal function itself (with a first argument
of the signal number corresponding to the signal that caused
the invocation of the handler) or refers to any object with
static storage duration other than by assigning a value to a
static storage duration variable of type volatile
sig_atomic_t. Furthermore, if such a call to the signal
function results in a SIG-ERR return, the value of errno is
indeterminate."
Then, in a footnote, the C standard adds:
"If any signal is generated by an asynchronous signal handier,
the behavior is undefined."

In other words, according to the C standard, any signal
generated by SIGALRM is undefined behavior. That's true, but if
he's requesting a SIGALRM, he's working under an OS and with a
compiler which supports it, and defines some of the behavior the
C and C++ standards leave undefined. If he's on a Posix
system, what he can and cannot do is defined by the Posix
standard. And while it's still very limited, it is a little bit
more than just setting a sig_atomic_t and calling signal().
Be very, very careful trying to use library functions, file
i/o, memory allocation, or just about anything else inside a
signal handler invoked asynchronously (other than by a call to
raise()). The C++ library, the underlying C library, and
maybe even the operating system can be in a state where there
are severe limits on what they can do.

Yes. He really has to ask in a group specialized for his OS to
find out exactly what he can do. (The usual solution under Unix
is to run a special timer thread, and handle the signal
there---Posix allows a signal to unblock a normal thread, rather
than just invoke a signal handler, and you can then do just
about anything you could normally do in a thread.)
 
R

Ron Eggler

James said:
While you've made a number of important points:

[...]
Note the reference to the C signal handler definition, which states:
"If the signal occurs other than as the result of calling the
abort or raise function, the behavior is undefined if the
signal handler calls any function in the standard library
other than the signal function itself (with a first argument
of the signal number corresponding to the signal that caused
the invocation of the handler) or refers to any object with
static storage duration other than by assigning a value to a
static storage duration variable of type volatile
sig_atomic_t. Furthermore, if such a call to the signal
function results in a SIG-ERR return, the value of errno is
indeterminate."
Then, in a footnote, the C standard adds:
"If any signal is generated by an asynchronous signal handier,
the behavior is undefined."

In other words, according to the C standard, any signal
generated by SIGALRM is undefined behavior.

What does undefined behaviour in this matter mean exactly? It's been raised
properly for me. I don't see the problem as long as I check in the actual
timer function what kind of signal i got it seems to work nicely.
That's true, but if
he's requesting a SIGALRM, he's working under an OS and with a
compiler which supports it, and defines some of the behavior the
C and C++ standards leave undefined. If he's on a Posix
system, what he can and cannot do is defined by the Posix
standard. And while it's still very limited, it is a little bit
more than just setting a sig_atomic_t and calling signal().

I don't need more than what this is offering me.

What do you mean by "be careful"? I believe it could end up in a stack
overflow if the actual timer function takes too much time. Is this what you
are referring to?
Yes. He really has to ask in a group specialized for his OS to
find out exactly what he can do. (The usual solution under Unix
is to run a special timer thread, and handle the signal
there---Posix allows a signal to unblock a normal thread, rather
than just invoke a signal handler, and you can then do just
about anything you could normally do in a thread.)

Alright the software I'm writing here is working on an embedded Linux
platform - not POSIX tho. It's just a customized distribution built on
ulibC.
Why would having an independent thread make more sense than just raising a
timer signal SIGALRM? I don't quite see the problem...

For my application it makes sense just doing it this way I believe -> Trying
to keep memory usage minimal as well as not wasting any CPU ressources
(thread running in idle).

Ron
 
R

Ron Eggler

I also replaced my atoi(string from XML parser) to this:

istringstream buffer(INITSource::XMLread(inBufstr,"Cyclic"));
buffer >> HeartBeatTime;
HeartBeatTime=float(float(HeartBeatTime)/100*90);
alarm(HeartBeatTime);

What do you think to this, is this better? This should work properly as well
and is C++ conform, any other suggestions or hints regarding this
conversion?

Thanks,
Ron
 
J

James Kanze

James said:
While you've made a number of important points:
[...]
Note the reference to the C signal handler definition,
which states:
"If the signal occurs other than as the result of calling the
abort or raise function, the behavior is undefined if the
signal handler calls any function in the standard library
other than the signal function itself (with a first argument
of the signal number corresponding to the signal that caused
the invocation of the handler) or refers to any object with
static storage duration other than by assigning a value to a
static storage duration variable of type volatile
sig_atomic_t. Furthermore, if such a call to the signal
function results in a SIG-ERR return, the value of errno is
indeterminate."
Then, in a footnote, the C standard adds:
"If any signal is generated by an asynchronous signal handier,
the behavior is undefined."
In other words, according to the C standard, any signal
generated by SIGALRM is undefined behavior.
What does undefined behaviour in this matter mean exactly?

That the behavior is undefined. Anything the implementation
does is correct. The implementation can refuse to compile it,
cause a core dump or reformat your hard disk when it is
executes, or ... define it to do something specific.

Posix does define some additional things with regards to
signals, including asynchronous signals. Presumable, so does
any non-Posix system which defined SIGALRM; it wouldn't make
much sense otherwise.
It's been raised properly for me. I don't see the problem as
long as I check in the actual timer function what kind of
signal i got it seems to work nicely.

The fact that you have undefined behavior doesn't mean that it
won't work. In this case, there are two aspects to consider:

-- Posix does define asynchronous signals, and SIGALRM. If
you're on a Posix conformant system (or one that is at least
conformant in this regard: any of the *nix, and I think even
Windows), catching the signal in your handler is defined,
and you have a few more defined options than just writing to
a sig_atomic_t (but not really very many). So it's likely
that that part of your code is defined on your system.

-- Undefined behavior doesn't mean that the code is guaranteed
to fail. According to Posix, for example, it is undefined
behavior to call any of the FILE* functions in a signal
handler. In practice, it's likely to work most of the time;
it all depends on exactly when the signal arrives (with
respect to what other things you're doing).

What you can and cannot do here depends on your system, not on C
or C++. So you really have to take it up in detail in a system
specific newsgroup. Before doing that, however, I would suggest
that you read up on signal handling under Unix. The use of
signal() is NOT recommended; you should be using sigaction()
instead. (And it sounds to me like you actually need threads,
and a dedicated thread to handle the signals. This is the most
common solution under Unix, since it means that you actually
handle the signal in a thread, and not in a signal handler, and
thus have access to literally everything the system offers.)
I don't need more than what this is offering me.

Just setting sig_atomic_t? That won't get you very far.
What do you mean by "be careful"? I believe it could end up in
a stack overflow if the actual timer function takes too much
time. Is this what you are referring to?

No. The fact that you're not allowed to call most functions
from a signal handler. See the Signal Concepts section in the
Posix standard
(http://www.opengroup.org/onlinepubs/009695399/functions/
xsh_chap02_04.html).
Or better yet, get a good, up to date book about Unix
programming (e.g. "Advanced Programming in the UNIX
Environment", by W. Richard Stevens, ISBN 0-201-56317-7).
Handling signals and other asynchronous events is not trivial,
and requires some understanding.
Alright the software I'm writing here is working on an
embedded Linux platform - not POSIX tho.

Close enough in this regard. I'm pretty sure that Linux gives
all of the Posix guarantees with regards to signals. It may
give some more, but I'm not aware of it.
It's just a customized distribution built on ulibC. Why would
having an independent thread make more sense than just raising
a timer signal SIGALRM? I don't quite see the problem...

The problem is that you're trying to respond asynchronously.
Which means that you're interrupting one activity to do
something else, and that you have to be careful using common
state. Except that in many case, you don't see the common
state; it's hidden somewhere in the system routines. (Malloc is
an obvious example; in order to work, malloc needs to maintain
global state concerning what is and is not being used. And
during a call to malloc, there will be moments when that global
state is inconsistent. If your signal handler is called at one
of those times, and calls malloc, the malloc called from the
signal handler will see an inconsistent state, and likely crash,
or do something else disagreeable.)
For my application it makes sense just doing it this way I
believe -> Trying to keep memory usage minimal as well as not
wasting any CPU ressources (thread running in idle).

Well, I've not really understood what you're trying to do. Most
of the time, when I need a keep alive, I'll be waiting on a
socket or a condition. In such cases, I'll just add a timeout
to the wait, and send the keep alive if I return because of the
timeout.
 
J

James Kanze

I also replaced my atoi(string from XML parser) to this:
istringstream buffer(INITSource::XMLread(inBufstr,"Cyclic"));
buffer >> HeartBeatTime;
HeartBeatTime=float(float(HeartBeatTime)/100*90);
alarm(HeartBeatTime);
What do you think to this, is this better?

If it is in a signal handler, it's undefined behavior.
This should work properly as well and is C++ conform, any
other suggestions or hints regarding this conversion?

You can't do anything this complicated in a signal handler
without incurring undefined behavior.

Note that C++ is even trickier with regards to signal handlers,
since Posix makes no guarantees concerning C++. In general, you
can count on being able to do anything you could do from a
signal handler in C, but nothing more. You cannot do *anything*
which uses any of the iostream stuff, or FILE*. You cannot call
any of the functions defined in the C++ standard. Of the
functions defined in the C standard, I think time(), rename(),
signal() and abort() are the only ones allowed (unless I've
missed one).
 

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,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top