Dining Philosopher Problem example with MSM state machines
: QMActive(Q_STATE_CAST(&Philo::initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U)
static bool registered = false; // starts off with 0, per C-standard
(void)e; // suppress the compiler warning about unused parameter
if (!registered) {
registered = true;
QS_OBJ_DICTIONARY(&l_philo[0]);
QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt);
QS_OBJ_DICTIONARY(&l_philo[1]);
QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt);
QS_OBJ_DICTIONARY(&l_philo[2]);
QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt);
QS_OBJ_DICTIONARY(&l_philo[3]);
QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt);
QS_OBJ_DICTIONARY(&l_philo[4]);
QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt);
QS_FUN_DICTIONARY(&Philo::initial);
QS_FUN_DICTIONARY(&Philo::thinking);
QS_FUN_DICTIONARY(&Philo::hungry);
QS_FUN_DICTIONARY(&Philo::eating);
}
QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal for each Philos
QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos
me->subscribe(EAT_SIG);
me->m_timeEvt.armX(think_time(), 0U);
(void)me->m_timeEvt.disarm();
/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe->philoNum = PHILO_ID(me);
AO_Table->POST(pe, me);
Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(me)
/* DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
me->m_timeEvt.armX(eat_time(), 0U);
TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe->philoNum = PHILO_ID(me);
QP::QF::PUBLISH(pe, me);
(void)me->m_timeEvt.disarm();
/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
: QMActive(Q_STATE_CAST(&Table::initial))
for (uint8_t n = 0U; n < N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
}
(void)e; // suppress the compiler warning about unused parameter
QS_OBJ_DICTIONARY(&l_table);
QS_FUN_DICTIONARY(&QP::QHsm::top);
QS_FUN_DICTIONARY(&Table::initial);
QS_FUN_DICTIONARY(&Table::active);
QS_FUN_DICTIONARY(&Table::serving);
QS_FUN_DICTIONARY(&Table::paused);
QS_SIG_DICTIONARY(DONE_SIG, (void *)0); // global signals
QS_SIG_DICTIONARY(EAT_SIG, (void *)0);
QS_SIG_DICTIONARY(PAUSE_SIG, (void *)0);
QS_SIG_DICTIONARY(TERMINATE_SIG, (void *)0);
QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal just for Table
me->subscribe(DONE_SIG);
me->subscribe(PAUSE_SIG);
me->subscribe(TERMINATE_SIG);
for (uint8_t n = 0U; n < N_PHILO; ++n) {
me->m_fork[n] = FREE;
me->m_isHungry[n] = false;
BSP_displayPhilStat(n, THINKING);
}
BSP_terminate(0);
Q_ERROR();
for (uint8_t n = 0U; n < N_PHILO; ++n) { // give permissions to eat...
if (me->m_isHungry[n]
&& (me->m_fork[LEFT(n)] == FREE)
&& (me->m_fork[n] == FREE))
{
me->m_fork[LEFT(n)] = USED;
me->m_fork[n] = USED;
TableEvt *te = Q_NEW(TableEvt, EAT_SIG);
te->philoNum = n;
QP::QF::PUBLISH(te, me);
me->m_isHungry[n] = false;
BSP_displayPhilStat(n, EATING);
}
}
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
BSP_displayPhilStat(n, HUNGRY);
uint8_t m = LEFT(n);
(me->m_fork[m] == FREE) && (me->m_fork[n] == FREE)
me->m_fork[m] = USED;
me->m_fork[n] = USED;
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoNum = n;
QP::QF::PUBLISH(pe, me);
BSP_displayPhilStat(n, EATING);
else
me->m_isHungry[n] = true;
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
BSP_displayPhilStat(n, THINKING);
uint8_t m = LEFT(n);
// both forks of Phil[n] must be used
Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
me->m_fork[m] = FREE;
me->m_fork[n] = FREE;
m = RIGHT(n); // check the right neighbor
if (me->m_isHungry[m] && (me->m_fork[m] == FREE)) {
me->m_fork[n] = USED;
me->m_fork[m] = USED;
me->m_isHungry[m] = false;
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoNum = m;
QP::QF::PUBLISH(pe, me);
BSP_displayPhilStat(m, EATING);
}
m = LEFT(n); // check the left neighbor
n = LEFT(m); // left fork of the left neighbor
if (me->m_isHungry[m] && (me->m_fork[n] == FREE)) {
me->m_fork[m] = USED;
me->m_fork[n] = USED;
me->m_isHungry[m] = false;
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoNum = m;
QP::QF::PUBLISH(pe, me);
BSP_displayPhilStat(m, EATING);
}
Q_ERROR();
BSP_displayPaused(1U);
BSP_displayPaused(0U);
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// philo ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
me->m_isHungry[n] = true;
BSP_displayPhilStat(n, HUNGRY);
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
BSP_displayPhilStat(n, THINKING);
uint8_t m = LEFT(n);
/* both forks of Phil[n] must be used */
Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
me->m_fork[m] = FREE;
me->m_fork[n] = FREE;
#ifndef dpp_h
#define dpp_h
namespace DPP {
enum DPPSignals {
EAT_SIG = QP::Q_USER_SIG, // published by Table to let a philosopher eat
DONE_SIG, // published by Philosopher when done eating
PAUSE_SIG, // published by BSP to pause the application
TERMINATE_SIG, // published by BSP to terminate the application
MAX_PUB_SIG, // the last published signal
HUNGRY_SIG, // posted direclty to Table from hungry Philo
MAX_SIG // the last signal
};
} // namespace DPP
$declare(Events::TableEvt)
// number of philosophers
#define N_PHILO ((uint8_t)5)
$declare(AOs::AO_Philo[N_PHILO])
$declare(AOs::AO_Table)
#endif // dpp_h
#include "qp_port.h"
#include "dpp.h"
#include "bsp.h"
Q_DEFINE_THIS_FILE
// Active object class -------------------------------------------------------
$declare(AOs::Philo)
namespace DPP {
// Local objects -------------------------------------------------------------
static Philo l_philo[N_PHILO]; // storage for all Philos
// helper function to provide a randomized think time for Philos
inline QP::QTimeEvtCtr think_time() {
return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC)
+ (BSP_TICKS_PER_SEC/2U));
}
// helper function to provide a randomized eat time for Philos
inline QP::QTimeEvtCtr eat_time() {
return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC)
+ BSP_TICKS_PER_SEC);
}
// helper function to provide the ID of Philo "me"
inline uint8_t PHILO_ID(Philo const * const me) {
return static_cast<uint8_t>(me - l_philo);
}
enum InternalSignals { // internal signals
TIMEOUT_SIG = MAX_SIG
};
// Global objects ------------------------------------------------------------
QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO
&l_philo[0],
&l_philo[1],
&l_philo[2],
&l_philo[3],
&l_philo[4]
};
} // namespace DPP
// Philo definition ----------------------------------------------------------
$define(AOs::Philo)
#include "qp_port.h"
#include "dpp.h"
#include "bsp.h"
Q_DEFINE_THIS_FILE
// Active object class -------------------------------------------------------
$declare(AOs::Table)
namespace DPP {
// helper function to provide the RIGHT neighbour of a Philo[n]
inline uint8_t RIGHT(uint8_t const n) {
return static_cast<uint8_t>((n + (N_PHILO - 1U)) % N_PHILO);
}
// helper function to provide the LEFT neighbour of a Philo[n]
inline uint8_t LEFT(uint8_t const n) {
return static_cast<uint8_t>((n + 1U) % N_PHILO);
}
static uint8_t const FREE = static_cast<uint8_t>(0);
static uint8_t const USED = static_cast<uint8_t>(1);
static char_t const * const THINKING = &"thinking"[0];
static char_t const * const HUNGRY = &"hungry "[0];
static char_t const * const EATING = &"eating "[0];
// Local objects -------------------------------------------------------------
static Table l_table; // the single instance of the Table active object
// Global-scope objects ------------------------------------------------------
QP::QActive * const AO_Table = &l_table; // "opaque" AO pointer
} // namespace DPP
//............................................................................
$define(AOs::Table)