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

Committer:
QL
Date:
Sat Feb 12 23:22:47 2011 +0000
Revision:
0:efb9ac8d1a88
Child:
3:81ceb3127876

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
QL 0:efb9ac8d1a88 1 //////////////////////////////////////////////////////////////////////////////
QL 0:efb9ac8d1a88 2 // Product: DPP example
QL 0:efb9ac8d1a88 3 // Last Updated for Version: 4.0.00
QL 0:efb9ac8d1a88 4 // Date of the Last Update: Apr 06, 2008
QL 0:efb9ac8d1a88 5 //
QL 0:efb9ac8d1a88 6 // Q u a n t u m L e a P s
QL 0:efb9ac8d1a88 7 // ---------------------------
QL 0:efb9ac8d1a88 8 // innovating embedded systems
QL 0:efb9ac8d1a88 9 //
QL 0:efb9ac8d1a88 10 // Copyright (C) 2002-2008 Quantum Leaps, LLC. All rights reserved.
QL 0:efb9ac8d1a88 11 //
QL 0:efb9ac8d1a88 12 // This software may be distributed and modified under the terms of the GNU
QL 0:efb9ac8d1a88 13 // General Public License version 2 (GPL) as published by the Free Software
QL 0:efb9ac8d1a88 14 // Foundation and appearing in the file GPL.TXT included in the packaging of
QL 0:efb9ac8d1a88 15 // this file. Please note that GPL Section 2[b] requires that all works based
QL 0:efb9ac8d1a88 16 // on this software must also be made publicly available under the terms of
QL 0:efb9ac8d1a88 17 // the GPL ("Copyleft").
QL 0:efb9ac8d1a88 18 //
QL 0:efb9ac8d1a88 19 // Alternatively, this software may be distributed and modified under the
QL 0:efb9ac8d1a88 20 // terms of Quantum Leaps commercial licenses, which expressly supersede
QL 0:efb9ac8d1a88 21 // the GPL and are specifically designed for licensees interested in
QL 0:efb9ac8d1a88 22 // retaining the proprietary status of their code.
QL 0:efb9ac8d1a88 23 //
QL 0:efb9ac8d1a88 24 // Contact information:
QL 0:efb9ac8d1a88 25 // Quantum Leaps Web site: http://www.quantum-leaps.com
QL 0:efb9ac8d1a88 26 // e-mail: info@quantum-leaps.com
QL 0:efb9ac8d1a88 27 //////////////////////////////////////////////////////////////////////////////
QL 0:efb9ac8d1a88 28 #include "qp_port.h"
QL 0:efb9ac8d1a88 29 #include "dpp.h"
QL 0:efb9ac8d1a88 30 #include "bsp.h"
QL 0:efb9ac8d1a88 31
QL 0:efb9ac8d1a88 32 Q_DEFINE_THIS_FILE
QL 0:efb9ac8d1a88 33
QL 0:efb9ac8d1a88 34 // Active object class -------------------------------------------------------
QL 0:efb9ac8d1a88 35 class Philo : public QActive {
QL 0:efb9ac8d1a88 36 private:
QL 0:efb9ac8d1a88 37 QTimeEvt m_timeEvt; // to timeout thinking or eating
QL 0:efb9ac8d1a88 38
QL 0:efb9ac8d1a88 39 public:
QL 0:efb9ac8d1a88 40 Philo();
QL 0:efb9ac8d1a88 41
QL 0:efb9ac8d1a88 42 private:
QL 0:efb9ac8d1a88 43 static QState initial (Philo *me, QEvent const *e);
QL 0:efb9ac8d1a88 44 static QState thinking(Philo *me, QEvent const *e);
QL 0:efb9ac8d1a88 45 static QState hungry (Philo *me, QEvent const *e);
QL 0:efb9ac8d1a88 46 static QState eating (Philo *me, QEvent const *e);
QL 0:efb9ac8d1a88 47 };
QL 0:efb9ac8d1a88 48
QL 0:efb9ac8d1a88 49 // Local objects -------------------------------------------------------------
QL 0:efb9ac8d1a88 50 static Philo l_philo[N_PHILO]; // storage for all Philos
QL 0:efb9ac8d1a88 51
QL 0:efb9ac8d1a88 52 #define THINK_TIME 23
QL 0:efb9ac8d1a88 53 #define EAT_TIME 19
QL 0:efb9ac8d1a88 54 // helper macro to provide the ID of Philo "me_"
QL 0:efb9ac8d1a88 55 #define PHILO_ID(me_) ((uint8_t)((me_) - l_philo))
QL 0:efb9ac8d1a88 56
QL 0:efb9ac8d1a88 57 enum InternalSignals { // internal signals
QL 0:efb9ac8d1a88 58 TIMEOUT_SIG = MAX_SIG
QL 0:efb9ac8d1a88 59 };
QL 0:efb9ac8d1a88 60 // Global objects ------------------------------------------------------------
QL 0:efb9ac8d1a88 61 QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AOs
QL 0:efb9ac8d1a88 62 &l_philo[0],
QL 0:efb9ac8d1a88 63 &l_philo[1],
QL 0:efb9ac8d1a88 64 &l_philo[2],
QL 0:efb9ac8d1a88 65 &l_philo[3],
QL 0:efb9ac8d1a88 66 &l_philo[4]
QL 0:efb9ac8d1a88 67 };
QL 0:efb9ac8d1a88 68
QL 0:efb9ac8d1a88 69 //............................................................................
QL 0:efb9ac8d1a88 70 Philo::Philo()
QL 0:efb9ac8d1a88 71 : QActive((QStateHandler)&Philo::initial),
QL 0:efb9ac8d1a88 72 m_timeEvt(TIMEOUT_SIG)
QL 0:efb9ac8d1a88 73 {}
QL 0:efb9ac8d1a88 74 //............................................................................
QL 0:efb9ac8d1a88 75 QState Philo::initial(Philo *me, QEvent const *) {
QL 0:efb9ac8d1a88 76 static uint8_t registered; // starts off with 0, per C-standard
QL 0:efb9ac8d1a88 77 if (!registered) {
QL 0:efb9ac8d1a88 78 QS_OBJ_DICTIONARY(&l_philo[0]);
QL 0:efb9ac8d1a88 79 QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt);
QL 0:efb9ac8d1a88 80 QS_OBJ_DICTIONARY(&l_philo[1]);
QL 0:efb9ac8d1a88 81 QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt);
QL 0:efb9ac8d1a88 82 QS_OBJ_DICTIONARY(&l_philo[2]);
QL 0:efb9ac8d1a88 83 QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt);
QL 0:efb9ac8d1a88 84 QS_OBJ_DICTIONARY(&l_philo[3]);
QL 0:efb9ac8d1a88 85 QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt);
QL 0:efb9ac8d1a88 86 QS_OBJ_DICTIONARY(&l_philo[4]);
QL 0:efb9ac8d1a88 87 QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt);
QL 0:efb9ac8d1a88 88
QL 0:efb9ac8d1a88 89 QS_FUN_DICTIONARY(&Philo::initial);
QL 0:efb9ac8d1a88 90 QS_FUN_DICTIONARY(&Philo::thinking);
QL 0:efb9ac8d1a88 91 QS_FUN_DICTIONARY(&Philo::hungry);
QL 0:efb9ac8d1a88 92 QS_FUN_DICTIONARY(&Philo::eating);
QL 0:efb9ac8d1a88 93
QL 0:efb9ac8d1a88 94 registered = (uint8_t)1;
QL 0:efb9ac8d1a88 95 }
QL 0:efb9ac8d1a88 96 QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal for each Philos
QL 0:efb9ac8d1a88 97 QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos
QL 0:efb9ac8d1a88 98
QL 0:efb9ac8d1a88 99 me->subscribe(EAT_SIG);
QL 0:efb9ac8d1a88 100
QL 0:efb9ac8d1a88 101 return Q_TRAN(&Philo::thinking);
QL 0:efb9ac8d1a88 102 }
QL 0:efb9ac8d1a88 103 //............................................................................
QL 0:efb9ac8d1a88 104 QState Philo::thinking(Philo *me, QEvent const *e) {
QL 0:efb9ac8d1a88 105 switch (e->sig) {
QL 0:efb9ac8d1a88 106 case Q_ENTRY_SIG: {
QL 0:efb9ac8d1a88 107 me->m_timeEvt.postIn(me, THINK_TIME);
QL 0:efb9ac8d1a88 108 return Q_HANDLED();
QL 0:efb9ac8d1a88 109 }
QL 0:efb9ac8d1a88 110 case TIMEOUT_SIG: {
QL 0:efb9ac8d1a88 111 BSP_busyDelay();
QL 0:efb9ac8d1a88 112 return Q_TRAN(&Philo::hungry);
QL 0:efb9ac8d1a88 113 }
QL 0:efb9ac8d1a88 114 case EAT_SIG: // intentionally fall-through
QL 0:efb9ac8d1a88 115 case DONE_SIG: {
QL 0:efb9ac8d1a88 116 // EAT or DONE must be for other Philos than this one
QL 0:efb9ac8d1a88 117 Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
QL 0:efb9ac8d1a88 118 return Q_HANDLED();
QL 0:efb9ac8d1a88 119 }
QL 0:efb9ac8d1a88 120 }
QL 0:efb9ac8d1a88 121 return Q_SUPER(&QHsm::top);
QL 0:efb9ac8d1a88 122 }
QL 0:efb9ac8d1a88 123 //............................................................................
QL 0:efb9ac8d1a88 124 QState Philo::hungry(Philo *me, QEvent const *e) {
QL 0:efb9ac8d1a88 125 switch (e->sig) {
QL 0:efb9ac8d1a88 126 case Q_ENTRY_SIG: {
QL 0:efb9ac8d1a88 127 TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
QL 0:efb9ac8d1a88 128 pe->philoNum = PHILO_ID(me);
QL 0:efb9ac8d1a88 129 AO_Table->postFIFO(pe);
QL 0:efb9ac8d1a88 130 return Q_HANDLED();
QL 0:efb9ac8d1a88 131 }
QL 0:efb9ac8d1a88 132 case EAT_SIG: {
QL 0:efb9ac8d1a88 133 if (((TableEvt *)e)->philoNum == PHILO_ID(me)) {
QL 0:efb9ac8d1a88 134 BSP_busyDelay();
QL 0:efb9ac8d1a88 135 return Q_TRAN(&Philo::eating);
QL 0:efb9ac8d1a88 136 }
QL 0:efb9ac8d1a88 137 break;
QL 0:efb9ac8d1a88 138 }
QL 0:efb9ac8d1a88 139 case DONE_SIG: {
QL 0:efb9ac8d1a88 140 // DONE must be for other Philos than this one
QL 0:efb9ac8d1a88 141 Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
QL 0:efb9ac8d1a88 142 return Q_HANDLED();
QL 0:efb9ac8d1a88 143 }
QL 0:efb9ac8d1a88 144 }
QL 0:efb9ac8d1a88 145 return Q_SUPER(&QHsm::top);
QL 0:efb9ac8d1a88 146 }
QL 0:efb9ac8d1a88 147 //............................................................................
QL 0:efb9ac8d1a88 148 QState Philo::eating(Philo *me, QEvent const *e) {
QL 0:efb9ac8d1a88 149 switch (e->sig) {
QL 0:efb9ac8d1a88 150 case Q_ENTRY_SIG: {
QL 0:efb9ac8d1a88 151 me->m_timeEvt.postIn(me, EAT_TIME);
QL 0:efb9ac8d1a88 152 return Q_HANDLED();
QL 0:efb9ac8d1a88 153 }
QL 0:efb9ac8d1a88 154 case Q_EXIT_SIG: {
QL 0:efb9ac8d1a88 155 TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
QL 0:efb9ac8d1a88 156 pe->philoNum = PHILO_ID(me);
QL 0:efb9ac8d1a88 157 QF::publish(pe);
QL 0:efb9ac8d1a88 158 return Q_HANDLED();
QL 0:efb9ac8d1a88 159 }
QL 0:efb9ac8d1a88 160 case TIMEOUT_SIG: {
QL 0:efb9ac8d1a88 161 BSP_busyDelay();
QL 0:efb9ac8d1a88 162 return Q_TRAN(&Philo::thinking);
QL 0:efb9ac8d1a88 163 }
QL 0:efb9ac8d1a88 164 case EAT_SIG: // intentionally fall-through
QL 0:efb9ac8d1a88 165 case DONE_SIG: {
QL 0:efb9ac8d1a88 166 // EAT or DONE must be for other Philos than this one
QL 0:efb9ac8d1a88 167 Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
QL 0:efb9ac8d1a88 168 return Q_HANDLED();
QL 0:efb9ac8d1a88 169 }
QL 0:efb9ac8d1a88 170 }
QL 0:efb9ac8d1a88 171 return Q_SUPER(&QHsm::top);
QL 0:efb9ac8d1a88 172 }
QL 0:efb9ac8d1a88 173