Re: Assigning a member function to signal callback function pointer
 
On Dec 24, 7:04 pm, Ramesh <rrame...@gmail.com> wrote:
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
-------
// 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                Confi=
gChange;
                ACE_Thread_Mutex    tMutex;
        public:
                testMgr();
                ~testMgr();
                UINT32          addConfigChange=
Timer(UINT32);
                void            entConfigChan=
geHandler(sigval_t );
};