QP/C++
qf_tick.cpp
Go to the documentation of this file.
00001 
00002 // Product: QF/C++
00003 // Last Updated for Version: 4.5.00
00004 // Date of the Last Update:  May 19, 2012
00005 //
00006 //                    Q u a n t u m     L e a P s
00007 //                    ---------------------------
00008 //                    innovating embedded systems
00009 //
00010 // Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved.
00011 //
00012 // This program is open source software: you can redistribute it and/or
00013 // modify it under the terms of the GNU General Public License as published
00014 // by the Free Software Foundation, either version 2 of the License, or
00015 // (at your option) any later version.
00016 //
00017 // Alternatively, this program may be distributed and modified under the
00018 // terms of Quantum Leaps commercial licenses, which expressly supersede
00019 // the GNU General Public License and are specifically designed for
00020 // licensees interested in retaining the proprietary status of their code.
00021 //
00022 // This program is distributed in the hope that it will be useful,
00023 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00025 // GNU General Public License for more details.
00026 //
00027 // You should have received a copy of the GNU General Public License
00028 // along with this program. If not, see <http://www.gnu.org/licenses/>.
00029 //
00030 // Contact information:
00031 // Quantum Leaps Web sites: http://www.quantum-leaps.com
00032 //                          http://www.state-machine.com
00033 // e-mail:                  info@quantum-leaps.com
00035 #include "qf_pkg.h"
00036 #include "qassert.h"
00040 
00041 QP_BEGIN_
00042 
00043 Q_DEFINE_THIS_MODULE("qf_tick")
00044 
00045 //............................................................................
00046 #ifndef Q_SPY
00047 void QF::tick(void) {                                            // see NOTE01
00048 #else
00049 void QF::tick(void const * const sender) {
00050 #endif
00051 
00052     QF_CRIT_STAT_
00053     QF_CRIT_ENTRY_();
00054 
00055     QS_BEGIN_NOCRIT_(QS_QF_TICK, null_void, null_void)
00056         QS_TEC_(static_cast<QTimeEvtCtr>(++QS::tickCtr_)); // the tick counter
00057     QS_END_NOCRIT_()
00058 
00059     QTimeEvt *prev = null_tevt;
00060     for (QTimeEvt *t = QF_timeEvtListHead_; t != null_tevt; t = t->m_next) {
00061         if (t->m_ctr == tc_0) {            // time evt. scheduled for removal?
00062             if (t == QF_timeEvtListHead_) {
00063                 QF_timeEvtListHead_ = t->m_next;
00064             }
00065             else {
00066                 Q_ASSERT(prev != null_tevt);
00067                 prev->m_next = t->m_next;
00068             }
00069             QF_EVT_REF_CTR_DEC_(t);                      // mark as not linked
00070         }
00071         else {
00072             --t->m_ctr;
00073             if (t->m_ctr == tc_0) {                        // about to expire?
00074                 if (t->m_interval != tc_0) {           // periodic time event?
00075                     t->m_ctr = t->m_interval;            // rearm the time evt
00076                 }
00077                 else {
00078                     QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS::teObj_, t)
00079                         QS_OBJ_(t);                  // this time event object
00080                         QS_OBJ_(t->m_act);                // the active object
00081                     QS_END_NOCRIT_()
00082                 }
00083 
00084                 QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS::teObj_, t)
00085                     QS_TIME_();                                   // timestamp
00086                     QS_OBJ_(t);                       // the time event object
00087                     QS_SIG_(t->sig);          // the signal of this time event
00088                     QS_OBJ_(t->m_act);                    // the active object
00089                 QS_END_NOCRIT_()
00090 
00091                 QF_CRIT_EXIT_();         // leave crit. section before posting
00092                            // POST() asserts internally if the queue overflows
00093                 t->m_act->POST(t, sender);
00094                 QF_CRIT_ENTRY_();        // re-enter crit. section to continue
00095 
00096                 if (t->m_ctr == tc_0) {             // still marked to expire?
00097                     if (t == QF_timeEvtListHead_) {
00098                         QF_timeEvtListHead_ = t->m_next;
00099                     }
00100                     else {
00101                         Q_ASSERT(prev != null_tevt);
00102                         prev->m_next = t->m_next;
00103                     }
00104                     QF_EVT_REF_CTR_DEC_(t);                 // mark as removed
00105                 }
00106                 else {
00107                     prev = t;
00108                 }
00109             }
00110             else {
00111                 prev = t;
00112             }
00113         }
00114     }
00115     QF_CRIT_EXIT_();
00116 }
00117 
00118 QP_END_
00119 
00121 // NOTE01:
00122 // QF::tick() must always run to completion and never preempt itself.
00123 // In particular, if QF::tick() runs in an ISR, the ISR is not allowed to
00124 // preempt itself. Also, QF::tick() should not be called from two different
00125 // ISRs, which potentially could preempt each other.
00126 //
00127 // NOTE02:
00128 // On many CPUs, the interrupt enabling takes only effect on the next
00129 // machine instruction, which happens to be here interrupt disabling.
00130 // The assignment of a volatile variable requires a few instructions, which
00131 // the compiler cannot optimize away. This ensures that the interrupts get
00132 // actually enabled, so that the interrupt latency stays low.
00133 //