LINUX.ORG.RU

POSIX таймеры


0

1

Доброго времени суток. Мне понадобилось инкапсулировать POSIX таймер в C++ класс. Возникли проблемы с назначением callback. Говорит что нельзя делать метод класса колбэком.

вот текст сообщения компилятора:

g++-4.5 -std=c++0x -lrt main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:69:28: error: argument of type ‘void (timer_handler::)(int, siginfo_t*, void*)’ does not match ‘void (*)(int, siginfo_t*, void*)’

Вот код:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>

#define CLOCKID CLOCK_REALTIME
#define SIG SIGRTMIN

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                       } while (0)

static void print_siginfo(siginfo_t *si)
{
   timer_t *tidp;
   int orr;

   tidp = (void**)&si->si_value.sival_ptr;

   printf("    sival_ptr = %p; ", si->si_value.sival_ptr);
   printf("    *sival_ptr = 0x%lx\n", (long) *tidp);

   orr = timer_getoverrun(*tidp);
   if (orr == -1)
       errExit("timer_getoverrun");
   else
       printf("    overrun count = %d\n", orr);
}
class timer_handler
{
public:
    void handler(int sig, siginfo_t *si, void *uc)
    {
       printf("Object Caught signal %d\n", sig);
       print_siginfo(si);
       signal(sig, SIG_IGN);
    }
};

void handler(int sig, siginfo_t *si, void *uc)
{
   printf("Function Caught signal %d\n", sig);
   print_siginfo(si);
   signal(sig, SIG_IGN);
}

timer_handler hndlr;

int main(int argc, char *argv[])
{
    
   timer_t timerid;
   struct sigevent sev;
   struct itimerspec its;
   long long freq_nanosecs;
   sigset_t mask;
   struct sigaction sa;

   if (argc != 3) {
       fprintf(stderr, "Usage: %s <sleep-secs> <freq-nanosecs>\n",
               argv[0]);
       exit(EXIT_FAILURE);
   }

   /* Establish handler for timer signal */

   printf("Establishing handler for signal %d\n", SIG);
   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = hndlr.handler;
   sigemptyset(&sa.sa_mask);
   if (sigaction(SIG, &sa, NULL) == -1)
       errExit("sigaction");

   /* Block timer signal temporarily */

   printf("Blocking signal %d\n", SIG);
   sigemptyset(&mask);
   sigaddset(&mask, SIG);
   if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
       errExit("sigprocmask");

   /* Create the timer */

   sev.sigev_notify = SIGEV_SIGNAL;
   sev.sigev_signo = SIG;
   sev.sigev_value.sival_ptr = &timerid;
   if (timer_create(CLOCKID, &sev, &timerid) == -1)
       errExit("timer_create");

   printf("timer ID is 0x%lx\n", (long) timerid);

   /* Start the timer */

   freq_nanosecs = atoll(argv[2]);
   its.it_value.tv_sec = freq_nanosecs / 1000000000;
   its.it_value.tv_nsec = freq_nanosecs % 1000000000;
   its.it_interval.tv_sec = its.it_value.tv_sec;
   its.it_interval.tv_nsec = its.it_value.tv_nsec;

   if (timer_settime(timerid, 0, &its, NULL) == -1)
        errExit("timer_settime");

   /* Sleep for a while; meanwhile, the timer may expire
      multiple times */

   printf("Sleeping for %d seconds\n", atoi(argv[1]));
   sleep(atoi(argv[1]));

   /* Unlock the timer signal, so that timer notification
      can be delivered */

   printf("Unblocking signal %d\n", SIG);
   if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
       errExit("sigprocmask");

   exit(EXIT_SUCCESS);
}

Кто нибудь может подсказать что мне делать?

написать обертку вокруг метода класса?

ono ()
Ответ на: комментарий от ono

Тоесть привязать коллбэком обычную функцию а изнутри звать hndlr.handler(...); с параметрами? не хочется. думал можно поадекватнее чтото сделать.

morfius ()
Ответ на: комментарий от morfius

тогда наверняка сработает

sa.sa_sigaction = hndlr::handler;

но это эквивалентно функции handler, ибо никакого внутреннего состояния хранить не получится.

ono ()
Ответ на: комментарий от morfius

В POSIX нет C++ => нельзя в функцию POSIX передать метод класса C++. Можно только функцию C (статичный метод сойдет).

unsigned ★★★ ()
Ответ на: комментарий от unsigned

Кстати, нельзя printf звать из обработчика сигнала.

unsigned ★★★ ()

Кто нибудь может подсказать что мне делать?

Статический метод

abacaba ()
Ответ на: комментарий от unsigned

Мда.... Из-за одного единственного таймера придётся тащить boost..... POSIX зло, а жаль:(

morfius ()
Ответ на: комментарий от morfius

У тебя же hlndr все равно глобальный - обращайся к нему напрямую из обработчика.

unsigned ★★★ ()

Если не тащить буст, то можно:

а) Сделать метод статическим

б) Сделать дружественную функцию-обёртку, которая аргументом принимает указатель на объект класса (скасченный в void *):

Что-то типа:

class my_class {
  friend void *f(void *);
  // ....
};
void *f(void *arg)
{
  my_class *p = static_cast<my_class *>(arg);
  p->my_method();
  // ....
|}
DELIRIUM ☆☆☆☆☆ ()

этот вопрос задается тут раз в месяц, пора уже в faq вносить ...


struct A {
   void do_all()
   {
   }

   static void handler(void * self)
   {
      ((A*)self)->do_all();
   }
};

....
A a;
register_callback(A::handler, &a);

Reset ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Буст тут не поможет. В (б) слишком много писать.

Reset ★★★★★ ()

Спасибо Reset и DILIRIUM. Завтра попробую.

morfius ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.