QP/C++
qf_tick.cpp
Go to the documentation of this file.
00001 
00002 // Product: QF/C++
00003 // Last Updated for Version: 4.3.00
00004 // Date of the Last Update:  Nov 01, 2011
00005 //
00006 //                    Q u a n t u m     L e a P s
00007 //                    ---------------------------
00008 //                    innovating embedded systems
00009 //
00010 // Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
00011 //
00012 // This software may be distributed and modified under the terms of the GNU
00013 // General Public License version 2 (GPL) as published by the Free Software
00014 // Foundation and appearing in the file GPL.TXT included in the packaging of
00015 // this file. Please note that GPL Section 2[b] requires that all works based
00016 // on this software must also be made publicly available under the terms of
00017 // the GPL ("Copyleft").
00018 //
00019 // Alternatively, this software may be distributed and modified under the
00020 // terms of Quantum Leaps commercial licenses, which expressly supersede
00021 // the GPL and are specifically designed for licensees interested in
00022 // retaining the proprietary status of their code.
00023 //
00024 // Contact information:
00025 // Quantum Leaps Web site:  http://www.quantum-leaps.com
00026 // e-mail:                  info@quantum-leaps.com
00028 #include "qf_pkg.h"
00029 //#include "qassert.h"
00033 
00034 #ifdef Q_USE_NAMESPACE
00035 namespace QP {
00036 #endif
00037 
00038 //Q_DEFINE_THIS_MODULE(qf_tick)
00039 
00040 //............................................................................
00041 #ifndef Q_SPY
00042 void QF::tick(void) {                                            // see NOTE01
00043 #else
00044 void QF::tick(void const *sender) {
00045 #endif
00046 
00047     QF_CRIT_STAT_
00048     QF_CRIT_ENTRY_();
00049 
00050     QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0)
00051         QS_TEC_(++QS::tickCtr_);                           // the tick counter
00052     QS_END_NOCRIT_()
00053 
00054     QTimeEvt *t = QF_timeEvtListHead_;
00055     while (t != (QTimeEvt *)0) {
00056         --t->m_ctr;
00057         if (t->m_ctr == (QTimeEvtCtr)0) {  // is the time evt about to expire?
00058             if (t->m_interval != (QTimeEvtCtr)0) {//is it a periodic time evt?
00059                 t->m_ctr = t->m_interval;                // rearm the time evt
00060             }
00061             else {   // one-shot time evt, disarm by removing it from the list
00062                 if (t == QF_timeEvtListHead_) {
00063                     QF_timeEvtListHead_ = t->m_next;
00064                 }
00065                 else {
00066                     if (t->m_next != (QTimeEvt *)0) {// not the last time evt?
00067                         t->m_next->m_prev = t->m_prev;
00068                     }
00069                     t->m_prev->m_next = t->m_next;
00070                 }
00071                 t->m_prev = (QTimeEvt *)0;     // mark the time event disarmed
00072 
00073                 QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS::teObj_, t)
00074                     QS_OBJ_(t);                      // this time event object
00075                     QS_OBJ_(t->m_act);                    // the active object
00076                 QS_END_NOCRIT_()
00077             }
00078 
00079             QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS::teObj_, t)
00080                 QS_TIME_();                                       // timestamp
00081                 QS_OBJ_(t);                           // the time event object
00082                 QS_SIG_(t->sig);              // the signal of this time event
00083                 QS_OBJ_(t->m_act);                        // the active object
00084             QS_END_NOCRIT_()
00085 
00086             QF_CRIT_EXIT_();    // unlock interrupts before calling QF service
00087 
00088                            // POST() asserts internally if the queue overflows
00089             t->m_act->POST(t, sender);
00090         }
00091         else {
00092             QF_CRIT_EXIT_();
00093             static uint8_t volatile dummy;
00094             dummy = (uint8_t)0;      // execute a few instructions, see NOTE02
00095         }
00096 
00097         QF_CRIT_ENTRY_();         // lock interrupts again to advance the link
00098         t = t->m_next;
00099     }
00100     QF_CRIT_EXIT_();
00101 }
00102 
00103 #ifdef Q_USE_NAMESPACE
00104 }                                                              // namespace QP
00105 #endif
00106 
00108 // NOTE01:
00109 // QF::tick() must always run to completion and never preempt itself.
00110 // In particular, if QF::tick() runs in an ISR, the ISR is not allowed to
00111 // preempt itself. Also, QF::tick() should not be called from two different
00112 // ISRs, which potentially could preempt each other.
00113 //
00114 // NOTE02:
00115 // On many CPUs, the interrupt unlocking takes only effect on the next
00116 // machine instruction, which happens to be here another interrupt lock.
00117 // The assignment of a volatile variable requires a few instructions, which
00118 // the compiler cannot optimize away. This ensures that the interrupts get
00119 // actually unlocked, so that the interrupt latency stays low.
00120 //