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:
Wed Sep 05 13:50:21 2012 +0000
Revision:
5:15aad9bccbbd
Parent:
4:6189d844a1a2
enabled the QK_PREEMPTIVE option

Who changed what in which revision?

UserRevisionLine numberNew contents of line
QL 0:efb9ac8d1a88 1 //////////////////////////////////////////////////////////////////////////////
QL 4:6189d844a1a2 2 // Model: dpp.qm
QL 4:6189d844a1a2 3 // File: ././table.cpp
QL 0:efb9ac8d1a88 4 //
QL 4:6189d844a1a2 5 // This file has been generated automatically by QP Modeler (QM).
QL 4:6189d844a1a2 6 // DO NOT EDIT THIS FILE MANUALLY.
QL 0:efb9ac8d1a88 7 //
QL 4:6189d844a1a2 8 // Please visit www.state-machine.com/qm for more information.
QL 0:efb9ac8d1a88 9 //////////////////////////////////////////////////////////////////////////////
QL 0:efb9ac8d1a88 10 #include "qp_port.h"
QL 0:efb9ac8d1a88 11 #include "dpp.h"
QL 0:efb9ac8d1a88 12 #include "bsp.h"
QL 0:efb9ac8d1a88 13
QL 4:6189d844a1a2 14 namespace DPP {
QL 4:6189d844a1a2 15
QL 0:efb9ac8d1a88 16 Q_DEFINE_THIS_FILE
QL 0:efb9ac8d1a88 17
QL 0:efb9ac8d1a88 18 // Active object class -------------------------------------------------------
QL 4:6189d844a1a2 19 // @(/2/1) ...................................................................
QL 4:6189d844a1a2 20 class Table : public QP::QActive {
QL 0:efb9ac8d1a88 21 private:
QL 0:efb9ac8d1a88 22 uint8_t m_fork[N_PHILO];
QL 4:6189d844a1a2 23 bool m_isHungry[N_PHILO];
QL 0:efb9ac8d1a88 24
QL 0:efb9ac8d1a88 25 public:
QL 0:efb9ac8d1a88 26 Table();
QL 0:efb9ac8d1a88 27
QL 4:6189d844a1a2 28 protected:
QL 4:6189d844a1a2 29 static QP::QState initial(Table * const me, QP::QEvt const * const e);
QL 4:6189d844a1a2 30 static QP::QState active(Table * const me, QP::QEvt const * const e);
QL 4:6189d844a1a2 31 static QP::QState serving(Table * const me, QP::QEvt const * const e);
QL 4:6189d844a1a2 32 static QP::QState paused(Table * const me, QP::QEvt const * const e);
QL 0:efb9ac8d1a88 33 };
QL 0:efb9ac8d1a88 34
QL 4:6189d844a1a2 35 // helper function to provide the RIGHT neighbour of a Philo[n]
QL 4:6189d844a1a2 36 inline uint8_t RIGHT(uint8_t const n) {
QL 4:6189d844a1a2 37 return static_cast<uint8_t>((n + (N_PHILO - 1U)) % N_PHILO);
QL 4:6189d844a1a2 38 }
QL 4:6189d844a1a2 39
QL 4:6189d844a1a2 40 // helper function to provide the LEFT neighbour of a Philo[n]
QL 4:6189d844a1a2 41 inline uint8_t LEFT(uint8_t const n) {
QL 4:6189d844a1a2 42 return static_cast<uint8_t>((n + 1U) % N_PHILO);
QL 4:6189d844a1a2 43 }
QL 4:6189d844a1a2 44
QL 4:6189d844a1a2 45 static uint8_t const FREE = static_cast<uint8_t>(0);
QL 4:6189d844a1a2 46 static uint8_t const USED = static_cast<uint8_t>(1);
QL 4:6189d844a1a2 47
QL 4:6189d844a1a2 48 static char_t const * const THINKING = &"thinking"[0];
QL 4:6189d844a1a2 49 static char_t const * const HUNGRY = &"hungry "[0];
QL 4:6189d844a1a2 50 static char_t const * const EATING = &"eating "[0];
QL 0:efb9ac8d1a88 51
QL 0:efb9ac8d1a88 52 // Local objects -------------------------------------------------------------
QL 4:6189d844a1a2 53 static Table l_table; // the single instance of the Table active object
QL 0:efb9ac8d1a88 54
QL 4:6189d844a1a2 55 // Global-scope objects ------------------------------------------------------
QL 4:6189d844a1a2 56 QP::QActive * const AO_Table = &l_table; // "opaque" AO pointer
QL 0:efb9ac8d1a88 57
QL 0:efb9ac8d1a88 58 //............................................................................
QL 4:6189d844a1a2 59 // @(/2/1) ...................................................................
QL 4:6189d844a1a2 60 // @(/2/1/2) .................................................................
QL 4:6189d844a1a2 61 Table::Table()
QL 4:6189d844a1a2 62 : QActive(Q_STATE_CAST(&Table::initial))
QL 4:6189d844a1a2 63 {
QL 4:6189d844a1a2 64 for (uint8_t n = 0U; n < N_PHILO; ++n) {
QL 0:efb9ac8d1a88 65 m_fork[n] = FREE;
QL 4:6189d844a1a2 66 m_isHungry[n] = false;
QL 0:efb9ac8d1a88 67 }
QL 0:efb9ac8d1a88 68 }
QL 4:6189d844a1a2 69
QL 4:6189d844a1a2 70 // @(/2/1/3) .................................................................
QL 4:6189d844a1a2 71 // @(/2/1/3/0)
QL 4:6189d844a1a2 72 QP::QState Table::initial(Table * const me, QP::QEvt const * const e) {
QL 4:6189d844a1a2 73 (void)e; // suppress the compiler warning about unused parameter
QL 0:efb9ac8d1a88 74
QL 0:efb9ac8d1a88 75 QS_OBJ_DICTIONARY(&l_table);
QL 4:6189d844a1a2 76 QS_FUN_DICTIONARY(&QP::QHsm::top);
QL 0:efb9ac8d1a88 77 QS_FUN_DICTIONARY(&Table::initial);
QL 4:6189d844a1a2 78 QS_FUN_DICTIONARY(&Table::active);
QL 0:efb9ac8d1a88 79 QS_FUN_DICTIONARY(&Table::serving);
QL 4:6189d844a1a2 80 QS_FUN_DICTIONARY(&Table::paused);
QL 0:efb9ac8d1a88 81
QL 4:6189d844a1a2 82 QS_SIG_DICTIONARY(DONE_SIG, (void *)0); // global signals
QL 4:6189d844a1a2 83 QS_SIG_DICTIONARY(EAT_SIG, (void *)0);
QL 4:6189d844a1a2 84 QS_SIG_DICTIONARY(PAUSE_SIG, (void *)0);
QL 4:6189d844a1a2 85 QS_SIG_DICTIONARY(TERMINATE_SIG, (void *)0);
QL 0:efb9ac8d1a88 86
QL 4:6189d844a1a2 87 QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal just for Table
QL 0:efb9ac8d1a88 88
QL 0:efb9ac8d1a88 89 me->subscribe(DONE_SIG);
QL 4:6189d844a1a2 90 me->subscribe(PAUSE_SIG);
QL 0:efb9ac8d1a88 91 me->subscribe(TERMINATE_SIG);
QL 0:efb9ac8d1a88 92
QL 4:6189d844a1a2 93 for (uint8_t n = 0U; n < N_PHILO; ++n) {
QL 4:6189d844a1a2 94 me->m_fork[n] = FREE;
QL 4:6189d844a1a2 95 me->m_isHungry[n] = false;
QL 4:6189d844a1a2 96 BSP_displayPhilStat(n, THINKING);
QL 4:6189d844a1a2 97 }
QL 0:efb9ac8d1a88 98 return Q_TRAN(&Table::serving);
QL 0:efb9ac8d1a88 99 }
QL 4:6189d844a1a2 100 // @(/2/1/3/1) ...............................................................
QL 4:6189d844a1a2 101 QP::QState Table::active(Table * const me, QP::QEvt const * const e) {
QL 4:6189d844a1a2 102 QP::QState status;
QL 0:efb9ac8d1a88 103 switch (e->sig) {
QL 4:6189d844a1a2 104 // @(/2/1/3/1/0)
QL 4:6189d844a1a2 105 case TERMINATE_SIG: {
QL 4:6189d844a1a2 106 BSP_terminate(0);
QL 4:6189d844a1a2 107 status = Q_HANDLED();
QL 4:6189d844a1a2 108 break;
QL 4:6189d844a1a2 109 }
QL 4:6189d844a1a2 110 // @(/2/1/3/1/1)
QL 4:6189d844a1a2 111 case EAT_SIG: {
QL 4:6189d844a1a2 112 Q_ERROR();
QL 4:6189d844a1a2 113 status = Q_HANDLED();
QL 4:6189d844a1a2 114 break;
QL 4:6189d844a1a2 115 }
QL 4:6189d844a1a2 116 default: {
QL 4:6189d844a1a2 117 status = Q_SUPER(&QHsm::top);
QL 4:6189d844a1a2 118 break;
QL 4:6189d844a1a2 119 }
QL 4:6189d844a1a2 120 }
QL 4:6189d844a1a2 121 return status;
QL 4:6189d844a1a2 122 }
QL 4:6189d844a1a2 123 // @(/2/1/3/1/2) .............................................................
QL 4:6189d844a1a2 124 QP::QState Table::serving(Table * const me, QP::QEvt const * const e) {
QL 4:6189d844a1a2 125 QP::QState status;
QL 4:6189d844a1a2 126 switch (e->sig) {
QL 4:6189d844a1a2 127 // @(/2/1/3/1/2)
QL 4:6189d844a1a2 128 case Q_ENTRY_SIG: {
QL 4:6189d844a1a2 129 for (uint8_t n = 0U; n < N_PHILO; ++n) { // give permissions to eat...
QL 4:6189d844a1a2 130 if (me->m_isHungry[n]
QL 4:6189d844a1a2 131 && (me->m_fork[LEFT(n)] == FREE)
QL 4:6189d844a1a2 132 && (me->m_fork[n] == FREE))
QL 4:6189d844a1a2 133 {
QL 4:6189d844a1a2 134 me->m_fork[LEFT(n)] = USED;
QL 4:6189d844a1a2 135 me->m_fork[n] = USED;
QL 4:6189d844a1a2 136 TableEvt *te = Q_NEW(TableEvt, EAT_SIG);
QL 4:6189d844a1a2 137 te->philoNum = n;
QL 4:6189d844a1a2 138 QP::QF::PUBLISH(te, me);
QL 4:6189d844a1a2 139 me->m_isHungry[n] = false;
QL 4:6189d844a1a2 140 BSP_displayPhilStat(n, EATING);
QL 4:6189d844a1a2 141 }
QL 4:6189d844a1a2 142 }
QL 4:6189d844a1a2 143 status = Q_HANDLED();
QL 4:6189d844a1a2 144 break;
QL 4:6189d844a1a2 145 }
QL 4:6189d844a1a2 146 // @(/2/1/3/1/2/0)
QL 0:efb9ac8d1a88 147 case HUNGRY_SIG: {
QL 4:6189d844a1a2 148 uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
QL 4:6189d844a1a2 149 // phil ID must be in range and he must be not hungry
QL 0:efb9ac8d1a88 150 Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
QL 0:efb9ac8d1a88 151
QL 4:6189d844a1a2 152 BSP_displayPhilStat(n, HUNGRY);
QL 4:6189d844a1a2 153 uint8_t m = LEFT(n);
QL 4:6189d844a1a2 154 // @(/2/1/3/1/2/0/0)
QL 0:efb9ac8d1a88 155 if ((me->m_fork[m] == FREE) && (me->m_fork[n] == FREE)) {
QL 4:6189d844a1a2 156 me->m_fork[m] = USED;
QL 4:6189d844a1a2 157 me->m_fork[n] = USED;
QL 4:6189d844a1a2 158 TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
QL 0:efb9ac8d1a88 159 pe->philoNum = n;
QL 4:6189d844a1a2 160 QP::QF::PUBLISH(pe, me);
QL 4:6189d844a1a2 161 BSP_displayPhilStat(n, EATING);
QL 4:6189d844a1a2 162 status = Q_HANDLED();
QL 0:efb9ac8d1a88 163 }
QL 4:6189d844a1a2 164 // @(/2/1/3/1/2/0/1)
QL 0:efb9ac8d1a88 165 else {
QL 4:6189d844a1a2 166 me->m_isHungry[n] = true;
QL 4:6189d844a1a2 167 status = Q_HANDLED();
QL 0:efb9ac8d1a88 168 }
QL 4:6189d844a1a2 169 break;
QL 0:efb9ac8d1a88 170 }
QL 4:6189d844a1a2 171 // @(/2/1/3/1/2/1)
QL 0:efb9ac8d1a88 172 case DONE_SIG: {
QL 4:6189d844a1a2 173 uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
QL 4:6189d844a1a2 174 // phil ID must be in range and he must be not hungry
QL 0:efb9ac8d1a88 175 Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
QL 0:efb9ac8d1a88 176
QL 4:6189d844a1a2 177 BSP_displayPhilStat(n, THINKING);
QL 4:6189d844a1a2 178 uint8_t m = LEFT(n);
QL 4:6189d844a1a2 179 // both forks of Phil[n] must be used
QL 0:efb9ac8d1a88 180 Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
QL 0:efb9ac8d1a88 181
QL 4:6189d844a1a2 182 me->m_fork[m] = FREE;
QL 4:6189d844a1a2 183 me->m_fork[n] = FREE;
QL 4:6189d844a1a2 184 m = RIGHT(n); // check the right neighbor
QL 4:6189d844a1a2 185
QL 0:efb9ac8d1a88 186 if (me->m_isHungry[m] && (me->m_fork[m] == FREE)) {
QL 4:6189d844a1a2 187 me->m_fork[n] = USED;
QL 4:6189d844a1a2 188 me->m_fork[m] = USED;
QL 4:6189d844a1a2 189 me->m_isHungry[m] = false;
QL 4:6189d844a1a2 190 TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
QL 0:efb9ac8d1a88 191 pe->philoNum = m;
QL 4:6189d844a1a2 192 QP::QF::PUBLISH(pe, me);
QL 4:6189d844a1a2 193 BSP_displayPhilStat(m, EATING);
QL 0:efb9ac8d1a88 194 }
QL 4:6189d844a1a2 195 m = LEFT(n); // check the left neighbor
QL 4:6189d844a1a2 196 n = LEFT(m); // left fork of the left neighbor
QL 0:efb9ac8d1a88 197 if (me->m_isHungry[m] && (me->m_fork[n] == FREE)) {
QL 4:6189d844a1a2 198 me->m_fork[m] = USED;
QL 4:6189d844a1a2 199 me->m_fork[n] = USED;
QL 4:6189d844a1a2 200 me->m_isHungry[m] = false;
QL 4:6189d844a1a2 201 TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
QL 0:efb9ac8d1a88 202 pe->philoNum = m;
QL 4:6189d844a1a2 203 QP::QF::PUBLISH(pe, me);
QL 4:6189d844a1a2 204 BSP_displayPhilStat(m, EATING);
QL 0:efb9ac8d1a88 205 }
QL 4:6189d844a1a2 206 status = Q_HANDLED();
QL 4:6189d844a1a2 207 break;
QL 4:6189d844a1a2 208 }
QL 4:6189d844a1a2 209 // @(/2/1/3/1/2/2)
QL 4:6189d844a1a2 210 case EAT_SIG: {
QL 4:6189d844a1a2 211 Q_ERROR();
QL 4:6189d844a1a2 212 status = Q_HANDLED();
QL 4:6189d844a1a2 213 break;
QL 0:efb9ac8d1a88 214 }
QL 4:6189d844a1a2 215 // @(/2/1/3/1/2/3)
QL 4:6189d844a1a2 216 case PAUSE_SIG: {
QL 4:6189d844a1a2 217 status = Q_TRAN(&Table::paused);
QL 4:6189d844a1a2 218 break;
QL 4:6189d844a1a2 219 }
QL 4:6189d844a1a2 220 default: {
QL 4:6189d844a1a2 221 status = Q_SUPER(&Table::active);
QL 4:6189d844a1a2 222 break;
QL 0:efb9ac8d1a88 223 }
QL 0:efb9ac8d1a88 224 }
QL 4:6189d844a1a2 225 return status;
QL 0:efb9ac8d1a88 226 }
QL 4:6189d844a1a2 227 // @(/2/1/3/1/3) .............................................................
QL 4:6189d844a1a2 228 QP::QState Table::paused(Table * const me, QP::QEvt const * const e) {
QL 4:6189d844a1a2 229 QP::QState status;
QL 4:6189d844a1a2 230 switch (e->sig) {
QL 4:6189d844a1a2 231 // @(/2/1/3/1/3)
QL 4:6189d844a1a2 232 case Q_ENTRY_SIG: {
QL 4:6189d844a1a2 233 BSP_displayPaused(1U);
QL 4:6189d844a1a2 234 status = Q_HANDLED();
QL 4:6189d844a1a2 235 break;
QL 4:6189d844a1a2 236 }
QL 4:6189d844a1a2 237 // @(/2/1/3/1/3)
QL 4:6189d844a1a2 238 case Q_EXIT_SIG: {
QL 4:6189d844a1a2 239 BSP_displayPaused(0U);
QL 4:6189d844a1a2 240 status = Q_HANDLED();
QL 4:6189d844a1a2 241 break;
QL 4:6189d844a1a2 242 }
QL 4:6189d844a1a2 243 // @(/2/1/3/1/3/0)
QL 4:6189d844a1a2 244 case PAUSE_SIG: {
QL 4:6189d844a1a2 245 status = Q_TRAN(&Table::serving);
QL 4:6189d844a1a2 246 break;
QL 4:6189d844a1a2 247 }
QL 4:6189d844a1a2 248 // @(/2/1/3/1/3/1)
QL 4:6189d844a1a2 249 case HUNGRY_SIG: {
QL 4:6189d844a1a2 250 uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
QL 4:6189d844a1a2 251 // philo ID must be in range and he must be not hungry
QL 4:6189d844a1a2 252 Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
QL 4:6189d844a1a2 253 me->m_isHungry[n] = true;
QL 4:6189d844a1a2 254 BSP_displayPhilStat(n, HUNGRY);
QL 4:6189d844a1a2 255 status = Q_HANDLED();
QL 4:6189d844a1a2 256 break;
QL 4:6189d844a1a2 257 }
QL 4:6189d844a1a2 258 // @(/2/1/3/1/3/2)
QL 4:6189d844a1a2 259 case DONE_SIG: {
QL 4:6189d844a1a2 260 uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
QL 4:6189d844a1a2 261 // phil ID must be in range and he must be not hungry
QL 4:6189d844a1a2 262 Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
QL 4:6189d844a1a2 263
QL 4:6189d844a1a2 264 BSP_displayPhilStat(n, THINKING);
QL 4:6189d844a1a2 265 uint8_t m = LEFT(n);
QL 4:6189d844a1a2 266 /* both forks of Phil[n] must be used */
QL 4:6189d844a1a2 267 Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
QL 4:6189d844a1a2 268
QL 4:6189d844a1a2 269 me->m_fork[m] = FREE;
QL 4:6189d844a1a2 270 me->m_fork[n] = FREE;
QL 4:6189d844a1a2 271 status = Q_HANDLED();
QL 4:6189d844a1a2 272 break;
QL 4:6189d844a1a2 273 }
QL 4:6189d844a1a2 274 default: {
QL 4:6189d844a1a2 275 status = Q_SUPER(&Table::active);
QL 4:6189d844a1a2 276 break;
QL 4:6189d844a1a2 277 }
QL 4:6189d844a1a2 278 }
QL 4:6189d844a1a2 279 return status;
QL 4:6189d844a1a2 280 }
QL 4:6189d844a1a2 281
QL 4:6189d844a1a2 282
QL 4:6189d844a1a2 283 } // namespace DPP