[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

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

Daniel Koch

11/26/2008 5:01:00 PM

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
54 Answers

Maxim Yegorushkin

11/26/2008 5:31:00 PM

0

On Nov 26, 5:01 pm, Daniel Koch <daniel.k...@gmail.com> wrote:

> 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#ta....

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/signa...

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.

--
Max

James Kanze

11/26/2008 6:24:00 PM

0

On Nov 26, 6:01 pm, Daniel Koch <daniel.k...@gmail.com> wrote:
> 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).

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

Daniel Koch

11/26/2008 7:52:00 PM

0

On 26 nov, 16:24, James Kanze <james.ka...@gmail.com> wrote:
> On Nov 26, 6:01 pm, Daniel Koch <daniel.k...@gmail.com> wrote:
>
> > 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).
>
> --
> James Kanze (GABI Software)             email:james.ka...@gmail.com
> 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

Juha Nieminen

11/27/2008 10:45:00 PM

0

Daniel Koch wrote:
> 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.

James Kanze

11/28/2008 8:32:00 AM

0

On Nov 27, 11:44 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Daniel Koch wrote:
> > 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.

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"''.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

Maxim Yegorushkin

11/28/2008 9:34:00 AM

0

On Nov 27, 10:44 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Daniel Koch wrote:
> > 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.

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

--
Max

Maxim Yegorushkin

11/28/2008 9:42:00 AM

0

On Nov 28, 8:32 am, James Kanze <james.ka...@gmail.com> wrote:
> On Nov 27, 11:44 pm, Juha Nieminen <nos...@thanks.invalid> wrote:

[]

> > 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.

--
Max

James Kanze

11/28/2008 2:26:00 PM

0

On Nov 28, 10:42 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 28, 8:32 am, James Kanze <james.ka...@gmail.com> 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.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

Maxim Yegorushkin

11/28/2008 2:49:00 PM

0

On Nov 28, 2:25 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Nov 28, 10:42 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
> wrote:
>
> > On Nov 28, 8:32 am, James Kanze <james.ka...@gmail.com> 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?

--
Max

James Kanze

11/28/2008 7:26:00 PM

0

On Nov 28, 3:48 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 28, 2:25 pm, James Kanze <james.ka...@gmail.com> wrote:
> > On Nov 28, 10:42 am, Maxim Yegorushkin
> > <maxim.yegorush...@gmail.com> wrote:
> > > On Nov 28, 8:32 am, James Kanze <james.ka...@gmail.com> 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.)

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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