ref: ad1df2d2a01bd064e643287ff305673dfede3ce3
dir: /dpp.qm/
<?xml version="1.0" encoding="UTF-8"?> <model version="5.2.5" links="1"> <documentation>Dining Philosopher Problem example</documentation> <!--${qpc}--> <framework name="qpc"/> <!--${Events}--> <package name="Events" stereotype="0x01"> <!--${Events::TableEvt}--> <class name="TableEvt" superclass="qpc::QEvt"> <!--${Events::TableEvt::philoNum}--> <attribute name="philoNum" type="uint8_t" visibility="0x00" properties="0x00"/> </class> </package> <!--${AOs}--> <package name="AOs" stereotype="0x02"> <!--${AOs::Philo}--> <class name="Philo" superclass="qpc::QActive"> <!--${AOs::Philo::inst[N_PHILO]}--> <attribute name="inst[N_PHILO]" type="Philo" visibility="0x00" properties="0x01"> <documentation>The array of static insts of the Philo class (Singleton pattern)</documentation> </attribute> <!--${AOs::Philo::timeEvt}--> <attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/> <!--${AOs::Philo::SM}--> <statechart properties="0x01"> <!--${AOs::Philo::SM::initial}--> <initial target="../1"> <action>static uint8_t registered = (uint8_t)0; /* starts off with 0, per C-standard */ (void)par; /* unused parameter */ // Here's a start: if (registered == (uint8_t)0) { registered = (uint8_t)1; QS_OBJ_DICTIONARY(&Philo_inst[0]); QS_OBJ_DICTIONARY(&Philo_inst[0].timeEvt); QS_OBJ_DICTIONARY(&Philo_inst[1]); QS_OBJ_DICTIONARY(&Philo_inst[1].timeEvt); QS_OBJ_DICTIONARY(&Philo_inst[2]); QS_OBJ_DICTIONARY(&Philo_inst[2].timeEvt); QS_OBJ_DICTIONARY(&Philo_inst[3]); QS_OBJ_DICTIONARY(&Philo_inst[3].timeEvt); QS_OBJ_DICTIONARY(&Philo_inst[4]); QS_OBJ_DICTIONARY(&Philo_inst[4].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 */ QActive_subscribe(&me->super, EAT_SIG); QActive_subscribe(&me->super, TEST_SIG);</action> <initial_glyph conn="2,3,5,1,20,5,-3"> <action box="0,-2,6,2"/> </initial_glyph> </initial> <!--${AOs::Philo::SM::thinking}--> <state name="thinking"> <entry>QTimeEvt_armX(&me->timeEvt, THINK_TIME, 0U);</entry> <exit>QTimeEvt_disarm(&me->timeEvt);</exit> <!--${AOs::Philo::SM::thinking::TIMEOUT}--> <tran trig="TIMEOUT" target="../../2"> <tran_glyph conn="2,13,3,1,20,12,-3"> <action box="0,-2,6,2"/> </tran_glyph> </tran> <!--${AOs::Philo::SM::thinking::EAT, DONE}--> <tran trig="EAT, DONE"> <action>/* EAT or DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));</action> <tran_glyph conn="2,17,3,-1,13"> <action box="0,-2,14,2"/> </tran_glyph> </tran> <!--${AOs::Philo::SM::thinking::TEST}--> <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> <!--${AOs::Philo::SM::hungry}--> <state name="hungry"> <entry>TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG); pe->philoNum = PHILO_ID(me); QACTIVE_POST(AO_Table, &pe->super, me);</entry> <!--${AOs::Philo::SM::hungry::EAT}--> <tran trig="EAT"> <!--${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~}--> <choice target="../../../3"> <guard>Q_EVT_CAST(TableEvt)->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> <!--${AOs::Philo::SM::hungry::DONE}--> <tran trig="DONE"> <action>/* DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->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> <!--${AOs::Philo::SM::eating}--> <state name="eating"> <entry>QTimeEvt_armX(&me->timeEvt, EAT_TIME, 0U);</entry> <exit>TableEvt *pe = Q_NEW(TableEvt, DONE_SIG); pe->philoNum = PHILO_ID(me); QACTIVE_PUBLISH(&pe->super, &me->super);</exit> <!--${AOs::Philo::SM::eating::TIMEOUT}--> <tran trig="TIMEOUT" target="../../1"> <tran_glyph conn="2,51,3,1,22,-41,-5"> <action box="0,-2,6,2"/> </tran_glyph> </tran> <!--${AOs::Philo::SM::eating::EAT, DONE}--> <tran trig="EAT, DONE"> <action>/* EAT or DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->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> <!--${AOs::Table}--> <class name="Table" superclass="qpc::QActive"> <!--${AOs::Table::inst}--> <attribute name="inst" type="Table" visibility="0x00" properties="0x01"> <documentation>The only static inst of the Table class (Singleton pattern)</documentation> </attribute> <!--${AOs::Table::fork[N_PHILO]}--> <attribute name="fork[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/> <!--${AOs::Table::isHungry[N_PHILO]}--> <attribute name="isHungry[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/> <!--${AOs::Table::SM}--> <statechart properties="0x03"> <!--${AOs::Table::SM::initial}--> <initial target="../1/2"> <action>uint8_t n; (void)par; /* unused parameter */ QS_OBJ_DICTIONARY(&Table_inst); 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(&me->super, DONE_SIG); QActive_subscribe(&me->super, PAUSE_SIG); QActive_subscribe(&me->super, SERVE_SIG); QActive_subscribe(&me->super, TEST_SIG); for (n = 0U; n < N_PHILO; ++n) { me->fork[n] = FREE; me->isHungry[n] = 0U; BSP_displayPhilStat(n, "thinking"); }</action> <initial_glyph conn="3,3,5,1,44,18,-9"> <action box="0,-2,6,2"/> </initial_glyph> </initial> <!--${AOs::Table::SM::active}--> <state name="active"> <!--${AOs::Table::SM::active::TEST}--> <tran trig="TEST"> <tran_glyph conn="2,11,3,-1,14"> <action box="0,-2,11,4"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::EAT}--> <tran trig="EAT"> <action>Q_ERROR();</action> <tran_glyph conn="2,15,3,-1,14"> <action box="0,-2,10,4"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::serving}--> <state name="serving"> <entry brief="give pending permissions to eat">uint8_t n; for (n = 0U; n < N_PHILO; ++n) { /* give permissions to eat... */ if ((me->isHungry[n] != 0U) && (me->fork[LEFT(n)] == FREE) && (me->fork[n] == FREE)) { TableEvt *te; me->fork[LEFT(n)] = USED; me->fork[n] = USED; te = Q_NEW(TableEvt, EAT_SIG); te->philoNum = n; QACTIVE_PUBLISH(&te->super, &me->super); me->isHungry[n] = 0U; BSP_displayPhilStat(n, "eating "); } }</entry> <!--${AOs::Table::SM::active::serving::HUNGRY}--> <tran trig="HUNGRY"> <action>uint8_t n, m; n = Q_EVT_CAST(TableEvt)->philoNum; /* phil ID must be in range and he must be not hungry */ Q_ASSERT((n < N_PHILO) && (me->isHungry[n] == 0U)); BSP_displayPhilStat(n, "hungry "); m = LEFT(n);</action> <!--${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}--> <choice> <guard brief="both free">(me->fork[m] == FREE) && (me->fork[n] == FREE)</guard> <action>TableEvt *pe; me->fork[m] = USED; me->fork[n] = USED; pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = n; QACTIVE_PUBLISH(&pe->super, &me->super); BSP_displayPhilStat(n, "eating ");</action> <choice_glyph conn="19,26,5,-1,10"> <action box="1,0,10,2"/> </choice_glyph> </choice> <!--${AOs::Table::SM::active::serving::HUNGRY::[else]}--> <choice> <guard>else</guard> <action>me->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> <!--${AOs::Table::SM::active::serving::DONE}--> <tran trig="DONE"> <action>uint8_t n, m; TableEvt *pe; n = Q_EVT_CAST(TableEvt)->philoNum; /* phil ID must be in range and he must be not hungry */ Q_ASSERT((n < N_PHILO) && (me->isHungry[n] == 0U)); BSP_displayPhilStat(n, "thinking"); m = LEFT(n); /* both forks of Phil[n] must be used */ Q_ASSERT((me->fork[n] == USED) && (me->fork[m] == USED)); me->fork[m] = FREE; me->fork[n] = FREE; m = RIGHT(n); /* check the right neighbor */ if ((me->isHungry[m] != 0U) && (me->fork[m] == FREE)) { me->fork[n] = USED; me->fork[m] = USED; me->isHungry[m] = 0U; pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = m; QACTIVE_PUBLISH(&pe->super, &me->super); BSP_displayPhilStat(m, "eating "); } m = LEFT(n); /* check the left neighbor */ n = LEFT(m); /* left fork of the left neighbor */ if ((me->isHungry[m] != 0U) && (me->fork[n] == FREE)) { me->fork[m] = USED; me->fork[n] = USED; me->isHungry[m] = 0U; pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = m; QACTIVE_PUBLISH(&pe->super, &me->super); BSP_displayPhilStat(m, "eating "); }</action> <tran_glyph conn="4,34,3,-1,15"> <action box="0,-2,6,2"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::serving::EAT}--> <tran trig="EAT"> <action>Q_ERROR();</action> <tran_glyph conn="4,37,3,-1,15"> <action box="0,-2,12,4"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::serving::PAUSE}--> <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> <!--${AOs::Table::SM::active::paused}--> <state name="paused"> <entry>BSP_displayPaused(1U);</entry> <exit>BSP_displayPaused(0U);</exit> <!--${AOs::Table::SM::active::paused::SERVE}--> <tran trig="SERVE" target="../../2"> <tran_glyph conn="4,57,3,1,39,-20,-5"> <action box="0,-2,7,2"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::paused::HUNGRY}--> <tran trig="HUNGRY"> <action>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->isHungry[n] == 0U)); me->isHungry[n] = 1U; BSP_displayPhilStat(n, "hungry ");</action> <tran_glyph conn="4,60,3,-1,15"> <action box="0,-2,6,2"/> </tran_glyph> </tran> <!--${AOs::Table::SM::active::paused::DONE}--> <tran trig="DONE"> <action>uint8_t n, m; n = Q_EVT_CAST(TableEvt)->philoNum; /* phil ID must be in range and he must be not hungry */ Q_ASSERT((n < N_PHILO) && (me->isHungry[n] == 0U)); BSP_displayPhilStat(n, "thinking"); m = LEFT(n); /* both forks of Phil[n] must be used */ Q_ASSERT((me->fork[n] == USED) && (me->fork[m] == USED)); me->fork[m] = FREE; me->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> <!--${AOs::AO_Philo[N_PHILO]}--> <attribute name="AO_Philo[N_PHILO]" type="QActive * const" visibility="0x00" properties="0x00"> <code>= { /* "opaque" pointers to Philo AO */ &Philo_inst[0].super, &Philo_inst[1].super, &Philo_inst[2].super, &Philo_inst[3].super, &Philo_inst[4].super };</code> </attribute> <!--${AOs::AO_Table}--> <attribute name="AO_Table" type="QActive * const" visibility="0x00" properties="0x00"> <code>= &Table_inst.super; /* "opaque" pointer to Table AO */</code> </attribute> <!--${AOs::Philo_ctor}--> <operation name="Philo_ctor" type="void" visibility="0x00" properties="0x00"> <code>uint8_t n; Philo *me; for (n = 0U; n < N_PHILO; ++n) { me = &Philo_inst[n]; QActive_ctor(&me->super, Q_STATE_CAST(&Philo_initial)); QTimeEvt_ctorX(&me->timeEvt, &me->super, TIMEOUT_SIG, 0U); }</code> </operation> <!--${AOs::Table_ctor}--> <operation name="Table_ctor" type="void" visibility="0x00" properties="0x00"> <code>Table *me = &Table_inst; uint8_t n; QActive_ctor(&me->super, Q_STATE_CAST(&Table_initial)); for (n = 0U; n < N_PHILO; ++n) { me->fork[n] = FREE; me->isHungry[n] = 0U; }</code> </operation> </package> <!--${src}--> <directory name="src"> <!--${src::dpp.h}--> <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> <!--${src::philo.c}--> <file name="philo.c"> <text>#include "qpc.h" #include "dpp.h" #include "bsp.h" Q_DEFINE_THIS_FILE /* Active object class -----------------------------------------------------*/ $declare${AOs::Philo} #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 "me_" */ #define PHILO_ID(me_) ((uint8_t)((me_) - &Philo_inst[0])) $define${AOs::AO_Philo[N_PHILO]} $define${AOs::Philo_ctor} $define${AOs::Philo}</text> </file> <!--${src::table.c}--> <file name="table.c"> <text>#include "qpc.h" #include "dpp.h" #include "bsp.h" 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) $define${AOs::AO_Table} $define${AOs::Table_ctor} $define${AOs::Table}</text> </file> </directory> </model>