2010-12-22 91 views
4

我正在設置一個POSIX定時器以給定速率調用一個函數。我設置了一個信號處理程序並初始化定時器等等......一切正常。但是,根據我讀過的所有文檔,我不應該在信號處理程序中收到來自計時器的信號(它應該自動被阻止)。爲了進一步藉此一步,我甚至設定的sigaction的sa_mask阻止所有的信號......我還是去了信號處理程序多次調用...POSIX定時器信號在信號處理程序中未被阻止

設置的處理程序:

// 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"); 
    } 

回調(是的,我知道用printfs是不好的信號處理程序):

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); 
    */ 
} 

輸出:

---> 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 
+3

Nevermind`printf`; `usleep` **不是**異步信號安全的。請參見[IEEE標準1003.1-2001信號概念](http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html):「當信號中斷不安全功能並且信號捕獲功能調用不安全功能時,行爲是不確定的。「 – ephemient 2010-12-22 22:24:17

回答

1

不是設置週期性定時器,而是在信號處理程序結束時再次拍攝它。

當您創建計時器做到這一點

// 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; 

然後附加到ElmoSynchronizer::rootPvtCallback功能這

//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"); 
} 

順便說的盡頭,我會使整個事情與線程和信號量,所以同步器可以簡單地檢查PVT更新過程是否在定義的持續時間內結束。 POSIX提供它們,並不比定時器更難實現。

1

當我需要調試信號處理程序時,我創建一個數組來放入調試信息(而不是使用printf)。收集大量信號處理程序調用的數據,然後轉儲數組的內容以查看發生了什麼。

您可能會看到與輸出不同的順序。