How to play with C callbacks (signal()) using C++ instance methods.

D

Daniel Koch

Great people,

I've a doubt about POSIX C functions when I'm using with C++.

I need to handle a signal, the signal() from signal.h needs a
callback. This callback need to perform an action inside class.

How can I define this callback as my instance method?

I think the wrong way is to define a pointer to class instance (this)
as global, then I can call public methods of class from this callback
(the callback defined by signal() haven't a void pointer to pass an
instance pointer).

What's the right way to do this?

Thank you,
Daniel Koch
 
M

Maxim Yegorushkin

I've a doubt about POSIX C functions when I'm using with C++.

I need to handle a signal, the signal() from signal.h needs a
callback. This callback need to perform an action inside class.

How can I define this callback as my instance method?

I think the wrong way is to define a pointer to class instance (this)
as global, then I can call public methods of class from this callback
(the callback defined by signal() haven't a void pointer to pass an
instance pointer).

You would need a global object.
What's the right way to do this?

There is a deeper problem: from within a signal handler you can call
only a limited set of functions, see the complete function list
http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#tag_02_04_03.

Popular functions like malloc() (and C++ new), all C stdio (and C++
IOStreams) and all pthread functions are not async-signal safe.

A standard way to deal with signals is the self-pipe trick, where a
signal handler writes a byte to a pipe whose other end is monitored by
select() in the main program. With new Linux kernels you can do
better: http://www.kernel.org/doc/man-pages/online/pages/man2/signalfd.2.html

This way your signals end up being file descriptor events, which you
can redirect easily to member functions.

Another way is to block signals in all threads and spawn a thread
which would wait for signals using sigwait() and handle signals
synchronously in that thread only.
 
J

James Kanze

I've a doubt about POSIX C functions when I'm using with C++.
I need to handle a signal, the signal() from signal.h needs a
callback. This callback need to perform an action inside
class.

You can't do that from a signal handler, at least not reliably.
How can I define this callback as my instance method?

You can't.
I think the wrong way is to define a pointer to class instance
(this) as global, then I can call public methods of class from
this callback (the callback defined by signal() haven't a void
pointer to pass an instance pointer).

Even that's not guaranteed to work. The relevant standards (C,
C++ and Posix) don't even allow you to read a pointer, much less
do anything with it.
What's the right way to do this?

Do what? The usual way of associating complex actions with a
signal under Posix is to use a signal handling thread, using
sigaction to block the signals in all of the other threads, and
sigwait in the signal handling thread. This should all be
described in your books on Unix programming (and since it is so
Unix specific, if you have further questions, you should ask in
a Unix group).
 
D

Daniel Koch

You can't do that from a signal handler, at least not reliably.


You can't.


Even that's not guaranteed to work.  The relevant standards (C,
C++ and Posix) don't even allow you to read a pointer, much less
do anything with it.


Do what?  The usual way of associating complex actions with a
signal under Posix is to use a signal handling thread, using
sigaction to block the signals in all of the other threads, and
sigwait in the signal handling thread.  This should all be
described in your books on Unix programming (and since it is so
Unix specific, if you have further questions, you should ask in
a Unix group).

--
James Kanze (GABI Software)             email:[email protected]
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

I've found Glib::SignalChildWatch.

I'm using gtkmm to show some windows and it is using libsigc++,
now I can use an instance method as signal handlers. :)

Thank you.
Daniel Koch
 
J

Juha Nieminen

Daniel said:
What's the right way to do this?

Other people have written about it not being standard and not
guaranteed to work and whatever, but I myself have used this many times
with C callbacks in unix systems successfully.

Most C callback mechanisms will take some data pointer as parameter,
which they will then pass to the callback function. Simply give a
pointer to the class instance as this data pointer, and as callback
function create a function which will reinterpret-cast that void* to the
class type and call the proper member function.

For example, assume you have some class like:

class A
{
public:
void callback();
};


You want to create an instance of A, and then have the C library
callback end up calling that A::callbackFunction() for that instance.
What you do is that you write a callback function with a signature
expected by that C library, and inside it you just call the object:

void callbackFunction(void* data)
{
A* obj = reinterpret_cast<A*>(data);
obj->callback();
}

Then somewhere you tell the C library to call that function, like:

cLibrarySetupCallbackFunction(callbackFunction, &obj);

where 'obj' is that A instance which you want to be called.

I have had this work like that. It *might* be possible that in some
situation you'll have to surround that callbackFunction with extern "C".

Sure, there might be *some* architectures and compilers where this
won't work, but I have had it working at least with gcc in a Sparc
Solaris as well as a PC Linux system.
 
J

James Kanze

Other people have written about it not being standard and not
guaranteed to work and whatever, but I myself have used this
many times with C callbacks in unix systems successfully.
Most C callback mechanisms will take some data pointer as
parameter, which they will then pass to the callback function.

Did you read his question? He was concerned doing something
from a signal handler. It's not just any callback; signal
handlers run under very special conditions. And of course, they
*don't* take a data pointer which will be passed back to the
handler.

[...]
You want to create an instance of A, and then have the C
library callback end up calling that A::callbackFunction() for
that instance. What you do is that you write a callback
function with a signature expected by that C library, and
inside it you just call the object:
void callbackFunction(void* data)
{
A* obj = reinterpret_cast<A*>(data);
obj->callback();
}
Then somewhere you tell the C library to call that function, like:

cLibrarySetupCallbackFunction(callbackFunction, &obj);
where 'obj' is that A instance which you want to be called.

This is fine for most callbacks, except that you have to declare
callbackFunction ``extern "C"''.
I have had this work like that. It *might* be possible that in
some situation you'll have to surround that callbackFunction
with extern "C".

The "situation" where you'd have to use ``extern "C"'' is
simple: any time the compiler isn't broken.
Sure, there might be *some* architectures and compilers where
this won't work, but I have had it working at least with gcc
in a Sparc Solaris as well as a PC Linux system.

This is a known bug in g++. Sun CC will diagnose an error
without the ``extern "C"''.
 
M

Maxim Yegorushkin

  Other people have written about it not being standard and not
guaranteed to work and whatever, but I myself have used this many times
with C callbacks in unix systems successfully.

  Most C callback mechanisms will take some data pointer as parameter,
which they will then pass to the callback function. Simply give a
pointer to the class instance as this data pointer, and as callback
function create a function which will reinterpret-cast that void* to the
class type and call the proper member function.

static_cast<> is sufficient when casting from void* to T*.
 
M

Maxim Yegorushkin

[]
cLibrarySetupCallbackFunction(callbackFunction, &obj);
where 'obj' is that A instance which you want to be called.

This is fine for most callbacks, except that you have to declare
callbackFunction ``extern "C"''.
I have had this work like that. It *might* be possible that in
some situation you'll have to surround that callbackFunction
with extern "C".

The "situation" where you'd have to use ``extern "C"'' is
simple: any time the compiler isn't broken.
Sure, there might be *some* architectures and compilers where
this won't work, but I have had it working at least with gcc
in a Sparc Solaris as well as a PC Linux system.

This is a known bug in g++.  Sun CC will diagnose an error
without the ``extern "C"''.

C and C++ calling conventions have been the same on Solaris. I don't
think Sun will ever change it because their remaining customers are
not going to be happy.

While formally it might make sense to emit this error, it is
practically useless.
 
J

James Kanze

On Nov 28, 8:32 am, James Kanze <[email protected]> wrote:

[...]
C and C++ calling conventions have been the same on Solaris. I
don't think Sun will ever change it because their remaining
customers are not going to be happy.
While formally it might make sense to emit this error, it is
practically useless.

It's required by the standard. A compiler which doesn't emit
the error isn't conform. The fact that the calling conventions
happen to be the same isn't really relevant; the language allows
them to be different, and considers them different types.
 
M

Maxim Yegorushkin

On Nov 28, 8:32 am, James Kanze <[email protected]> wrote:

    [...]
C and C++ calling conventions have been the same on Solaris. I
don't think Sun will ever change it because their remaining
customers are not going to be happy.
While formally it might make sense to emit this error, it is
practically useless.

It's required by the standard.  A compiler which doesn't emit
the error isn't conform.  The fact that the calling conventions
happen to be the same isn't really relevant; the language allows
them to be different, and considers them different types.

Is there a platform/compiler where they are different?
 
J

James Kanze

On Nov 28, 8:32 am, James Kanze <[email protected]> wrote:
    [...]
C and C++ calling conventions have been the same on
Solaris. I don't think Sun will ever change it because
their remaining customers are not going to be happy.
While formally it might make sense to emit this error, it
is practically useless.
It's required by the standard.  A compiler which doesn't emit
the error isn't conform.  The fact that the calling conventions
happen to be the same isn't really relevant; the language allows
them to be different, and considers them different types.
Is there a platform/compiler where they are different?

There certainly have been; there are very strong reasons for
making them different on an Intel, for example, and they were
different on the first C++ compiler I used. (I'm not too sure
what the situation is with VC++ today; I think it uses some
non-standard means, but the results are the same.)
 
M

Maxim Yegorushkin

On Nov 28, 10:42 am, Maxim Yegorushkin
    [...]
C and C++ calling conventions have been the same on
Solaris. I don't think Sun will ever change it because
their remaining customers are not going to be happy.
While formally it might make sense to emit this error, it
is practically useless.
It's required by the standard.  A compiler which doesn't emit
the error isn't conform.  The fact that the calling conventions
happen to be the same isn't really relevant; the language allows
them to be different, and considers them different types.
Is there a platform/compiler where they are different?

There certainly have been; there are very strong reasons for
making them different on an Intel, for example, and they were
different on the first C++ compiler I used.  (I'm not too sure
what the situation is with VC++ today; I think it uses some
non-standard means, but the results are the same.)

Any present day examples?
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top