/** * @brief Disables a Virtual Timer. * @pre The timer must be in armed state before calling this function. * * @param[in] vtp the @p virtual_timer_t structure pointer * * @iclass */ void chVTDoResetI(virtual_timer_t *vtp) { chDbgCheckClassI(); chDbgCheck(vtp != NULL); chDbgAssert(vtp->vt_func != NULL, "timer not set or already triggered"); /* Removing the element from the delta list.*/ vtp->vt_next->vt_delta += vtp->vt_delta; vtp->vt_prev->vt_next = vtp->vt_next; vtp->vt_next->vt_prev = vtp->vt_prev; vtp->vt_func = (vtfunc_t)NULL; /* The above code changes the value in the header when the removed element is the last of the list, restoring it.*/ ch.vtlist.vt_delta = (systime_t)-1; #if CH_CFG_ST_TIMEDELTA > 0 || defined(__DOXYGEN__) { if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) { /* Just removed the last element in the list, alarm timer stopped.*/ port_timer_stop_alarm(); } else { /* The alarm is set to the next element in the delta list.*/ port_timer_set_alarm(ch.vtlist.vt_lasttime + ch.vtlist.vt_next->vt_delta); } } #endif /* CH_CFG_ST_TIMEDELTA > 0 */ }
/** * @brief Disables a Virtual Timer. * @pre The timer must be in armed state before calling this function. * * @param[in] vtp the @p virtual_timer_t structure pointer * * @iclass */ void chVTDoResetI(virtual_timer_t *vtp) { chDbgCheckClassI(); chDbgCheck(vtp != NULL); chDbgAssert(vtp->func != NULL, "timer not set or already triggered"); #if CH_CFG_ST_TIMEDELTA == 0 /* The delta of the timer is added to the next timer.*/ vtp->next->delta += vtp->delta; /* Removing the element from the delta list.*/ vtp->prev->next = vtp->next; vtp->next->prev = vtp->prev; vtp->func = NULL; /* The above code changes the value in the header when the removed element is the last of the list, restoring it.*/ ch.vtlist.delta = (sysinterval_t)-1; #else /* CH_CFG_ST_TIMEDELTA > 0 */ sysinterval_t nowdelta, delta; /* If the timer is not the first of the list then it is simply unlinked else the operation is more complex.*/ if (ch.vtlist.next != vtp) { /* Removing the element from the delta list.*/ vtp->prev->next = vtp->next; vtp->next->prev = vtp->prev; vtp->func = NULL; /* Adding delta to the next element, if it is not the last one.*/ if (&ch.vtlist != (virtual_timers_list_t *)vtp->next) vtp->next->delta += vtp->delta; return; } /* Removing the first timer from the list.*/ ch.vtlist.next = vtp->next; ch.vtlist.next->prev = (virtual_timer_t *)&ch.vtlist; vtp->func = NULL; /* If the list become empty then the alarm timer is stopped and done.*/ if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) { port_timer_stop_alarm(); return; } /* The delta of the removed timer is added to the new first timer.*/ ch.vtlist.next->delta += vtp->delta; /* If the new first timer has a delta of zero then the alarm is not modified, the already programmed alarm will serve it.*/ /* if (ch.vtlist.next->delta == 0) { return; }*/ /* Distance in ticks between the last alarm event and current time.*/ nowdelta = chTimeDiffX(ch.vtlist.lasttime, chVTGetSystemTimeX()); /* If the current time surpassed the time of the next element in list then the event interrupt is already pending, just return.*/ if (nowdelta >= ch.vtlist.next->delta) { return; } /* Distance from the next scheduled event and now.*/ delta = ch.vtlist.next->delta - nowdelta; /* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA ticks from now.*/ if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { delta = nowdelta + (sysinterval_t)CH_CFG_ST_TIMEDELTA; } else { delta = nowdelta + delta; #if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION /* The delta could be too large for the physical timer to handle.*/ if (delta > (sysinterval_t)TIME_MAX_SYSTIME) { delta = (sysinterval_t)TIME_MAX_SYSTIME; } #endif } port_timer_set_alarm(chTimeAddX(ch.vtlist.lasttime, delta)); #endif /* CH_CFG_ST_TIMEDELTA > 0 */ }
/** * @brief Time management handler. * @note This handler has to be invoked by a periodic ISR in order to * reschedule the waiting threads. * * @iclass */ void chSysTimerHandlerI(void) { #if NIL_CFG_ST_TIMEDELTA == 0 thread_t *tp = &nil.threads[0]; nil.systime++; do { /* Is the thread in a wait state with timeout?.*/ if (tp->timeout > (systime_t)0) { chDbgAssert(!NIL_THD_IS_READY(tp), "is ready"); /* Did the timer reach zero?*/ if (--tp->timeout == (systime_t)0) { /* Timeout on semaphores requires a special handling because the semaphore counter must be incremented.*/ /*lint -save -e9013 [15.7] There is no else because it is not needed.*/ if (NIL_THD_IS_WTSEM(tp)) { tp->u1.semp->cnt++; } else if (NIL_THD_IS_SUSP(tp)) { *tp->u1.trp = NULL; } /*lint -restore*/ (void) chSchReadyI(tp, MSG_TIMEOUT); } } /* Lock released in order to give a preemption chance on those architectures supporting IRQ preemption.*/ chSysUnlockFromISR(); tp++; chSysLockFromISR(); } while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); #else thread_t *tp = &nil.threads[0]; systime_t next = (systime_t)0; chDbgAssert(nil.nexttime == port_timer_get_alarm(), "time mismatch"); do { /* Is the thread in a wait state with timeout?.*/ if (tp->timeout > (systime_t)0) { chDbgAssert(!NIL_THD_IS_READY(tp), "is ready"); chDbgAssert(tp->timeout >= (nil.nexttime - nil.lasttime), "skipped one"); tp->timeout -= nil.nexttime - nil.lasttime; if (tp->timeout == (systime_t)0) { /* Timeout on semaphores requires a special handling because the semaphore counter must be incremented.*/ /*lint -save -e9013 [15.7] There is no else because it is not needed.*/ if (NIL_THD_IS_WTSEM(tp)) { tp->u1.semp->cnt++; } else if (NIL_THD_IS_SUSP(tp)) { *tp->u1.trp = NULL; } /*lint -restore*/ (void) chSchReadyI(tp, MSG_TIMEOUT); } else { if (tp->timeout <= (systime_t)(next - (systime_t)1)) { next = tp->timeout; } } } /* Lock released in order to give a preemption chance on those architectures supporting IRQ preemption.*/ chSysUnlockFromISR(); tp++; chSysLockFromISR(); } while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); nil.lasttime = nil.nexttime; if (next > (systime_t)0) { nil.nexttime += next; port_timer_set_alarm(nil.nexttime); } else { /* No tick event needed.*/ port_timer_stop_alarm(); } #endif }