Я работаю с переносом одной из встроенных библиотек микроконтроллеров в linux и написанием обертки python вокруг нее.SIGALRM, интервальные таймеры и проблемы со сном()
Один из моих модулей низкого уровня зависит от обратного вызова, который вызывается каждые 10 мс. Этот обратный вызов подсчитывает таймеры программного обеспечения, каждый из которых имеет свои собственные обратные вызовы. Эти таймеры используются по всей нашей библиотеке, и, хотя они не должны быть на 100% точными, ожидается, что они продолжат тикать и, надеюсь, достигнут точности +/- 10%. Этот модуль имитирует стандартное прерывание таймера в микроконтроллере.
У меня есть существующая реализация с использованием обработчиков setitimer и SIGALRM, которые прекрасно работают. Вот некоторые из моего кода:
void halCounterInit(void)
{
struct sigaction alrm_action;
alrm_action.sa_handler = timerInterrupt;
alrm_action.sa_flags = SA_RESTART;
sigaction(SIGALRM, &alrm_action, NULL);
}
void halCounterEnable(void)
{
mytime.it_interval.tv_sec = 0;
mytime.it_interval.tv_usec = 10000; //10ms
mytime.it_value.tv_sec = 0;
mytime.it_value.tv_usec = 10000; //10ms
setitimer(ITIMER_REAL, &mytime, NULL);
}
void halCounterDisable(void)
{
mytime.it_interval.tv_sec = 0;
mytime.it_interval.tv_usec = 0;
mytime.it_value.tv_sec = 0;
mytime.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &mytime, NULL);
}
void halCounterRegisterInterruptHandler(InterruptHandlerCallback cb, void *params)
{
myInterruptHandler = cb;
myParams = params;
}
void timerInterrupt(int signum)
{
if (myInterruptHandler != NULL)
{
myInterruptHandler(myParams);
}
}
Во время тестирования некоторые из этого кода в сочетании с другим кодом, я заметил, что звонки спать() выгонять рано, когда генерируется сигнал SIGALRM. Я взаимодействую с gevent (на основе libevent) в python, используя ctypes, чтобы создать новый слой над моей библиотекой C. Я обеспокоен тем, что эта проблема SIGALRM затруднит поиск ошибок в python.
Я попытался переписать мой простой счетчик, используя вызов pthread и blocking select(), но кажется, что вызов select() выходит из системы раньше, а мои таймеры становятся ужасно неточными.
- Есть ли способ заставить setitimer генерировать другой сигнал, который я могу уловить, вместо сигальма?
- Есть ли другой способ сделать это без использования сигналов? Я пробовал наноселекцию, выбор и регулярный сон в другом потоке, но это работает не очень хорошо.
Любая помощь приветствуется. В идеале это будет работать как для OSX, так и для Linux, но Linux является единственным жестким требованием.
Edit:
Мой отдельный код нить с помощью выбора() или nanosleep(). Оба являются неточными. Выбирается реализация select. MyTime правильно настроен в функции init. Это функция резьбы:
while (TRUE)
{
pthread_mutex_lock(&Lock);
//we are paused
while(!Running)
{
//we are waiting for a signal to tell us when to start again
pthread_cond_wait(&Cond, &Lock);
}
pthread_mutex_unlock(&Lock);
RemTime.tv_nsec = 0;
do
{
nanosleep(&MyTime, &RemTime);
}
while(RemTime.tv_nsec != 0);
//select(0, NULL, NULL, NULL, &MyTime);
if (myInterruptHandler != NULL)
{
myInterruptHandler(myParams);
}
}
Спасибо.
Re # 1, да, но это сложно сделать (tm), как предлагает @abligh ниже, и особенно сложно в коде _library_ (который не может утверждать, что сигналы со свободным перерывом). Re # 2, да, но мы не можем помочь вам отлаживать код, который мы не видим. (Кстати, SIGALRM или SIGVTALRM? Ваше повествование и ваш код говорят разные вещи.) – pilcrow
@pilcrow, SIGALRM, я просто понял, что скопировал код отладки, с которым я играл. Будет редактировать. –