POSIX timer signal is not blocked in the signal handler

I am setting up a POSIX timer to call a function at a given speed. I set up a signal handler and initialize a timer, etc ... everything works. However, according to all the documentation I read, I should never receive a signal from a timer while I am in a signal handler (it should be automatically blocked). To take this a step further, I even set sa_mask sigaction to block all signals ... I still get some calls to the signal handler ...

Handler settings:

// establish the signal handler sigset_t blockMask; struct sigaction sigact; sigfillset(&blockMask); //sigemptyset(&blockMask); sigact.sa_flags = SA_SIGINFO; sigact.sa_sigaction = callbackIn; sigact.sa_mask = blockMask; if( sigaction(ElmoSynchronizer::NEXT_RT_SIGNAL_NUMBER, &sigact, NULL) == -1 ) { return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't establish signal handler for timer" ); } // create the timer struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = ElmoSynchronizer::NEXT_RT_SIGNAL_NUMBER; sev.sigev_value.sival_ptr = this; if( timer_create(CLOCK_REALTIME, &sev, timerIn) == -1 ) { return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't create POSIX timer for timer" ); } // start the timer struct itimerspec timerSpec; timerSpec.it_value = firstExecTime; timerSpec.it_interval = ElmoSynchronizer::getTimespecFromDouble(1.0/rate_hz); if( timer_settime(*timerIn, TIMER_ABSTIME, &timerSpec, NULL) == -1 ) { return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't start timer for timer" ); } 

Callback (yes, I know printfs are bad in signal handlers):

  void ElmoSynchronizer::rootPvtCallback(int sig, siginfo_t *si, void *uc) { // get a pointer to the ElmoSynchronizer calling this ElmoSynchronizer *elmoSync = (ElmoSynchronizer*)si->si_value.sival_ptr; struct timespec startTime; clock_gettime(CLOCK_REALTIME, &startTime); uint32_t expectedTime_us = elmoSync->getMasterClockTimeFromTimespec_us(elmoSync->m_pvtSupplyStartTime) + ((elmoSync->m_updateIteration * elmoSync->m_elmoUpdatePeriod_ms) * 1000); uint32_t actualTime_us = elmoSync->getMasterClockTimeFromTimespec_us(startTime); uint32_t currIter = elmoSync->m_updateIteration+1; printf("---> PVT update - iteration %u @ %u\n", currIter, elmoSync->getMasterClockTimeFromTimespec_us(startTime)); fflush(stdout); // iterate through all of our callbacks and call them! for( unsigned int i = 0; i < elmoSync->m_elmos.size(); i++ ) { // get the position/velocity pair posVelPair_t pv = elmoSync->m_elmos[i].callback(elmoSync->m_elmos[i].elmo); // now add the point to the elmo elmoSync->m_elmos[i].elmo->addPvtPoints( pv.position_cnts, pv.velocity_cps, elmoSync->m_elmoUpdatePeriod_ms ); } elmoSync->m_updateIteration++; if( elmoSync->m_updateIteration == 250 ) { usleep(elmoSync->m_elmoUpdatePeriod_ms*4000); } // make sure we executed fast enough struct timespec endTime; clock_gettime(CLOCK_REALTIME, &endTime); double totalCallbackTime_s = getSecondsFromTimespec(ElmoSynchronizer::ts_subtract(endTime, startTime)); if( totalCallbackTime_s > (elmoSync->m_elmoUpdatePeriod_ms * 1.0E-3) ) { //ROS_WARN("PVT update - Callback execution took longer than update period! %lfs actual / %lfs period", totalCallbackTime_s, (elmoSync->m_elmoUpdatePeriod_ms * 1.0E-3)); //overflowedRootPvtCallbackPeriod = true; } printf("<--- PVT update - iteration %u @ %u\n", currIter, elmoSync->getMasterClockTimeFromTimespec_us(endTime)); fflush(stdout); /* printf("PVT update - iteration: %u actual: %u expected: %u diff: %u cbTime: %u\n", elmoSync->m_updateIteration, actualTime_us, expectedTime_us, actualTime_us-expectedTime_us, (uint32_t)(totalCallbackTime_s * 1.0E6)); fflush(stdout); */ } 

Output:

 ---> PVT update - iteration 248 @ 13315103 <--- PVT update - iteration 248 @ 13315219 ---> PVT update - iteration 249 @ 13346107 <--- PVT update - iteration 249 @ 13346199 ---> PVT update - iteration 250 @ 13377104 // two entrances ---> PVT update - iteration 251 @ 13408109 // second entrance <--- PVT update - iteration 251 @ 13408197 ---> PVT update - iteration 252 @ 13439109 <--- PVT update - iteration 252 @ 13439254 ---> PVT update - iteration 253 @ 13470120 <--- PVT update - iteration 253 @ 13470216 ---> PVT update - iteration 254 @ 13501122 <--- PVT update - iteration 254 @ 13501213 <--- PVT update - iteration 250 @ 13501317 // exit for iteration 250 ---> PVT update - iteration 255 @ 13532078 <--- PVT update - iteration 255 @ 13532170 ---> PVT update - iteration 256 @ 13563109 <--- PVT update - iteration 256 @ 13563242 
+4
source share
2 answers

Instead of setting a periodic timer, shoot again when the signal handler ends.

When you create a timer, do it

 // start the timer //struct itimerspec timerSpec; this->timerSpec_.it_value = firstExecTime; this->timerSpec_.it_interval = 0; //one-shot if( timer_settime(*timerIn, TIMER_ABSTIME, &this->timerSpec_, NULL) == -1 ) { return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't start timer for timer" ); } // from now we will shoot the timer with this value this->timerSpec_.it_value = ElmoSynchronizer::getTimespecFromDouble(1.0/rate_hz); // store *timerIn in also in ElmoSynchronizer this->timerId_ = *timerIn; 

Then add to the very end of the ElmoSynchronizer::rootPvtCallback this

 //shoot our the timer again if( timer_settime(elmoSync->timerId_, 0, &elmoSync->timerSpec_, NULL) == -1 ) { return CanStatus( CanStatus::SYSTEM_ERROR, __FUNCTION__, "Couldn't restart timer" ); } 

By the way, I would do all this with the help of threads and semaphores, so the synchronizer could just check if the PVT update process was completed or not at a certain duration. POSIX offers them and is no more difficult to implement than a timer.

+1
source

When I need to debug signal handlers, I make an array to post debugging information (instead of using printf). Collect data for several calls to the signal handler, then upload the contents of the array to see what happened.

You can see a different output order.

+1
source

Source: https://habr.com/ru/post/1333104/


All Articles