Quantum Leaps 33d17c2dbd 5.8.0
2016-11-30 18:14:20 -05:00

446 lines
14 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<model version="4.0.0" links="0">
<documentation>Dining Philosopher Problem example
NOTE: Requries QP5.</documentation>
<framework name="qpc"/>
<package name="Events" stereotype="0x01">
<class name="TableEvt" superclass="qpc::QEvt">
<attribute name="philoNum" type="uint8_t" visibility="0x00" properties="0x00"/>
</class>
</package>
<package name="AOs" stereotype="0x02">
<class name="Philo" superclass="qpc::QActive">
<attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
<statechart>
<initial target="../1">
<action>static uint8_t registered = (uint8_t)0; /* starts off with 0, per C-standard */
(void)e; /* suppress the compiler warning about unused parameter */
if (registered == (uint8_t)0) {
registered = (uint8_t)1;
QS_OBJ_DICTIONARY(&amp;l_philo[0]);
QS_OBJ_DICTIONARY(&amp;l_philo[0].timeEvt);
QS_OBJ_DICTIONARY(&amp;l_philo[1]);
QS_OBJ_DICTIONARY(&amp;l_philo[1].timeEvt);
QS_OBJ_DICTIONARY(&amp;l_philo[2]);
QS_OBJ_DICTIONARY(&amp;l_philo[2].timeEvt);
QS_OBJ_DICTIONARY(&amp;l_philo[3]);
QS_OBJ_DICTIONARY(&amp;l_philo[3].timeEvt);
QS_OBJ_DICTIONARY(&amp;l_philo[4]);
QS_OBJ_DICTIONARY(&amp;l_philo[4].timeEvt);
QS_FUN_DICTIONARY(&amp;Philo_initial);
QS_FUN_DICTIONARY(&amp;Philo_thinking);
QS_FUN_DICTIONARY(&amp;Philo_hungry);
QS_FUN_DICTIONARY(&amp;Philo_eating);
}
QS_SIG_DICTIONARY(HUNGRY_SIG, me); /* signal for each Philos */
QS_SIG_DICTIONARY(TIMEOUT_SIG, me); /* signal for each Philos */
QActive_subscribe(&amp;me-&gt;super, EAT_SIG);
QActive_subscribe(&amp;me-&gt;super, TEST_SIG);</action>
<initial_glyph conn="2,3,5,1,20,5,-3">
<action box="0,-2,6,2"/>
</initial_glyph>
</initial>
<state name="thinking">
<entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, THINK_TIME, 0U);</entry>
<exit>QTimeEvt_disarm(&amp;me-&gt;timeEvt);</exit>
<tran trig="TIMEOUT" target="../../2">
<tran_glyph conn="2,13,3,1,20,12,-3">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="EAT, DONE">
<action>/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
<tran_glyph conn="2,17,3,-1,13">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<tran trig="TEST">
<tran_glyph conn="2,20,3,-1,13">
<action box="0,-2,11,4"/>
</tran_glyph>
</tran>
<state_glyph node="2,5,17,16">
<entry box="1,2,5,2"/>
<exit box="1,4,6,2"/>
</state_glyph>
</state>
<state name="hungry">
<entry>TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe-&gt;philoNum = PHILO_ID(me);
QACTIVE_POST(AO_Table, &amp;pe-&gt;super, me);</entry>
<tran trig="EAT">
<choice target="../../../3">
<guard>Q_EVT_CAST(TableEvt)-&gt;philoNum == PHILO_ID(me)</guard>
<choice_glyph conn="15,30,5,1,7,13,-3">
<action box="1,0,19,4"/>
</choice_glyph>
</choice>
<tran_glyph conn="2,30,3,-1,13">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<tran trig="DONE">
<action>/* DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
<tran_glyph conn="2,36,3,-1,14">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,23,17,16">
<entry box="1,2,5,2"/>
</state_glyph>
</state>
<state name="eating">
<entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, EAT_TIME, 0U);</entry>
<exit>TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe-&gt;philoNum = PHILO_ID(me);
QF_PUBLISH(&amp;pe-&gt;super, me);</exit>
<tran trig="TIMEOUT" target="../../1">
<tran_glyph conn="2,51,3,1,22,-41,-5">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="EAT, DONE">
<action>/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
<tran_glyph conn="2,55,3,-1,13">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,41,17,18">
<entry box="1,2,5,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state_diagram size="37,61"/>
</statechart>
</class>
<class name="Table" superclass="qpc::QActive">
<attribute name="fork[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="isHungry[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
<statechart>
<initial target="../1/2">
<action>uint8_t n;
(void)e; /* suppress the compiler warning about unused parameter */
QS_OBJ_DICTIONARY(&amp;l_table);
QS_FUN_DICTIONARY(&amp;QHsm_top);
QS_FUN_DICTIONARY(&amp;Table_initial);
QS_FUN_DICTIONARY(&amp;Table_active);
QS_FUN_DICTIONARY(&amp;Table_serving);
QS_FUN_DICTIONARY(&amp;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(SERVE_SIG, (void *)0);
QS_SIG_DICTIONARY(TEST_SIG, (void *)0);
QS_SIG_DICTIONARY(HUNGRY_SIG, me); /* signal just for Table */
QActive_subscribe(&amp;me-&gt;super, DONE_SIG);
QActive_subscribe(&amp;me-&gt;super, PAUSE_SIG);
QActive_subscribe(&amp;me-&gt;super, SERVE_SIG);
QActive_subscribe(&amp;me-&gt;super, TEST_SIG);
for (n = 0U; n &lt; N_PHILO; ++n) {
me-&gt;fork[n] = FREE;
me-&gt;isHungry[n] = 0U;
BSP_displayPhilStat(n, &quot;thinking&quot;);
}</action>
<initial_glyph conn="3,3,5,1,44,18,-9">
<action box="0,-2,6,2"/>
</initial_glyph>
</initial>
<state name="active">
<tran trig="TEST">
<tran_glyph conn="2,11,3,-1,14">
<action box="0,-2,11,4"/>
</tran_glyph>
</tran>
<tran trig="EAT">
<action>Q_ERROR();</action>
<tran_glyph conn="2,15,3,-1,14">
<action box="0,-2,10,4"/>
</tran_glyph>
</tran>
<state name="serving">
<entry brief="give pending permissions to eat">uint8_t n;
for (n = 0U; n &lt; N_PHILO; ++n) { /* give permissions to eat... */
if ((me-&gt;isHungry[n] != 0U)
&amp;&amp; (me-&gt;fork[LEFT(n)] == FREE)
&amp;&amp; (me-&gt;fork[n] == FREE))
{
TableEvt *te;
me-&gt;fork[LEFT(n)] = USED;
me-&gt;fork[n] = USED;
te = Q_NEW(TableEvt, EAT_SIG);
te-&gt;philoNum = n;
QF_PUBLISH(&amp;te-&gt;super, me);
me-&gt;isHungry[n] = 0U;
BSP_displayPhilStat(n, &quot;eating &quot;);
}
}</entry>
<tran trig="HUNGRY">
<action>uint8_t n, m;
n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
BSP_displayPhilStat(n, &quot;hungry &quot;);
m = LEFT(n);</action>
<choice>
<guard brief="both free">(me-&gt;fork[m] == FREE) &amp;&amp; (me-&gt;fork[n] == FREE)</guard>
<action>TableEvt *pe;
me-&gt;fork[m] = USED;
me-&gt;fork[n] = USED;
pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoNum = n;
QF_PUBLISH(&amp;pe-&gt;super, me);
BSP_displayPhilStat(n, &quot;eating &quot;);</action>
<choice_glyph conn="19,26,5,-1,10">
<action box="1,0,10,2"/>
</choice_glyph>
</choice>
<choice>
<guard>else</guard>
<action>me-&gt;isHungry[n] = 1U;</action>
<choice_glyph conn="19,26,4,-1,5,10">
<action box="1,5,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,26,3,-1,15">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<tran trig="DONE">
<action>uint8_t n, m;
TableEvt *pe;
n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
BSP_displayPhilStat(n, &quot;thinking&quot;);
m = LEFT(n);
/* both forks of Phil[n] must be used */
Q_ASSERT((me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));
me-&gt;fork[m] = FREE;
me-&gt;fork[n] = FREE;
m = RIGHT(n); /* check the right neighbor */
if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[m] == FREE)) {
me-&gt;fork[n] = USED;
me-&gt;fork[m] = USED;
me-&gt;isHungry[m] = 0U;
pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoNum = m;
QF_PUBLISH(&amp;pe-&gt;super, me);
BSP_displayPhilStat(m, &quot;eating &quot;);
}
m = LEFT(n); /* check the left neighbor */
n = LEFT(m); /* left fork of the left neighbor */
if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[n] == FREE)) {
me-&gt;fork[m] = USED;
me-&gt;fork[n] = USED;
me-&gt;isHungry[m] = 0U;
pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoNum = m;
QF_PUBLISH(&amp;pe-&gt;super, me);
BSP_displayPhilStat(m, &quot;eating &quot;);
}</action>
<tran_glyph conn="4,34,3,-1,15">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="EAT">
<action>Q_ERROR();</action>
<tran_glyph conn="4,37,3,-1,15">
<action box="0,-2,12,4"/>
</tran_glyph>
</tran>
<tran trig="PAUSE" target="../../3">
<tran_glyph conn="4,41,3,1,37,6,-3">
<action box="0,-2,7,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,19,34,24">
<entry box="1,2,27,2"/>
</state_glyph>
</state>
<state name="paused">
<entry>BSP_displayPaused(1U);</entry>
<exit>BSP_displayPaused(0U);</exit>
<tran trig="SERVE" target="../../2">
<tran_glyph conn="4,57,3,1,39,-20,-5">
<action box="0,-2,7,2"/>
</tran_glyph>
</tran>
<tran trig="HUNGRY">
<action>uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* philo ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
me-&gt;isHungry[n] = 1U;
BSP_displayPhilStat(n, &quot;hungry &quot;);</action>
<tran_glyph conn="4,60,3,-1,15">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="DONE">
<action>uint8_t n, m;
n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
BSP_displayPhilStat(n, &quot;thinking&quot;);
m = LEFT(n);
/* both forks of Phil[n] must be used */
Q_ASSERT((me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));
me-&gt;fork[m] = FREE;
me-&gt;fork[n] = FREE;</action>
<tran_glyph conn="4,63,3,-1,15">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,45,34,20">
<entry box="1,2,18,4"/>
<exit box="1,6,18,4"/>
</state_glyph>
</state>
<state_glyph node="2,5,43,62"/>
</state>
<state_diagram size="49,69"/>
</statechart>
</class>
<attribute name="AO_Philo[N_PHILO]" type="QMActive * const" visibility="0x00" properties="0x00"/>
<attribute name="AO_Table" type="QActive * const" visibility="0x00" properties="0x00"/>
<operation name="Philo_ctor" type="void" visibility="0x00" properties="0x00">
<code>uint8_t n;
Philo *me;
for (n = 0U; n &lt; N_PHILO; ++n) {
me = &amp;l_philo[n];
QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Philo_initial));
QTimeEvt_ctorX(&amp;me-&gt;timeEvt, &amp;me-&gt;super, TIMEOUT_SIG, 0U);
}</code>
</operation>
<operation name="Table_ctor" type="void" visibility="0x00" properties="0x00">
<code>uint8_t n;
Table *me = &amp;l_table;
QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Table_initial));
for (n = 0U; n &lt; N_PHILO; ++n) {
me-&gt;fork[n] = FREE;
me-&gt;isHungry[n] = 0U;
}</code>
</operation>
</package>
<directory name=".">
<file name="dpp.h">
<text>#ifndef dpp_h
#define dpp_h
enum DPPSignals {
EAT_SIG = 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 serving forks */
SERVE_SIG, /* published by BSP to serve re-start serving forks */
TEST_SIG, /* published by BSP to test the application */
MAX_PUB_SIG, /* the last published signal */
HUNGRY_SIG, /* posted direclty to Table from hungry Philo */
TIMEOUT_SIG, /* used by Philosophers for time events */
MAX_SIG /* the last signal */
};
$declare(Events::TableEvt)
/* number of philosophers */
#define N_PHILO ((uint8_t)5)
$declare(AOs::Philo_ctor)
$declare(AOs::AO_Philo[N_PHILO])
$declare(AOs::Table_ctor)
$declare(AOs::AO_Table)
#ifdef qxk_h
void Test1_ctor(void);
extern QXThread * const XT_Test1;
void Test2_ctor(void);
extern QXThread * const XT_Test2;
#endif /* qxk_h */
#endif /* dpp_h */</text>
</file>
<file name="philo.c">
<text>#include &quot;qpc.h&quot;
#include &quot;dpp.h&quot;
#include &quot;bsp.h&quot;
Q_DEFINE_THIS_FILE
/* Active object class -----------------------------------------------------*/
$declare(AOs::Philo)
/* Local objects -----------------------------------------------------------*/
static Philo l_philo[N_PHILO]; /* storage for all Philos */
#define THINK_TIME \
(QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + (BSP_TICKS_PER_SEC/2U))
#define EAT_TIME \
(QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + BSP_TICKS_PER_SEC)
/* helper macro to provide the ID of Philo &quot;me_&quot; */
#define PHILO_ID(me_) ((uint8_t)((me_) - l_philo))
/* Global objects ----------------------------------------------------------*/
QMActive * const AO_Philo[N_PHILO] = { /* &quot;opaque&quot; pointers to Philo AO */
&amp;l_philo[0].super,
&amp;l_philo[1].super,
&amp;l_philo[2].super,
&amp;l_philo[3].super,
&amp;l_philo[4].super
};
/* Philo definition --------------------------------------------------------*/
$define(AOs::Philo_ctor)
$define(AOs::Philo)</text>
</file>
<file name="table.c">
<text>#include &quot;qpc.h&quot;
#include &quot;dpp.h&quot;
#include &quot;bsp.h&quot;
Q_DEFINE_THIS_FILE
/* Active object class -----------------------------------------------------*/
$declare(AOs::Table)
#define RIGHT(n_) ((uint8_t)(((n_) + (N_PHILO - 1U)) % N_PHILO))
#define LEFT(n_) ((uint8_t)(((n_) + 1U) % N_PHILO))
#define FREE ((uint8_t)0)
#define USED ((uint8_t)1)
/* Local objects -----------------------------------------------------------*/
static Table l_table; /* the single instance of the Table active object */
/* Global-scope objects ----------------------------------------------------*/
QMActive * const AO_Table = &amp;l_table.super; /* &quot;opaque&quot; AO pointer */
/*..........................................................................*/
$define(AOs::Table_ctor)
$define(AOs::Table)</text>
</file>
</directory>
</model>