Assigning a member function to signal callback function pointer

R

Ramesh

Hello,

I am writing an application in linux using timer_create API to create
timers in my application, I have registered a call back routine which
would be called when the timer timesout. I get the following error:

-------

test.cpp: In member function 'unsigned long
testMgr::addConfigChangeTimer(unsigned long)':
test.cpp:125: error: argument of type 'void (testMgr::)(sigval_t)'
does not match 'void (*)(sigval_t)'

------

The compiler expects a function returning void and taking a sigval_t
as argument, in my case the only difference is that the linkage is C++
style and its a member function.

Is there a way I can assign a member function to the notify_function
pointer?

Thanks
/R



Here is the code snippet:

---

// Actual point of assignment of the callback function to the signal
handler

unsigned long testMgr::addConfigChangeTimer(unsigned long interval) {

timer_t id = 0;
int count = 0;
struct sigevent sig;
struct itimerspec timerspec;

memset(&timerspec, 0, sizeof(struct itimerspec));
memset(&sig, 0, sizeof(struct sigevent));

sig.sigev_notify = SIGEV_THREAD;
sig.sigev_notify_function = ConfigChangeHandler;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sig.sigev_value.sival_ptr = (void*)&count

-------

// Actual function


void testMgr::ConfigChangeHandler(sigval_t value) {

ACE_Guard<ACE_Thread_Mutex> guard(tMutex);

if (ConfigChange == TRUE) {
Notifythreads();
ConfigChange = FALSE;
}
trace("Config change timeout process completed");
}

----

// Class definition

class testMgr {

private:

timestamp ChangeTime;
BOOL ConfigChange;
ACE_Thread_Mutex tMutex;

public:

testMgr();
~testMgr();
UINT32 addConfigChangeTimer(UINT32);
void entConfigChangeHandler(sigval_t );
};
 
J

jason.cipriani

Hello,

I am writing an application in linux using timer_create API to create
timers in my application, I have registered a call back routine which
would be called when the timer timesout. I get the following error:

-------

test.cpp: In member function 'unsigned long
testMgr::addConfigChangeTimer(unsigned long)':
test.cpp:125: error: argument of type 'void (testMgr::)(sigval_t)'
does not match 'void (*)(sigval_t)'

------

The compiler expects a function returning void and taking a sigval_t
as argument, in my case the only difference is that the linkage is C++
style and its a member function.

Is there a way I can assign a member function to the notify_function
pointer?

Thanks
/R

Here is the code snippet:

---

// Actual point of assignment of the callback function to the signal
handler

unsigned long testMgr::addConfigChangeTimer(unsigned long interval) {

    timer_t id                  = 0;
    int count                   = 0;
    struct sigevent sig;
    struct itimerspec timerspec;

    memset(&timerspec, 0, sizeof(struct itimerspec));
    memset(&sig, 0, sizeof(struct sigevent));

    sig.sigev_notify            = SIGEV_THREAD;
    sig.sigev_notify_function   = ConfigChangeHandler;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    sig.sigev_value.sival_ptr   = (void*)&count

Do you actually mean to pass the address of the local variable count
to an asynchronous callback function here?

Anyways, like Sam said you can't pass a pointer to a member function
as a callback and expect it to be called on the appropriate instance
of the object. Pointer-to-members do exist, and you can use them but
only if you also supply an instance of a class. The compiler error you
received is because you attempted to pass a pointer to a non-static
member function but it was expecting a pointer to a static/non-member
function (the two have different types).

Instead, pass your 'this' pointer through sig.sigev_value.sival_ptr,
and make your callback a static function. Then your callback can
either do what it needs to do or pass control off to a non-static
member function appropriately, e.g.:


class testMgr {
public:
unsigned long addConfigChangeTimer (unsigned long);
private:
void ConfigChangeHandler ();
static void StaticConfigChangeHandler (sigval_t value);
};


unsigned long testMgr::addConfigChangeTimer (unsigned long) {
...
sig.sigev_notify_function = StaticConfigChangeHandler;
sig.sigev_value.sival_ptr = (void *)this;
...
}


void testMgr::StaticConfigChangeHandler (sigval_t value) {
// pass control to member function.
assert(value.sival_ptr);
((testMgr *)value.sival_ptr)->ConfigChangeHandler();
}


void testMgr::ConfigChangeHandler () {
// do stuff.
...
}


If you want to pass additional context data to ConfigChangeHandler
then you'll have to pack stuff in to some kind of structure, e.g.:

struct ConfigChangeHandlerParams {
ConfigChangeHandler *inst;
int *pcount;
};


void testMgr::StaticConfigChangeHandler (sigval_t value) {
// for example, passing pcount:
assert(value.sival_ptr);
ConfigChangeHandlerParams *p = (ConfigChangeHandlerParams *)
value.sival_ptr;
p->inst->ConfigChangeHandler(p->pcount);
}


Managing ConfigChangeHandlerParams structs in an exception-safe way is
left as an exercise.

HTH,
Jason
 
R

red floyd

Ramesh said:
Hello,

I am writing an application in linux using timer_create API to create
timers in my application, I have registered a call back routine which
would be called when the timer timesout. I get the following error:

-------

test.cpp: In member function 'unsigned long
testMgr::addConfigChangeTimer(unsigned long)':
test.cpp:125: error: argument of type 'void (testMgr::)(sigval_t)'
does not match 'void (*)(sigval_t)'

------

The compiler expects a function returning void and taking a sigval_t
as argument, in my case the only difference is that the linkage is C++
style and its a member function.

Is there a way I can assign a member function to the notify_function
pointer?

This is a FAQ. FAQ 33.2 to be precise.

http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
 
I

Ian Collins

Sam said:
Recall that an ordinary class member function has access to member
variables of an individual class instance. You may think that by passing
a pointer to a member function from another member function, as a
callback function, when the callback function gets invoked it will be
invoked for the same class instance, but this is not the case. The
timer_create API doesn't know about any objects, it only takes an
ordinary function pointer. With C++, a function pointer is not enough,
you need a class instance to go with it.

Unless, of course, it's a static class member function that's not
associated with any class instance.
Which still isn't a valid function to pass to a C interface, the linkage
is wrong.
 
J

jason.cipriani

Which still isn't a valid function to pass to a C interface, the linkage
is wrong.

You may mean "calling convention", not "linkage", although in all
compilers that I know of that let you specify the calling convention,
it's part of the type (e.g. __stdcall vs. __cdecl with MSVC).

Passing C++ function pointers to functions with C linkage is not an
issue, the linkage is used by the linker, but passing function
pointers around is not the same as linking object files together.
Linkage doesn't come into play there.

JC
 
I

Ian Collins

You may mean "calling convention", not "linkage", although in all
compilers that I know of that let you specify the calling convention,
it's part of the type (e.g. __stdcall vs. __cdecl with MSVC).
No, I should have said "Linkage specification". Nothing to do with
calling conventions. A static member function does not have extern "C"
linkage.
Passing C++ function pointers to functions with C linkage is not an
issue, the linkage is used by the linker, but passing function
pointers around is not the same as linking object files together.
Linkage doesn't come into play there.
Passing a pointer to a C++ function to a function expecting a pointer to
a C function is an issue, although many compilers will ignore the
difference. Others aren't so lax.
 
J

James Kanze

The standard specifies a means of specifying the calling
convention; it's called a linkage specification.
No, I should have said "Linkage specification". Nothing to do
with calling conventions.

Linkage specification is the C++ syntax for specifying the
calling conventions: "C++", "C", "Fortran", etc. ("C++" and "C"
are required; any others are implementation defined.)
A static member function does not have extern "C" linkage.

More precisely, "A C language linkage is ignored for the names
of class members and the member function type of class member
functions."
Passing a pointer to a C++ function to a function expecting a
pointer to a C function is an issue, although many compilers
will ignore the difference. Others aren't so lax.

The linkage is part of the type. Using the address of a
function with C++ linkage to initialize a pointer to a function
with C linkage is a diagnosable error; a C++ compiler is
required to emit a diagnostic. Some compilers have bugs,
however, and don't. (And why Microsoft decided to invent a
completely different mechanism, when the standard already
defined one, I don't know. Logically, instead of new keywords,
I would have expected ``extern "stdcall"'', etc. Not that it
makes much difference in practice.)
 
R

Ramesh

The standard specifies a means of specifying the calling
convention; it's called a linkage specification.


Linkage specification is the C++ syntax for specifying the
calling conventions: "C++", "C", "Fortran", etc.  ("C++" and "C"
are required; any others are implementation defined.)


More precisely, "A C language linkage is ignored for the names
of class members and the member function type of class member
functions."


The linkage is part of the type.  Using the address of a
function with C++ linkage to initialize a pointer to a function
with C linkage is a diagnosable error; a C++ compiler is
required to emit a diagnostic.  Some compilers have bugs,
however, and don't.  (And why Microsoft decided to invent a
completely different mechanism, when the standard already
defined one, I don't know.  Logically, instead of new keywords,
I would have expected ``extern "stdcall"'', etc.  Not that it
makes much difference in practice.)

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

Thanks a bunch.

Cheers
/R
 
R

Rolf Magnus

James said:
The standard specifies a means of specifying the calling
convention; it's called a linkage specification.


Linkage specification is the C++ syntax for specifying the
calling conventions: "C++", "C", "Fortran", etc. ("C++" and "C"
are required; any others are implementation defined.)

Well, "linkage" contains everything that is involved in being able to call
functions defined in the other language. That includes calling conventions as
well as name mangling.
The linkage is part of the type. Using the address of a
function with C++ linkage to initialize a pointer to a function
with C linkage is a diagnosable error; a C++ compiler is
required to emit a diagnostic. Some compilers have bugs,
however, and don't. (And why Microsoft decided to invent a
completely different mechanism, when the standard already
defined one, I don't know. Logically, instead of new keywords,
I would have expected ``extern "stdcall"'', etc. Not that it
makes much difference in practice.)

My guess is that this is simply because that C++ feature doesn't exist in C
and because the Microsoft variant is older than the C++ mechanism.
 
J

jason.cipriani

(And why Microsoft decided to invent a
completely different mechanism, when the standard already
defined one, I don't know.  Logically, instead of new keywords,
I would have expected ``extern "stdcall"'', etc.  Not that it
makes much difference in practice.)

This is because it was actually a Microsoft extension to C that made
it into C++ for easier compatibility with the Windows API, which is
all C. Same deal with their SEH stuff (__try, __except, __finally,
etc., which can actually catch hardware exceptions like access
violations as well) -- those are available in MS C++ even though C++
defines an exception handling mechanism, but they were originally
extensions to C.

By the way, just a little bit of trivia, Borland made it even more
annoying by having their __fastcall use different semantics than
Microsoft's __fastcall, and then later introducing __msfastcall (which
means the same thing as __fastcall on MS compilers). That's a pretty
subtle one that can bite you if you're moving between MS and Borland
compilers, which are otherwise extremely similar -- that is, if you're
using __fastcall in the first place.

Jason
 
J

James Kanze

Well, "linkage" contains everything that is involved in being
able to call functions defined in the other language. That
includes calling conventions as well as name mangling.

And anything else that might be needed. I've usually heard
"calling conventions" used for all of it. But of course, that
was before type safe name mangling was used: the "calling
convention" was typically something along the lines of
prefixing a '_' to the name.
My guess is that this is simply because that C++ feature
doesn't exist in C and because the Microsoft variant is older
than the C++ mechanism.

The C++ mechanism dates to well before Microsoft had a C++
compiler, or were even developing one.
 
J

James Kanze

This is because it was actually a Microsoft extension to C
that made it into C++ for easier compatibility with the
Windows API, which is all C.

OK. If it's from C, it's understandable; C doesn't provide a
standard syntax for this. Still, in their place, I'd have
specified the standard syntax to handle it, and just kept the
other for reasons of backward (or C) compatibility.
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top