2023-12-14 16:55:58 -05:00

729 lines
25 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<model version="5.3.0" links="1">
<documentation>Dining Philosopher Problem example with MPU isolation</documentation>
<!--${qpcpp}-->
<framework name="qpcpp"/>
<!--${Shared}-->
<package name="Shared" stereotype="0x01" namespace="APP::">
<!--${Shared::AppSignals}-->
<attribute name="AppSignals" type="enum" visibility="0x04" properties="0x00">
<code>: QP::QSignal {
EAT_SIG = QP::Q_USER_SIG, // published by Table to let a Philo eat
DONE_SIG, // published by Philo when done eating
PAUSE_SIG, // published by BSP to pause the application
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
TIMEOUT_SIG, // posted by time event to Philo
HUNGRY_SIG, // posted by hungry Philo to Table
MAX_SIG // the last signal
};</code>
</attribute>
<!--${Shared::produce_sig_dict}-->
<operation name="produce_sig_dict?def Q_SPY" type="void" visibility="0x00" properties="0x02">
<code>QS_SIG_DICTIONARY(EAT_SIG, nullptr);
QS_SIG_DICTIONARY(DONE_SIG, nullptr);
QS_SIG_DICTIONARY(PAUSE_SIG, nullptr);
QS_SIG_DICTIONARY(SERVE_SIG, nullptr);
QS_SIG_DICTIONARY(TEST_SIG, nullptr);
QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr);
QS_SIG_DICTIONARY(HUNGRY_SIG, nullptr);</code>
</operation>
<!--${Shared::N_PHILO}-->
<attribute name="N_PHILO" type="constexpr std::uint8_t" visibility="0x04" properties="0x00">
<code>{5};</code>
</attribute>
<!--${Shared::TableEvt}-->
<class name="TableEvt" superclass="qpcpp::QEvt">
<!--${Shared::TableEvt::philoId}-->
<attribute name="philoId" type="std::uint8_t" visibility="0x00" properties="0x00"/>
<!--${Shared::TableEvt::TableEvt}-->
<operation name="TableEvt" type="constexpr" visibility="0x00" properties="0x02">
<!--${Shared::TableEvt::TableEvt::sig}-->
<parameter name="sig" type="QP::QSignal"/>
<!--${Shared::TableEvt::TableEvt::id}-->
<parameter name="id" type="std::uint8_t"/>
<code> : QEvt(sig),
philoId(id)</code>
</operation>
<!--${Shared::TableEvt::TableEvt}-->
<operation name="TableEvt?def QEVT_DYN_CTOR" type="" visibility="0x00" properties="0x02">
<!--${Shared::TableEvt::TableEvt::id}-->
<parameter name="id" type="std::uint8_t"/>
<code> : QEvt(QP::QEvt::DYNAMIC),
philoId(id)</code>
</operation>
</class>
<!--${Shared::AO_Philo[N_PHILO]}-->
<attribute name="AO_Philo[N_PHILO]" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<!--${Shared::Philo_ctor}-->
<operation name="Philo_ctor" type="void" visibility="0x00" properties="0x00">
<!--${Shared::Philo_ctor::id}-->
<parameter name="id" type="std::uint_fast8_t const"/>
<!--${Shared::Philo_ctor::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${Shared::Philo_ctor::size}-->
<parameter name="size" type="std::uint32_t const"/>
<!--${Shared::Philo_ctor::mpu = nullptr}-->
<parameter name="mpu = nullptr" type="void const * const"/>
<code>Q_REQUIRE(sizeof(Philo) &lt;= size);
// run the constructor through placemen new()
auto me = new(sto) Philo(id);
me-&gt;setThread(mpu);</code>
</operation>
<!--${Shared::AO_Table}-->
<attribute name="AO_Table" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<!--${Shared::Table_ctor}-->
<operation name="Table_ctor" type="void" visibility="0x00" properties="0x00">
<!--${Shared::Table_ctor::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${Shared::Table_ctor::size}-->
<parameter name="size" type="std::uint32_t const"/>
<!--${Shared::Table_ctor::mpu = nullptr}-->
<parameter name="mpu = nullptr" type="void const * const"/>
<code>Q_REQUIRE(sizeof(Table) &lt;= size);
// run the constructor through placemen new()
auto me = new(sto) Table();
me-&gt;setThread(mpu);</code>
</operation>
</package>
<!--${Shared-TH}-->
<package name="Shared-TH" stereotype="0x02" namespace="APP::">
<!--${Shared-TH::TH_XThread1}-->
<attribute name="TH_XThread1" type="QP::QXThread * const" visibility="0x00" properties="0x00"/>
<!--${Shared-TH::XThread1_ctor}-->
<operation name="XThread1_ctor" type="void" visibility="0x00" properties="0x00">
<!--${Shared-TH::XThread1_ctor::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${Shared-TH::XThread1_ctor::size}-->
<parameter name="size" type="std::uint32_t const"/>
<!--${Shared-TH::XThread1_ctor::mpu = nullptr}-->
<parameter name="mpu = nullptr" type="void const * const"/>
<code>Q_REQUIRE(sizeof(XThread1) &lt;= size);
// run the constructor through placement new()
auto me = new(sto) XThread1();
me-&gt;setThread(mpu);</code>
</operation>
<!--${Shared-TH::TH_XThread2}-->
<attribute name="TH_XThread2" type="QP::QXThread * const" visibility="0x00" properties="0x00"/>
<!--${Shared-TH::XThread2_ctor}-->
<operation name="XThread2_ctor" type="void" visibility="0x00" properties="0x00">
<!--${Shared-TH::XThread2_ctor::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${Shared-TH::XThread2_ctor::size}-->
<parameter name="size" type="std::uint32_t const"/>
<!--${Shared-TH::XThread2_ctor::mpu = nullptr}-->
<parameter name="mpu = nullptr" type="void const * const"/>
<code>Q_REQUIRE(sizeof(XThread2) &lt;= size);
// run the constructor through placement new()
auto me = new(sto) XThread2();
me-&gt;setThread(mpu);</code>
</operation>
<!--${Shared-TH::TH_sema}-->
<attribute name="TH_sema" type="QP::QXSemaphore" visibility="0x00" properties="0x00">
<documentation>// NOTE: kernel objects can be allocated outside any memory regions
// accessible to the threads.</documentation>
</attribute>
<!--${Shared-TH::TH_mutex}-->
<attribute name="TH_mutex" type="QP::QXMutex" visibility="0x00" properties="0x00">
<documentation>// NOTE: kernel objects can be allocated outside any memory regions
// accessible to the threads.</documentation>
</attribute>
<!--${Shared-TH::TH_obj_dict}-->
<operation name="TH_obj_dict?def Q_SPY" type="void" visibility="0x00" properties="0x00">
<code>QS_OBJ_DICTIONARY(TH_XThread1);
QS_OBJ_DICTIONARY(TH_XThread1-&gt;getTimeEvt());
QS_OBJ_DICTIONARY(TH_XThread2);
QS_OBJ_DICTIONARY(TH_XThread2-&gt;getTimeEvt());
QS_OBJ_DICTIONARY(&amp;TH_sema);
QS_OBJ_DICTIONARY(&amp;TH_mutex);</code>
</operation>
</package>
<!--${AOs}-->
<package name="AOs" stereotype="0x02" namespace="APP::">
<!--${AOs::Philo}-->
<class name="Philo" superclass="qpcpp::QActive">
<documentation>The Philo AO and the N_PHILO instances</documentation>
<!--${AOs::Philo::m_timeEvt}-->
<attribute name="m_timeEvt" type="QP::QTimeEvt" visibility="0x02" properties="0x00"/>
<!--${AOs::Philo::m_id}-->
<attribute name="m_id" type="std::uint8_t" visibility="0x02" properties="0x00"/>
<!--${AOs::Philo::Philo}-->
<operation name="Philo" type="" visibility="0x00" properties="0x00">
<!--${AOs::Philo::Philo::id}-->
<parameter name="id" type="std::uint_fast8_t const"/>
<code> : QActive(Q_STATE_CAST(&amp;Philo::initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U),
m_id(static_cast&lt;std::uint8_t&gt;(id))</code>
</operation>
<!--${AOs::Philo::SM}-->
<statechart properties="0x02">
<!--${AOs::Philo::SM::initial}-->
<initial target="../1">
<action>Q_UNUSED_PAR(e);
#ifdef Q_SPY
Philo *Philo_inst = this;
QS_OBJ_ARR_DICTIONARY(Philo_inst, m_id);
QS_OBJ_ARR_DICTIONARY(&amp;Philo_inst-&gt;m_timeEvt, m_id);
#endif
subscribe(EAT_SIG);
subscribe(TEST_SIG);</action>
<initial_glyph conn="2,4,5,1,20,7,-2">
<action box="0,-2,6,2"/>
</initial_glyph>
</initial>
<!--${AOs::Philo::SM::thinking}-->
<state name="thinking">
<entry>m_timeEvt.armX(think_time(), 0U);</entry>
<exit>(void)m_timeEvt.disarm();</exit>
<!--${AOs::Philo::SM::thinking::TIMEOUT}-->
<tran trig="TIMEOUT" target="../../2">
<tran_glyph conn="2,16,3,1,20,14,-2">
<action box="0,-2,12,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)-&gt;philoId != m_id);</action>
<tran_glyph conn="2,20,3,-1,14">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<!--${AOs::Philo::SM::thinking::TEST}-->
<tran trig="TEST">
<tran_glyph conn="2,24,3,-1,14">
<action box="0,-2,11,4"/>
</tran_glyph>
</tran>
<state_glyph node="2,6,18,20">
<entry box="1,2,5,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<!--${AOs::Philo::SM::hungry}-->
<state name="hungry">
<entry>#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, HUNGRY_SIG, m_id);
#else
TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe-&gt;philoId = m_id;
#endif
AO_Table-&gt;POST(pe, this);</entry>
<!--${AOs::Philo::SM::hungry::EAT}-->
<tran trig="EAT">
<!--${AOs::Philo::SM::hungry::EAT::[e->philoId==m_id]}-->
<choice target="../../../3">
<guard brief="e-&gt;philoId == m_id">Q_EVT_CAST(TableEvt)-&gt;philoId == m_id</guard>
<choice_glyph conn="10,36,5,1,12,10,-2">
<action box="1,0,23,6"/>
</choice_glyph>
</choice>
<tran_glyph conn="2,36,3,-1,8">
<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)-&gt;philoId != m_id);</action>
<tran_glyph conn="2,40,3,-1,14">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,28,18,14">
<entry box="1,2,5,2"/>
</state_glyph>
</state>
<!--${AOs::Philo::SM::eating}-->
<state name="eating">
<entry>m_timeEvt.armX(eat_time(), 0U);</entry>
<exit>#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, DONE_SIG, m_id);
#else
TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe-&gt;philoId = m_id;
#endif
QP::QActive::PUBLISH(pe, this);
(void)m_timeEvt.disarm();</exit>
<!--${AOs::Philo::SM::eating::TIMEOUT}-->
<tran trig="TIMEOUT" target="../../1">
<tran_glyph conn="2,54,3,1,22,-41,-4">
<action box="0,-2,13,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)-&gt;philoId != m_id);</action>
<tran_glyph conn="2,58,3,-1,14">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,44,18,18">
<entry box="1,2,5,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state_diagram size="36,64"/>
</statechart>
</class>
<!--${AOs::Table}-->
<class name="Table" superclass="qpcpp::QActive">
<!--${AOs::Table::m_fork[N_PHILO]}-->
<attribute name="m_fork[N_PHILO]" type="std::uint8_t" visibility="0x02" properties="0x00"/>
<!--${AOs::Table::m_isHungry[N_PHILO]}-->
<attribute name="m_isHungry[N_PHILO]" type="bool" visibility="0x02" properties="0x00"/>
<!--${AOs::Table::Table}-->
<operation name="Table" type="" visibility="0x00" properties="0x00">
<code> : QActive(Q_STATE_CAST(&amp;Table::initial))
for (std::uint8_t n = 0U; n &lt; N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
}</code>
</operation>
<!--${AOs::Table::SM}-->
<statechart properties="0x02">
<!--${AOs::Table::SM::initial}-->
<initial target="../1/2">
<action>Q_UNUSED_PAR(e);
#ifdef Q_SPY
Table *Table_inst = this;
QS_OBJ_DICTIONARY(Table_inst);
#endif
subscribe(DONE_SIG);
subscribe(PAUSE_SIG);
subscribe(SERVE_SIG);
subscribe(TEST_SIG);
for (std::uint8_t n = 0U; n &lt; N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
BSP::displayPhilStat(n, THINKING);
}</action>
<initial_glyph conn="2,4,5,1,46,20,-10">
<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,12,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,16,3,-1,14">
<action box="0,-2,10,4"/>
</tran_glyph>
</tran>
<!--${AOs::Table::SM::active::serving}-->
<state name="serving">
<entry brief="give pending permitions to eat"> // give permissions to eat...
for (std::uint8_t n = 0U; n &lt; N_PHILO; ++n) {
if (m_isHungry[n]
&amp;&amp; (m_fork[left(n)] == FREE)
&amp;&amp; (m_fork[n] == FREE))
{
m_fork[left(n)] = USED;
m_fork[n] = USED;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, n);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoId = n;
#endif
QP::QActive::PUBLISH(pe, this);
m_isHungry[n] = false;
BSP::displayPhilStat(n, EATING);
}
}</entry>
<!--${AOs::Table::SM::active::serving::HUNGRY}-->
<tran trig="HUNGRY">
<action>std::uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (!m_isHungry[n]));
BSP::displayPhilStat(n, HUNGRY);
std::uint8_t m = left(n);</action>
<!--${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}-->
<choice>
<guard brief="both free">(m_fork[m] == FREE) &amp;&amp; (m_fork[n] == FREE)</guard>
<action>m_fork[m] = USED;
m_fork[n] = USED;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, n);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoId = n;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(n, EATING);</action>
<choice_glyph conn="20,28,5,-1,12">
<action box="1,0,10,2"/>
</choice_glyph>
</choice>
<!--${AOs::Table::SM::active::serving::HUNGRY::[else]}-->
<choice>
<guard>else</guard>
<action>m_isHungry[n] = true;</action>
<choice_glyph conn="20,28,4,-1,4,12">
<action box="1,4,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,28,3,-1,16">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<!--${AOs::Table::SM::active::serving::DONE}-->
<tran trig="DONE">
<action>std::uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (!m_isHungry[n]));
BSP::displayPhilStat(n, THINKING);
std::uint8_t m = left(n);
// both forks of Phil[n] must be used
Q_ASSERT((m_fork[n] == USED) &amp;&amp; (m_fork[m] == USED));
m_fork[m] = FREE;
m_fork[n] = FREE;
m = right(n); // check the right neighbor
if (m_isHungry[m] &amp;&amp; (m_fork[m] == FREE)) {
m_fork[n] = USED;
m_fork[m] = USED;
m_isHungry[m] = false;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, m);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoId = m;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(m, EATING);
}
m = left(n); // check the left neighbor
n = left(m); // left fork of the left neighbor
if (m_isHungry[m] &amp;&amp; (m_fork[n] == FREE)) {
m_fork[m] = USED;
m_fork[n] = USED;
m_isHungry[m] = false;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, m);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoId = m;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(m, EATING);
}</action>
<tran_glyph conn="4,36,3,-1,16">
<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,40,3,-1,16">
<action box="0,-2,12,4"/>
</tran_glyph>
</tran>
<!--${AOs::Table::SM::active::serving::PAUSE}-->
<tran trig="PAUSE" target="../../3">
<tran_glyph conn="4,44,3,1,36,8,-2">
<action box="0,-2,7,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,20,34,26">
<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,62,3,1,38,-31,-4">
<action box="0,-2,7,2"/>
</tran_glyph>
</tran>
<!--${AOs::Table::SM::active::paused::HUNGRY}-->
<tran trig="HUNGRY">
<action>std::uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoId;
// philo ID must be in range and he must be not hungry
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (!m_isHungry[n]));
m_isHungry[n] = true;
BSP::displayPhilStat(n, HUNGRY);</action>
<tran_glyph conn="4,66,3,-1,16">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<!--${AOs::Table::SM::active::paused::DONE}-->
<tran trig="DONE">
<action>std::uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (!m_isHungry[n]));
BSP::displayPhilStat(n, THINKING);
std::uint8_t m = left(n);
// both forks of Phil[n] must be used
Q_ASSERT((m_fork[n] == USED) &amp;&amp; (m_fork[m] == USED));
m_fork[m] = FREE;
m_fork[n] = FREE;</action>
<tran_glyph conn="4,70,3,-1,16">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,48,34,24">
<entry box="1,2,18,4"/>
<exit box="1,6,18,4"/>
</state_glyph>
</state>
<state_glyph node="2,6,44,68"/>
</state>
<state_diagram size="50,76"/>
</statechart>
</class>
</package>
<!--${XThreads}-->
<package name="XThreads" stereotype="0x02" namespace="APP::">
<!--${XThreads::XThread1}-->
<class name="XThread1" superclass="qpcpp::QXThread">
<!--${XThreads::XThread1::m_foo}-->
<attribute name="m_foo" type="std::uint8_t" visibility="0x02" properties="0x00">
<documentation>// NOTE: data needed by this thread should be members of
// the thread class. That way they are in the memory region
// accessible from this thread.</documentation>
</attribute>
<!--${XThreads::XThread1::XThread1}-->
<operation name="XThread1" type="" visibility="0x00" properties="0x00">
<code> : QXThread(&amp;run)</code>
</operation>
<!--${XThreads::XThread1::run}-->
<operation name="run" type="void" visibility="0x02" properties="0x01">
<!--${XThreads::XThread1::run::thr}-->
<parameter name="thr" type="QP::QXThread * const"/>
<code>// downcast the generic thr pointer to the specific thread
auto me = static_cast&lt;XThread1 *&gt;(thr);
// subscribe to the EAT signal (from the application)
me-&gt;subscribe(APP::EAT_SIG);
for (;;) {
QP::QEvt const *e = me-&gt;queueGet(BSP::TICKS_PER_SEC/4U);
if (e) {
TH_sema.signal(); // signal Thread2
QP::QF::gc(e); // must explicitly recycle the received event!
}
TH_mutex.lock(QP::QXTHREAD_NO_TIMEOUT); // lock the mutex
BSP::ledOn();
if (TH_mutex.tryLock()) { // exercise the mutex
// some floating point code to exercise the VFP...
float volatile x = 1.4142135F;
x = x * 1.4142135F;
QP::QXThread::delay(10U); // BLOCK while holding a mutex
TH_mutex.unlock();
}
TH_mutex.unlock();
BSP::ledOff();
}</code>
</operation>
</class>
<!--${XThreads::XThread2}-->
<class name="XThread2" superclass="qpcpp::QXThread">
<!--${XThreads::XThread2::m_foo}-->
<attribute name="m_foo" type="std::uint8_t" visibility="0x02" properties="0x00">
<documentation>// NOTE: data needed by this thread should be members of
// the thread class. That way they are in the memory region
// accessible from this thread.</documentation>
</attribute>
<!--${XThreads::XThread2::XThread2}-->
<operation name="XThread2" type="" visibility="0x00" properties="0x00">
<code> : QXThread(&amp;run)</code>
</operation>
<!--${XThreads::XThread2::run}-->
<operation name="run" type="void" visibility="0x02" properties="0x01">
<!--${XThreads::XThread2::run::thr}-->
<parameter name="thr" type="QP::QXThread * const"/>
<code>// downcast the generic thr pointer to the specific thread
//auto me = static_cast&lt;XThread2 *&gt;(thr);
// initialize the semaphore before using it
// NOTE: Here the semaphore is initialized in the highest-priority thread
// that uses it. Alternatively, the semaphore can be initialized
// before any thread runs.
TH_sema.init(0U, // count==0 (signaling semaphore)
1U); // max_count==1 (binary semaphore)
// initialize the mutex before using it
// NOTE: Here the mutex is initialized in the highest-priority thread
// that uses it. Alternatively, the mutex can be initialized
// before any thread runs.
TH_mutex.init(APP::N_PHILO + 6U); // priority-ceiling mutex
//l_mutex.init(0U); // alternatively: priority-ceiling NOT used
for (;;) {
// wait on a semaphore (BLOCK indefinitely)
TH_sema.wait();
TH_mutex.lock(QP::QXTHREAD_NO_TIMEOUT); // lock the mutex
QP::QXThread::delay(5U); // wait more (BLOCK)
TH_mutex.unlock();
}</code>
</operation>
</class>
</package>
<!--${.}-->
<directory name=".">
<!--${.::dpp.hpp}-->
<file name="dpp.hpp">
<text>#ifndef DPP_HPP_
#define DPP_HPP_
$declare ${Shared}
#ifdef QXK_HPP_
$declare ${Shared-TH}
#endif // QXK_HPP_
#endif // DPP_HPP_</text>
</file>
<!--${.::philo.cpp}-->
<file name="philo.cpp">
<text>#include &quot;qpcpp.hpp&quot; // QP/C++ real-time embedded framework
#include &quot;dpp.hpp&quot; // DPP Application interface
#include &quot;bsp.hpp&quot; // Board Support Package
$declare ${AOs::Philo}
//----------------------------------------------------------------------------
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_FILE
// helper function to provide a randomized think time for Philos
static inline QP::QTimeEvtCtr think_time() {
return static_cast&lt;QP::QTimeEvtCtr&gt;((BSP::random() % BSP::TICKS_PER_SEC)
+ (BSP::TICKS_PER_SEC/2U));
}
// helper function to provide a randomized eat time for Philos
static inline QP::QTimeEvtCtr eat_time() {
return static_cast&lt;QP::QTimeEvtCtr&gt;((BSP::random() % BSP::TICKS_PER_SEC)
+ BSP::TICKS_PER_SEC);
}
} // unnamed namespace
//----------------------------------------------------------------------------
$define ${Shared::Philo_ctor}
$define ${AOs::Philo}</text>
</file>
<!--${.::table.cpp}-->
<file name="table.cpp">
<text>#include &quot;qpcpp.hpp&quot; // QP/C++ real-time embedded framework
#include &quot;dpp.hpp&quot; // DPP Application interface
#include &quot;bsp.hpp&quot; // Board Support Package
$declare ${AOs::Table}
//----------------------------------------------------------------------------
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_FILE
// helper function to provide the RIGHT neighbor of a Philo[n]
static inline std::uint8_t right(std::uint8_t const n) {
return static_cast&lt;std::uint8_t&gt;((n + (APP::N_PHILO - 1U)) % APP::N_PHILO);
}
// helper function to provide the LEFT neighbor of a Philo[n]
static inline std::uint8_t left(std::uint8_t const n) {
return static_cast&lt;std::uint8_t&gt;((n + 1U) % APP::N_PHILO);
}
static constexpr std::uint8_t FREE {0U};
static constexpr std::uint8_t USED {1U};
static constexpr char const * const THINKING {&quot;thinking&quot;};
static constexpr char const * const HUNGRY {&quot;hungry &quot;};
static constexpr char const * const EATING {&quot;eating &quot;};
} // unnamed namespace
//----------------------------------------------------------------------------
$define ${Shared::Table_ctor}
$define ${AOs::Table}</text>
</file>
</directory>
<!--${qxk}-->
<directory name="qxk">
<!--${qxk::xthread1.cpp}-->
<file name="xthread1.cpp">
<text>#include &quot;qpcpp.hpp&quot; // QP/C++ real-time embedded framework
#include &quot;dpp.hpp&quot; // DPP Application interface
#include &quot;bsp.hpp&quot; // Board Support Package
//----------------------------------------------------------------------------
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_FILE
} // unnamed namespace
//----------------------------------------------------------------------------
$define ${Shared-TH::TH_sema}
$define ${Shared-TH::TH_mutex}
$declare ${XThreads::XThread1}
$define ${Shared-TH::XThread1_ctor}
$define ${Shared-TH::TH_obj_dict}
$define ${XThreads::XThread1}</text>
</file>
<!--${qxk::xthread2.cpp}-->
<file name="xthread2.cpp">
<text>#include &quot;qpcpp.hpp&quot; // QP/C++ real-time embedded framework
#include &quot;dpp.hpp&quot; // DPP Application interface
#include &quot;bsp.hpp&quot; // Board Support Package
//----------------------------------------------------------------------------
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_FILE
} // unnamed namespace
//----------------------------------------------------------------------------
$declare ${XThreads::XThread2}
$define ${Shared-TH::XThread2_ctor}
$define ${XThreads::XThread2}</text>
</file>
</directory>
</model>