dpp.qm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <model version="5.2.5" links="1">
  3. <documentation>Dining Philosopher Problem example</documentation>
  4. <!--${qpc}-->
  5. <framework name="qpc"/>
  6. <!--${Shared}-->
  7. <package name="Shared" stereotype="0x05">
  8. <!--${Shared::TableEvt}-->
  9. <class name="TableEvt" superclass="qpc::QEvt">
  10. <!--${Shared::TableEvt::philoNum}-->
  11. <attribute name="philoNum" type="uint8_t" visibility="0x00" properties="0x00"/>
  12. </class>
  13. <!--${Shared::AO_Philo[N_PHILO]}-->
  14. <attribute name="AO_Philo[N_PHILO]" type="QActive * const" visibility="0x00" properties="0x00">
  15. <documentation>/* opaque pointers to the Philo AOs */</documentation>
  16. <code>= {
  17. &amp;Philo_inst[0].super,
  18. &amp;Philo_inst[1].super,
  19. &amp;Philo_inst[2].super,
  20. &amp;Philo_inst[3].super,
  21. &amp;Philo_inst[4].super
  22. };</code>
  23. </attribute>
  24. <!--${Shared::AO_Table}-->
  25. <attribute name="AO_Table" type="QActive * const" visibility="0x00" properties="0x00">
  26. <documentation>/* opaque pointer to the Table AO */</documentation>
  27. <code>= &amp;Table_inst.super;</code>
  28. </attribute>
  29. <!--${Shared::Philo_ctor}-->
  30. <operation name="Philo_ctor" type="void" visibility="0x00" properties="0x00">
  31. <!--${Shared::Philo_ctor::n}-->
  32. <parameter name="n" type="uint8_t"/>
  33. <code>Philo *me = &amp;Philo_inst[n];
  34. QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Philo_initial));
  35. QTimeEvt_ctorX(&amp;me-&gt;timeEvt, &amp;me-&gt;super, TIMEOUT_SIG, 0U);</code>
  36. </operation>
  37. <!--${Shared::Table_ctor}-->
  38. <operation name="Table_ctor" type="void" visibility="0x00" properties="0x00">
  39. <code>Table *me = &amp;Table_inst;
  40. QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Table_initial));
  41. for (uint8_t n = 0U; n &lt; N_PHILO; ++n) {
  42. me-&gt;fork[n] = FREE;
  43. me-&gt;isHungry[n] = 0U;
  44. }</code>
  45. </operation>
  46. </package>
  47. <!--${AOs}-->
  48. <package name="AOs" stereotype="0x02">
  49. <!--${AOs::Philo}-->
  50. <class name="Philo" superclass="qpc::QActive">
  51. <!--${AOs::Philo::inst[N_PHILO]}-->
  52. <attribute name="inst[N_PHILO]" type="Philo" visibility="0x00" properties="0x01"/>
  53. <!--${AOs::Philo::timeEvt}-->
  54. <attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
  55. <!--${AOs::Philo::SM}-->
  56. <statechart properties="0x01">
  57. <!--${AOs::Philo::SM::initial}-->
  58. <initial target="../1">
  59. <action>(void)par; /* unused parameter */
  60. #ifdef Q_SPY
  61. uint8_t n = PHILO_ID(me);
  62. QS_OBJ_ARR_DICTIONARY(&amp;Philo_inst[n], n);
  63. QS_OBJ_ARR_DICTIONARY(&amp;Philo_inst[n].timeEvt, n);
  64. #endif
  65. QActive_subscribe(&amp;me-&gt;super, EAT_SIG);
  66. QActive_subscribe(&amp;me-&gt;super, TEST_SIG);
  67. /* the following code outputs the &quot;fun-dictionaries&quot; only once for
  68. * all Philo instances, as opposed to repeat them for every instance.
  69. */
  70. static bool registered = false;
  71. if (!registered) {
  72. registered = true;
  73. QS_FUN_DICTIONARY(&amp;Philo_initial);
  74. QS_FUN_DICTIONARY(&amp;Philo_thinking);
  75. QS_FUN_DICTIONARY(&amp;Philo_hungry);
  76. QS_FUN_DICTIONARY(&amp;Philo_eating);
  77. }</action>
  78. <initial_glyph conn="2,3,5,1,20,5,-3">
  79. <action box="0,-2,6,2"/>
  80. </initial_glyph>
  81. </initial>
  82. <!--${AOs::Philo::SM::thinking}-->
  83. <state name="thinking">
  84. <entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, THINK_TIME, 0U);</entry>
  85. <exit>QTimeEvt_disarm(&amp;me-&gt;timeEvt);</exit>
  86. <!--${AOs::Philo::SM::thinking::TIMEOUT}-->
  87. <tran trig="TIMEOUT" target="../../2">
  88. <tran_glyph conn="2,13,3,1,20,12,-3">
  89. <action box="0,-2,6,2"/>
  90. </tran_glyph>
  91. </tran>
  92. <!--${AOs::Philo::SM::thinking::EAT, DONE}-->
  93. <tran trig="EAT, DONE">
  94. <action>/* EAT or DONE must be for other Philos than this one */
  95. Q_ASSERT_ID(10, Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
  96. <tran_glyph conn="2,17,3,-1,13">
  97. <action box="0,-2,14,2"/>
  98. </tran_glyph>
  99. </tran>
  100. <state_glyph node="2,5,17,16">
  101. <entry box="1,2,5,2"/>
  102. <exit box="1,4,6,2"/>
  103. </state_glyph>
  104. </state>
  105. <!--${AOs::Philo::SM::hungry}-->
  106. <state name="hungry">
  107. <entry>TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
  108. pe-&gt;philoNum = PHILO_ID(me);
  109. QACTIVE_POST(AO_Table, &amp;pe-&gt;super, me);</entry>
  110. <!--${AOs::Philo::SM::hungry::EAT}-->
  111. <tran trig="EAT">
  112. <!--${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~}-->
  113. <choice target="../../../3">
  114. <guard>Q_EVT_CAST(TableEvt)-&gt;philoNum == PHILO_ID(me)</guard>
  115. <choice_glyph conn="15,30,5,1,7,13,-3">
  116. <action box="1,0,19,4"/>
  117. </choice_glyph>
  118. </choice>
  119. <tran_glyph conn="2,30,3,-1,13">
  120. <action box="0,-2,14,2"/>
  121. </tran_glyph>
  122. </tran>
  123. <!--${AOs::Philo::SM::hungry::DONE}-->
  124. <tran trig="DONE">
  125. <action>/* DONE must be for other Philos than this one */
  126. Q_ASSERT_ID(20, Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
  127. <tran_glyph conn="2,36,3,-1,14">
  128. <action box="0,-2,14,2"/>
  129. </tran_glyph>
  130. </tran>
  131. <state_glyph node="2,23,17,16">
  132. <entry box="1,2,5,2"/>
  133. </state_glyph>
  134. </state>
  135. <!--${AOs::Philo::SM::eating}-->
  136. <state name="eating">
  137. <entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, EAT_TIME, 0U);</entry>
  138. <exit>TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
  139. pe-&gt;philoNum = PHILO_ID(me);
  140. QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
  141. QTimeEvt_disarm(&amp;me-&gt;timeEvt);</exit>
  142. <!--${AOs::Philo::SM::eating::TIMEOUT}-->
  143. <tran trig="TIMEOUT" target="../../1">
  144. <tran_glyph conn="2,51,3,1,22,-41,-5">
  145. <action box="0,-2,6,2"/>
  146. </tran_glyph>
  147. </tran>
  148. <!--${AOs::Philo::SM::eating::EAT, DONE}-->
  149. <tran trig="EAT, DONE">
  150. <action>/* EAT or DONE must be for other Philos than this one */
  151. Q_ASSERT_ID(30, Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
  152. <tran_glyph conn="2,55,3,-1,13">
  153. <action box="0,-2,14,2"/>
  154. </tran_glyph>
  155. </tran>
  156. <state_glyph node="2,41,17,18">
  157. <entry box="1,2,5,2"/>
  158. <exit box="1,4,5,2"/>
  159. </state_glyph>
  160. </state>
  161. <state_diagram size="37,61"/>
  162. </statechart>
  163. </class>
  164. <!--${AOs::Table}-->
  165. <class name="Table" superclass="qpc::QActive">
  166. <!--${AOs::Table::inst}-->
  167. <attribute name="inst" type="Table" visibility="0x00" properties="0x01">
  168. <documentation>The only static instance of the Table class (Singleton pattern)</documentation>
  169. </attribute>
  170. <!--${AOs::Table::fork[N_PHILO]}-->
  171. <attribute name="fork[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
  172. <!--${AOs::Table::isHungry[N_PHILO]}-->
  173. <attribute name="isHungry[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
  174. <!--${AOs::Table::SM}-->
  175. <statechart properties="0x03">
  176. <!--${AOs::Table::SM::initial}-->
  177. <initial target="../1/1">
  178. <action>(void)par; /* unused parameter */
  179. QS_OBJ_DICTIONARY(&amp;Table_inst);
  180. QActive_subscribe(&amp;me-&gt;super, DONE_SIG);
  181. QActive_subscribe(&amp;me-&gt;super, PAUSE_SIG);
  182. QActive_subscribe(&amp;me-&gt;super, SERVE_SIG);
  183. QActive_subscribe(&amp;me-&gt;super, TEST_SIG);
  184. for (uint8_t n = 0U; n &lt; N_PHILO; ++n) {
  185. me-&gt;fork[n] = FREE;
  186. me-&gt;isHungry[n] = 0U;
  187. BSP_displayPhilStat(n, &quot;thinking&quot;);
  188. }</action>
  189. <initial_glyph conn="3,3,5,1,44,18,-9">
  190. <action box="0,-2,6,2"/>
  191. </initial_glyph>
  192. </initial>
  193. <!--${AOs::Table::SM::active}-->
  194. <state name="active">
  195. <!--${AOs::Table::SM::active::EAT}-->
  196. <tran trig="EAT">
  197. <action>Q_ERROR_ID(60);</action>
  198. <tran_glyph conn="2,15,3,-1,14">
  199. <action box="0,-2,17,4"/>
  200. </tran_glyph>
  201. </tran>
  202. <!--${AOs::Table::SM::active::serving}-->
  203. <state name="serving">
  204. <entry brief="give pending permissions to eat">uint8_t n;
  205. for (n = 0U; n &lt; N_PHILO; ++n) { /* give permissions to eat... */
  206. if ((me-&gt;isHungry[n] != 0U)
  207. &amp;&amp; (me-&gt;fork[LEFT(n)] == FREE)
  208. &amp;&amp; (me-&gt;fork[n] == FREE))
  209. {
  210. TableEvt *te;
  211. me-&gt;fork[LEFT(n)] = USED;
  212. me-&gt;fork[n] = USED;
  213. te = Q_NEW(TableEvt, EAT_SIG);
  214. te-&gt;philoNum = n;
  215. QACTIVE_PUBLISH(&amp;te-&gt;super, &amp;me-&gt;super);
  216. me-&gt;isHungry[n] = 0U;
  217. BSP_displayPhilStat(n, &quot;eating &quot;);
  218. }
  219. }</entry>
  220. <!--${AOs::Table::SM::active::serving::HUNGRY}-->
  221. <tran trig="HUNGRY">
  222. <action>uint8_t n, m;
  223. n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
  224. /* phil ID must be in range and he must be not hungry */
  225. Q_ASSERT_ID(40, (n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
  226. BSP_displayPhilStat(n, &quot;hungry &quot;);
  227. m = LEFT(n);</action>
  228. <!--${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}-->
  229. <choice>
  230. <guard brief="both free">(me-&gt;fork[m] == FREE) &amp;&amp; (me-&gt;fork[n] == FREE)</guard>
  231. <action>TableEvt *pe;
  232. me-&gt;fork[m] = USED;
  233. me-&gt;fork[n] = USED;
  234. pe = Q_NEW(TableEvt, EAT_SIG);
  235. pe-&gt;philoNum = n;
  236. QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
  237. BSP_displayPhilStat(n, &quot;eating &quot;);</action>
  238. <choice_glyph conn="19,26,5,-1,10">
  239. <action box="1,0,10,2"/>
  240. </choice_glyph>
  241. </choice>
  242. <!--${AOs::Table::SM::active::serving::HUNGRY::[else]}-->
  243. <choice>
  244. <guard>else</guard>
  245. <action>me-&gt;isHungry[n] = 1U;</action>
  246. <choice_glyph conn="19,26,4,-1,5,10">
  247. <action box="1,5,6,2"/>
  248. </choice_glyph>
  249. </choice>
  250. <tran_glyph conn="4,26,3,-1,15">
  251. <action box="0,-2,8,2"/>
  252. </tran_glyph>
  253. </tran>
  254. <!--${AOs::Table::SM::active::serving::DONE}-->
  255. <tran trig="DONE">
  256. <action>uint8_t n, m;
  257. TableEvt *pe;
  258. n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
  259. /* phil ID must be in range and he must be not hungry */
  260. Q_ASSERT_ID(50, (n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
  261. BSP_displayPhilStat(n, &quot;thinking&quot;);
  262. m = LEFT(n);
  263. /* both forks of Phil[n] must be used */
  264. Q_ASSERT_ID(51, (me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));
  265. me-&gt;fork[m] = FREE;
  266. me-&gt;fork[n] = FREE;
  267. m = RIGHT(n); /* check the right neighbor */
  268. if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[m] == FREE)) {
  269. me-&gt;fork[n] = USED;
  270. me-&gt;fork[m] = USED;
  271. me-&gt;isHungry[m] = 0U;
  272. pe = Q_NEW(TableEvt, EAT_SIG);
  273. pe-&gt;philoNum = m;
  274. QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
  275. BSP_displayPhilStat(m, &quot;eating &quot;);
  276. }
  277. m = LEFT(n); /* check the left neighbor */
  278. n = LEFT(m); /* left fork of the left neighbor */
  279. if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[n] == FREE)) {
  280. me-&gt;fork[m] = USED;
  281. me-&gt;fork[n] = USED;
  282. me-&gt;isHungry[m] = 0U;
  283. pe = Q_NEW(TableEvt, EAT_SIG);
  284. pe-&gt;philoNum = m;
  285. QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
  286. BSP_displayPhilStat(m, &quot;eating &quot;);
  287. }</action>
  288. <tran_glyph conn="4,34,3,-1,15">
  289. <action box="0,-2,6,2"/>
  290. </tran_glyph>
  291. </tran>
  292. <!--${AOs::Table::SM::active::serving::PAUSE}-->
  293. <tran trig="PAUSE" target="../../2">
  294. <tran_glyph conn="4,40,3,1,37,7,-3">
  295. <action box="0,-2,7,2"/>
  296. </tran_glyph>
  297. </tran>
  298. <state_glyph node="4,19,34,24">
  299. <entry box="1,2,27,2"/>
  300. </state_glyph>
  301. </state>
  302. <!--${AOs::Table::SM::active::paused}-->
  303. <state name="paused">
  304. <entry>BSP_displayPaused(1U);</entry>
  305. <exit>BSP_displayPaused(0U);</exit>
  306. <!--${AOs::Table::SM::active::paused::SERVE}-->
  307. <tran trig="SERVE" target="../../1">
  308. <tran_glyph conn="4,57,3,1,39,-23,-5">
  309. <action box="0,-2,7,2"/>
  310. </tran_glyph>
  311. </tran>
  312. <!--${AOs::Table::SM::active::paused::HUNGRY}-->
  313. <tran trig="HUNGRY">
  314. <action>uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
  315. /* philo ID must be in range and he must be not hungry */
  316. Q_ASSERT_ID(60, (n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
  317. me-&gt;isHungry[n] = 1U;
  318. BSP_displayPhilStat(n, &quot;hungry &quot;);</action>
  319. <tran_glyph conn="4,60,3,-1,15">
  320. <action box="0,-2,6,2"/>
  321. </tran_glyph>
  322. </tran>
  323. <!--${AOs::Table::SM::active::paused::DONE}-->
  324. <tran trig="DONE">
  325. <action>uint8_t n, m;
  326. n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
  327. /* phil ID must be in range and he must be not hungry */
  328. Q_ASSERT_ID(70, (n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
  329. BSP_displayPhilStat(n, &quot;thinking&quot;);
  330. m = LEFT(n);
  331. /* both forks of Phil[n] must be used */
  332. Q_ASSERT_ID(71, (me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));
  333. me-&gt;fork[m] = FREE;
  334. me-&gt;fork[n] = FREE;</action>
  335. <tran_glyph conn="4,63,3,-1,15">
  336. <action box="0,-2,6,2"/>
  337. </tran_glyph>
  338. </tran>
  339. <state_glyph node="4,45,34,20">
  340. <entry box="1,2,18,4"/>
  341. <exit box="1,6,18,4"/>
  342. </state_glyph>
  343. </state>
  344. <state_glyph node="2,5,43,62"/>
  345. </state>
  346. <state_diagram size="49,69"/>
  347. </statechart>
  348. </class>
  349. </package>
  350. <!--${.}-->
  351. <directory name=".">
  352. <!--${.::dpp.h}-->
  353. <file name="dpp.h">
  354. <text>#ifndef DPP_H
  355. #define DPP_H
  356. enum DPPSignals {
  357. EAT_SIG = Q_USER_SIG, /* published by Table to let a philosopher eat */
  358. DONE_SIG, /* published by Philosopher when done eating */
  359. PAUSE_SIG, /* published by BSP to pause serving forks */
  360. SERVE_SIG, /* published by BSP to serve re-start serving forks */
  361. TEST_SIG, /* published by BSP to test the application */
  362. MAX_PUB_SIG, /* the last published signal */
  363. HUNGRY_SIG, /* posted direclty to Table from hungry Philo */
  364. TIMEOUT_SIG, /* used by Philosophers for time events */
  365. MAX_SIG /* the last signal */
  366. };
  367. enum {
  368. N_PHILO = 5 /* number of Philos */
  369. };
  370. $declare ${Shared}
  371. #ifdef QXK_H_
  372. void Test1_ctor(void);
  373. extern QXThread * const XT_Test1;
  374. void Test2_ctor(void);
  375. extern QXThread * const XT_Test2;
  376. #endif /* QXK_H_ */
  377. #endif /* DPP_H */
  378. </text>
  379. </file>
  380. <!--${.::philo.c}-->
  381. <file name="philo.c">
  382. <text>#include &quot;qpc.h&quot;
  383. #include &quot;dpp.h&quot;
  384. #include &quot;bsp.h&quot;
  385. Q_DEFINE_THIS_MODULE(&quot;philo&quot;)
  386. /* Active object class -----------------------------------------------------*/
  387. $declare ${AOs::Philo}
  388. /* helper macros to provide a randomized think time for Philos */
  389. #define THINK_TIME \
  390. (QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + (BSP_TICKS_PER_SEC/2U))
  391. #define EAT_TIME \
  392. (QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + BSP_TICKS_PER_SEC)
  393. /* helper macro to provide the ID of Philo &quot;me_&quot; */
  394. #define PHILO_ID(me_) ((uint8_t)((me_) - &amp;Philo_inst[0]))
  395. /* Shared objects ----------------------------------------------------------*/
  396. $define ${Shared::AO_Philo[N_PHILO]}
  397. $define ${Shared::Philo_ctor}
  398. /* Philo definition --------------------------------------------------------*/
  399. $define ${AOs::Philo}</text>
  400. </file>
  401. <!--${.::table.c}-->
  402. <file name="table.c">
  403. <text>#include &quot;qpc.h&quot;
  404. #include &quot;dpp.h&quot;
  405. #include &quot;bsp.h&quot;
  406. Q_DEFINE_THIS_MODULE(&quot;table&quot;)
  407. /* Active object class -----------------------------------------------------*/
  408. $declare ${AOs::Table}
  409. #define RIGHT(n_) ((uint8_t)(((n_) + (N_PHILO - 1U)) % N_PHILO))
  410. #define LEFT(n_) ((uint8_t)(((n_) + 1U) % N_PHILO))
  411. #define FREE ((uint8_t)0)
  412. #define USED ((uint8_t)1)
  413. /* Shared objects ----------------------------------------------------------*/
  414. $define ${Shared::AO_Table}
  415. $define ${Shared::Table_ctor}
  416. /*..........................................................................*/
  417. $define ${AOs::Table}</text>
  418. </file>
  419. </directory>
  420. </model>