Assigning a member function to signal callback function pointer

Discussion in 'C++' started by Ramesh, Dec 25, 2008.

  1. Ramesh

    Ramesh Guest

    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 );
    };
     
    Ramesh, Dec 25, 2008
    #1
    1. Advertisements

  2. 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
     
    jason.cipriani, Dec 25, 2008
    #2
    1. Advertisements

  3. Ramesh

    red floyd Guest

    This is a FAQ. FAQ 33.2 to be precise.

    http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
     
    red floyd, Dec 25, 2008
    #3
  4. Ramesh

    Ian Collins Guest

    Which still isn't a valid function to pass to a C interface, the linkage
    is wrong.
     
    Ian Collins, Dec 25, 2008
    #4
  5. 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
     
    jason.cipriani, Dec 25, 2008
    #5
  6. Ramesh

    Ian Collins Guest

    No, I should have said "Linkage specification". Nothing to do with
    calling conventions. A static member function does not have extern "C"
    linkage.
    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.
     
    Ian Collins, Dec 25, 2008
    #6
  7. Ramesh

    James Kanze Guest

    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, Dec 25, 2008
    #7
  8. Ramesh

    Ramesh Guest

    Thanks a bunch.

    Cheers
    /R
     
    Ramesh, Dec 25, 2008
    #8
  9. Ramesh

    Rolf Magnus Guest

    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.
    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.
     
    Rolf Magnus, Dec 25, 2008
    #9
  10. 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
     
    jason.cipriani, Dec 27, 2008
    #10
  11. Ramesh

    James Kanze Guest

    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.
    The C++ mechanism dates to well before Microsoft had a C++
    compiler, or were even developing one.
     
    James Kanze, Dec 27, 2008
    #11
  12. Ramesh

    James Kanze Guest

    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.
     
    James Kanze, Dec 27, 2008
    #12
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.