Error passing function in signal( ... )

D

Dudebot

Hi Gurus, I'm porting some C code into a C++ environment. I have
working signal code in C:

#includes for signal...

static void exit_gracefully()
{
*control = STOP|TWSIEN; // send stop signal
exit( 0 );
}

int main( int argc, char **argv )
{
....
signal( SIGTERM, exit_gracefully );

However, when I try to port it into a class, e.g.

class ADC {
public:
....
void sample(); // sample ADC

private:
volatile unsigned int *control;
void exit_gracefully();
};

void ADC::exit_gracefully()
{
*control = STOP|TWSIEN; // send stop signal
exit( 0 );
}

void ADC::sample()
{
....
signal( SIGTERM, exit_gracefully );

I get these compilation errors:

error: argument of type `void (ADC::)()' does not match `void
(*)(int)'

I can't pull exit_gracefully() out of the class, as it needs to access
the private member control.

I tried casting the function in the signal call
signal( SIGTERM, void (*)(int) exit_gracefully );

But I'm getting
error: parse error before `)' token

I tried all sorts of typedef conconctions a la
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5,
but can't get anything to help.

Any ideas?

Many TIA,
Craig
 
P

Pavel Borzenkov

Hi Gurus, I'm porting some C code into a C++ environment. I have
working signal code in C:

#includes for signal...

static void exit_gracefully()
{
*control = STOP|TWSIEN; // send stop signal
exit( 0 );
}

int main( int argc, char **argv )
{
...
signal( SIGTERM, exit_gracefully );

However, when I try to port it into a class, e.g.

class ADC {
public:
...
void sample(); // sample ADC

private:
volatile unsigned int *control;
void exit_gracefully();
};

void ADC::exit_gracefully()
{
*control = STOP|TWSIEN; // send stop signal
exit( 0 );
}

void ADC::sample()
{
...
signal( SIGTERM, exit_gracefully );

I get these compilation errors:

error: argument of type `void (ADC::)()' does not match `void
(*)(int)'

Yes. They have different types.
I can't pull exit_gracefully() out of the class, as it needs to access
the private member control.

You could implement get/set methods for this variable.
Another way is to declare the exit_gracefully function as static,
so its type will be "void (*)(int)"
I tried casting the function in the signal call
signal( SIGTERM, void (*)(int) exit_gracefully );

But I'm getting
error: parse error before `)' token

I tried all sorts of typedef conconctions a la
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5,
but can't get anything to help.

You used the wrong link. See point 33.2 in the same FAQ.
 
I

Ian Collins

Hi Gurus, I'm porting some C code into a C++ environment. I have
working signal code in C:

I get these compilation errors:

error: argument of type `void (ADC::)()' does not match `void
(*)(int)'

That's correct, the function signatures don't match.
I can't pull exit_gracefully() out of the class, as it needs to access
the private member control.

Then declare it extern "C" and make it a friend of the class.
 
D

Dudebot

Whoa. This seems like choosing between two bad design options, almost
a philosophical question.

Pavel points me to making a wrapper in
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2,
where the number of caveats is too numerous to count ;)

Ian tells me to make it extern... meaning, try to match the objects
perfectly in the compile, and hope for the best.

Are these really the only two good ways to proceed?

(Thanks, Pavel and Ian!)

Craig
 
I

Ian Collins

Whoa. This seems like choosing between two bad design options, almost
a philosophical question.

Pavel points me to making a wrapper in
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2,
where the number of caveats is too numerous to count ;)

Ian tells me to make it extern... meaning, try to match the objects
perfectly in the compile, and hope for the best.

Hope for the best?
Are these really the only two good ways to proceed?

Well your options are limited by the C interface you are working with.
You simply can't pass a C++ member function (the signature is wrong)
some compilers will let you get away with a static member function , but
the linkage is still wrong.

The handler function signature means neither a static member or a friend
function can be passed a pointer to a class instance. Using the int
parameter to pass some form of index might be your only option.
 
J

Jorgen Grahn

Hi Gurus, I'm porting some C code into a C++ environment. I have
working signal code in C:

#includes for signal...

static void exit_gracefully()
{
*control = STOP|TWSIEN; // send stop signal
exit( 0 );
}

That's not really a "graceful" exit in C++ -- your destructors won't
run. May or may not matter to your application, of course ...

The simple workaround is to throw an exception instead and catch it
in main().

/Jorgen
 
R

Richard Kettlewell

Jorgen Grahn said:
Dudebot wrote:

That's not really a "graceful" exit in C++ -- your destructors won't
run. May or may not matter to your application, of course ...

Destructors of static-duration objects are called by exit(). BUT they
are almost certainly not safe to run in the context of a signal
handler (almost nothing is).

(For that matter C99 doesn't even allow exit() - only _Exit().)
The simple workaround is to throw an exception instead and catch it
in main().

Throwing an exception from a signal handler sounds like a very bad plan
indeed.
 
J

James Kanze

On 12/30/10 12:48 PM, Dudebot wrote:
Hope for the best?
Well your options are limited by the C interface you are working with.
You simply can't pass a C++ member function (the signature is wrong)
some compilers will let you get away with a static member function , but
the linkage is still wrong.
The handler function signature means neither a static member or a friend
function can be passed a pointer to a class instance. Using the int
parameter to pass some form of index might be your only option.

It's not really an option either; you're very, very limited with
regards to what you can do in a signal handler: you *can't* call
exit (which he apparently wants to do), you can't even access
anything C++. According to the C standard, all you can do is
write (but not read) to a variable with type sig_atomic_t.
Posix (and presumably Windows) allows a little bit more, but
nothing which involves C++: you can't do stream IO (FILE* or
iostream), you can't call a destructor, and you can't throw an
exception. (You can call _exit or abort, but this won't flush
any stream buffers.)

More generally, you probably don't want to, at least if the goal
is to trigger a clean shutdown. You normally can't start
a clean shutdown at just anytime, and signals arrive
asynchronously. The usual solution depends on the application:
for anything multithreaded under Unix, you can create a special
signal handler thread; signals will generate an event which
unblocks the thread, and the thread can start the clean shutdown
(running as a normal thread, and not as a signal handler). For
single threaded processes, the usual solution is just to have
a global sig_atomic_t initialized to zero, set it to one in the
signal handler, and poll it at appropriate moments.
 
J

Jorgen Grahn

Destructors of static-duration objects are called by exit().

Ok, but the other ones (the vast majority of all objects) are not
destroyed properly.
BUT they
are almost certainly not safe to run in the context of a signal
handler (almost nothing is).

(For that matter C99 doesn't even allow exit() - only _Exit().)

Sorry, didn't spot that he used actual signals. The comment about
"send stop signal" in the actual signal handler confused me -- I
thought he just used the word "signal" for his own purposes.
Throwing an exception from a signal handler sounds like a very bad plan
indeed.

Agreed.

/Jorgen
 
D

Dudebot

More generally, you probably don't want to, at least if the goal
is to trigger a clean shutdown.  You normally can't start
a clean shutdown at just anytime, and signals arrive
asynchronously.  The usual solution depends on the application:
for anything multithreaded under Unix, you can create a special
signal handler thread; signals will generate an event which
unblocks the thread, and the thread can start the clean shutdown
(running as a normal thread, and not as a signal handler).  For
single threaded processes, the usual solution is just to have
a global sig_atomic_t initialized to zero, set it to one in the
signal handler, and poll it at appropriate moments.

Wow, I learned a lot from this thread--many thanks, all. James, can
you point me to how to create the signal handler thread that you
describe? I think that I get it in principle, but am having a hard
time imagining how to actually do it.

Again, many thanks,
Craig
 
I

Ian Collins

Wow, I learned a lot from this thread--many thanks, all. James, can
you point me to how to create the signal handler thread that you
describe? I think that I get it in principle, but am having a hard
time imagining how to actually do it.

This is drifting into the realm of comp.programming.threads, but it's
really quite simple. You just create a thread that blocks on sigwait()
and mask out signals to the other threads. The Solaris man page has an
example:

http://docs.sun.com/app/docs/doc/816-5167/sigwait-2?l=en&n=1&a=view
 
J

James Kanze

This is drifting into the realm of comp.programming.threads, but it's
really quite simple. You just create a thread that blocks on sigwait()
and mask out signals to the other threads. The Solaris man page has an
example:

And the example only uses Posix functionality---no Solaris
extensions---so it should port easily to most other Linux
platforms. (Not that I can easily verify it at the moment.)
 

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

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top