Dining Philosophers Problem (DPP) example for the QP active object framework. Demonstrates: event-driven programming, hierarchical state machines in C++, modeling and graphical state machine design, code generation, preemptive multitasking, software tracing, power saving mode, direct event posting, publish-subscribe. More information available in the [[/users/QL/notebook|Quantum Leaps Notebook pages]]. See also [[http://www.state-machine.com|state-machine.com]].

Dependencies:   mbed qp

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers philo.cpp Source File

philo.cpp

00001 //////////////////////////////////////////////////////////////////////////////
00002 // Model: dpp.qm
00003 // File:  ././philo.cpp
00004 //
00005 // This file has been generated automatically by QP Modeler (QM).
00006 // DO NOT EDIT THIS FILE MANUALLY.
00007 //
00008 // Please visit www.state-machine.com/qm for more information.
00009 //////////////////////////////////////////////////////////////////////////////
00010 #include "qp_port.h"
00011 #include "dpp.h"
00012 #include "bsp.h"
00013 
00014 namespace DPP {
00015 
00016 Q_DEFINE_THIS_FILE
00017 
00018 // Active object class -------------------------------------------------------
00019 // @(/2/0) ...................................................................
00020 class Philo : public QP::QActive {
00021 private:
00022     QP::QTimeEvt m_timeEvt;
00023 
00024 public:
00025     Philo();
00026 
00027 protected:
00028     static QP::QState initial(Philo * const me, QP::QEvt const * const e);
00029     static QP::QState thinking(Philo * const me, QP::QEvt const * const e);
00030     static QP::QState hungry(Philo * const me, QP::QEvt const * const e);
00031     static QP::QState eating(Philo * const me, QP::QEvt const * const e);
00032 };
00033 
00034 // Local objects -------------------------------------------------------------
00035 static Philo l_philo[N_PHILO];   // storage for all Philos
00036 
00037 // helper function to provide a randomized think time for Philos
00038 inline QP::QTimeEvtCtr think_time() {
00039     return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC)
00040                                         + (BSP_TICKS_PER_SEC/2U));
00041 }
00042 
00043 // helper function to provide a randomized eat time for Philos
00044 inline QP::QTimeEvtCtr eat_time() {
00045     return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC)
00046                                         + BSP_TICKS_PER_SEC);
00047 }
00048 
00049 // helper function to provide the ID of Philo "me"
00050 inline uint8_t PHILO_ID(Philo const * const me) {
00051     return static_cast<uint8_t>(me - l_philo);
00052 }
00053 
00054 enum InternalSignals {           // internal signals
00055     TIMEOUT_SIG = MAX_SIG
00056 };
00057 
00058 // Global objects ------------------------------------------------------------
00059 QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO
00060     &l_philo[0],
00061     &l_philo[1],
00062     &l_philo[2],
00063     &l_philo[3],
00064     &l_philo[4]
00065 };
00066 
00067 // Philo definition ----------------------------------------------------------
00068 // @(/2/0) ...................................................................
00069 // @(/2/0/1) .................................................................
00070 Philo::Philo() 
00071   : QActive(Q_STATE_CAST(&Philo::initial)),
00072     m_timeEvt(TIMEOUT_SIG)
00073 {
00074 }
00075 
00076 // @(/2/0/2) .................................................................
00077 // @(/2/0/2/0)
00078 QP::QState Philo::initial(Philo * const me, QP::QEvt const * const e) {
00079     static bool registered = false; // starts off with 0, per C-standard
00080     (void)e; // suppress the compiler warning about unused parameter
00081     if (!registered) {
00082         registered = true;
00083 
00084         QS_OBJ_DICTIONARY(&l_philo[0]);
00085         QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt);
00086         QS_OBJ_DICTIONARY(&l_philo[1]);
00087         QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt);
00088         QS_OBJ_DICTIONARY(&l_philo[2]);
00089         QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt);
00090         QS_OBJ_DICTIONARY(&l_philo[3]);
00091         QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt);
00092         QS_OBJ_DICTIONARY(&l_philo[4]);
00093         QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt);
00094 
00095         QS_FUN_DICTIONARY(&Philo::initial);
00096         QS_FUN_DICTIONARY(&Philo::thinking);
00097         QS_FUN_DICTIONARY(&Philo::hungry);
00098         QS_FUN_DICTIONARY(&Philo::eating);
00099     }
00100     QS_SIG_DICTIONARY(HUNGRY_SIG, me);  // signal for each Philos
00101     QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos
00102 
00103     me->subscribe(EAT_SIG);
00104     return Q_TRAN(&Philo::thinking);
00105 }
00106 // @(/2/0/2/1) ...............................................................
00107 QP::QState Philo::thinking(Philo * const me, QP::QEvt const * const e) {
00108     QP::QState status;
00109     switch (e->sig) {
00110         // @(/2/0/2/1)
00111         case Q_ENTRY_SIG: {
00112             me->m_timeEvt.postIn(me, think_time());
00113             status = Q_HANDLED();
00114             break;
00115         }
00116         // @(/2/0/2/1)
00117         case Q_EXIT_SIG: {
00118             (void)me->m_timeEvt.disarm();
00119             status = Q_HANDLED();
00120             break;
00121         }
00122         // @(/2/0/2/1/0)
00123         case TIMEOUT_SIG: {
00124             status = Q_TRAN(&Philo::hungry);
00125             break;
00126         }
00127         // @(/2/0/2/1/1)
00128         case EAT_SIG: // intentionally fall through
00129         case DONE_SIG: {
00130             /* EAT or DONE must be for other Philos than this one */
00131             Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
00132             status = Q_HANDLED();
00133             break;
00134         }
00135         default: {
00136             status = Q_SUPER(&QHsm::top);
00137             break;
00138         }
00139     }
00140     return status;
00141 }
00142 // @(/2/0/2/2) ...............................................................
00143 QP::QState Philo::hungry(Philo * const me, QP::QEvt const * const e) {
00144     QP::QState status;
00145     switch (e->sig) {
00146         // @(/2/0/2/2)
00147         case Q_ENTRY_SIG: {
00148             TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
00149             pe->philoNum = PHILO_ID(me);
00150             AO_Table->POST(pe, me);
00151             status = Q_HANDLED();
00152             break;
00153         }
00154         // @(/2/0/2/2/0)
00155         case EAT_SIG: {
00156             // @(/2/0/2/2/0/0)
00157             if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(me)) {
00158                 status = Q_TRAN(&Philo::eating);
00159             }
00160             else {
00161                 status = Q_UNHANDLED();
00162             }
00163             break;
00164         }
00165         // @(/2/0/2/2/1)
00166         case DONE_SIG: {
00167             /* DONE must be for other Philos than this one */
00168             Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
00169             status = Q_HANDLED();
00170             break;
00171         }
00172         default: {
00173             status = Q_SUPER(&QHsm::top);
00174             break;
00175         }
00176     }
00177     return status;
00178 }
00179 // @(/2/0/2/3) ...............................................................
00180 QP::QState Philo::eating(Philo * const me, QP::QEvt const * const e) {
00181     QP::QState status;
00182     switch (e->sig) {
00183         // @(/2/0/2/3)
00184         case Q_ENTRY_SIG: {
00185             me->m_timeEvt.postIn(me, eat_time());
00186             status = Q_HANDLED();
00187             break;
00188         }
00189         // @(/2/0/2/3)
00190         case Q_EXIT_SIG: {
00191             TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
00192             pe->philoNum = PHILO_ID(me);
00193             QP::QF::PUBLISH(pe, me);
00194             (void)me->m_timeEvt.disarm();
00195             status = Q_HANDLED();
00196             break;
00197         }
00198         // @(/2/0/2/3/0)
00199         case TIMEOUT_SIG: {
00200             status = Q_TRAN(&Philo::thinking);
00201             break;
00202         }
00203         // @(/2/0/2/3/1)
00204         case EAT_SIG: // intentionally fall through
00205         case DONE_SIG: {
00206             /* EAT or DONE must be for other Philos than this one */
00207             Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
00208             status = Q_HANDLED();
00209             break;
00210         }
00211         default: {
00212             status = Q_SUPER(&QHsm::top);
00213             break;
00214         }
00215     }
00216     return status;
00217 }
00218 
00219 
00220 }                                                             // namespace DPP