Dining Philosophers Problem (DPP) example for the QP active object framework. Demonstrates: event-driven programming, hierarchical state machines in C++, modeling and graphical state machine design, code generation, preemptive multitasking, software tracing, power saving mode, direct event posting, publish-subscribe. More information available in the [[/users/QL/notebook|Quantum Leaps Notebook pages]]. See also [[http://www.state-machine.com|state-machine.com]].

Dependencies:   mbed qp

Revision:
4:6189d844a1a2
Parent:
3:81ceb3127876
--- a/philo.cpp	Mon Sep 26 02:21:01 2011 +0000
+++ b/philo.cpp	Tue Sep 04 22:41:20 2012 +0000
@@ -1,65 +1,62 @@
 //////////////////////////////////////////////////////////////////////////////
-// Product: DPP example
-// Last Updated for Version: 4.2.00
-// Date of the Last Update:  Jul 15, 2011
-//
-//                    Q u a n t u m     L e a P s
-//                    ---------------------------
-//                    innovating embedded systems
-//
-// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+// Model: dpp.qm
+// File:  ././philo.cpp
 //
-// This software may be distributed and modified under the terms of the GNU
-// General Public License version 2 (GPL) as published by the Free Software
-// Foundation and appearing in the file GPL.TXT included in the packaging of
-// this file. Please note that GPL Section 2[b] requires that all works based
-// on this software must also be made publicly available under the terms of
-// the GPL ("Copyleft").
+// This file has been generated automatically by QP Modeler (QM).
+// DO NOT EDIT THIS FILE MANUALLY.
 //
-// Alternatively, this software may be distributed and modified under the
-// terms of Quantum Leaps commercial licenses, which expressly supersede
-// the GPL and are specifically designed for licensees interested in
-// retaining the proprietary status of their code.
-//
-// Contact information:
-// Quantum Leaps Web site:  http://www.quantum-leaps.com
-// e-mail:                  info@quantum-leaps.com
+// Please visit www.state-machine.com/qm for more information.
 //////////////////////////////////////////////////////////////////////////////
 #include "qp_port.h"
 #include "dpp.h"
 #include "bsp.h"
 
+namespace DPP {
+
 Q_DEFINE_THIS_FILE
 
 // Active object class -------------------------------------------------------
-class Philo : public QActive {
+// @(/2/0) ...................................................................
+class Philo : public QP::QActive {
 private:
-    QTimeEvt m_timeEvt;                       // to timeout thinking or eating
+    QP::QTimeEvt m_timeEvt;
 
 public:
     Philo();
 
-private:
-    static QState initial (Philo *me, QEvent const *e);
-    static QState thinking(Philo *me, QEvent const *e);
-    static QState hungry  (Philo *me, QEvent const *e);
-    static QState eating  (Philo *me, QEvent const *e);
+protected:
+    static QP::QState initial(Philo * const me, QP::QEvt const * const e);
+    static QP::QState thinking(Philo * const me, QP::QEvt const * const e);
+    static QP::QState hungry(Philo * const me, QP::QEvt const * const e);
+    static QP::QState eating(Philo * const me, QP::QEvt const * const e);
 };
 
 // Local objects -------------------------------------------------------------
-static Philo l_philo[N_PHILO];                       // storage for all Philos
+static Philo l_philo[N_PHILO];   // storage for all Philos
 
-#define THINK_TIME  (BSP_TICKS_PER_SEC/2)
-#define EAT_TIME    (BSP_TICKS_PER_SEC/5)
+// 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 macro to provide the ID of Philo "me_"
-#define PHILO_ID(me_)    ((uint8_t)((me_) - l_philo))
+// 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);
+}
 
-enum InternalSignals {                                     // internal signals
+// 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 ------------------------------------------------------------
-QActive * const AO_Philo[N_PHILO] = {        // "opaque" pointers to Philo AOs
+QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO
     &l_philo[0],
     &l_philo[1],
     &l_philo[2],
@@ -67,15 +64,23 @@
     &l_philo[4]
 };
 
-//............................................................................
-Philo::Philo()
-    : QActive((QStateHandler)&Philo::initial),
-      m_timeEvt(TIMEOUT_SIG)
-{}
-//............................................................................
-QState Philo::initial(Philo *me, QEvent const *) {
-    static uint8_t registered;            // starts off with 0, per C-standard
+// Philo definition ----------------------------------------------------------
+// @(/2/0) ...................................................................
+// @(/2/0/1) .................................................................
+Philo::Philo() 
+  : QActive(Q_STATE_CAST(&Philo::initial)),
+    m_timeEvt(TIMEOUT_SIG)
+{
+}
+
+// @(/2/0/2) .................................................................
+// @(/2/0/2/0)
+QP::QState Philo::initial(Philo * const me, QP::QEvt const * const e) {
+    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]);
@@ -91,80 +96,125 @@
         QS_FUN_DICTIONARY(&Philo::thinking);
         QS_FUN_DICTIONARY(&Philo::hungry);
         QS_FUN_DICTIONARY(&Philo::eating);
-
-        registered = (uint8_t)1;
     }
-    QS_SIG_DICTIONARY(HUNGRY_SIG, me);               // signal for each Philos
-    QS_SIG_DICTIONARY(TIMEOUT_SIG, me);              // signal for each Philos
+    QS_SIG_DICTIONARY(HUNGRY_SIG, me);  // signal for each Philos
+    QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos
 
     me->subscribe(EAT_SIG);
-
     return Q_TRAN(&Philo::thinking);
 }
-//............................................................................
-QState Philo::thinking(Philo *me, QEvent const *e) {
+// @(/2/0/2/1) ...............................................................
+QP::QState Philo::thinking(Philo * const me, QP::QEvt const * const e) {
+    QP::QState status;
     switch (e->sig) {
+        // @(/2/0/2/1)
         case Q_ENTRY_SIG: {
-            me->m_timeEvt.postIn(me, THINK_TIME);
-            return Q_HANDLED();
+            me->m_timeEvt.postIn(me, think_time());
+            status = Q_HANDLED();
+            break;
         }
+        // @(/2/0/2/1)
+        case Q_EXIT_SIG: {
+            (void)me->m_timeEvt.disarm();
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/0/2/1/0)
         case TIMEOUT_SIG: {
-            return Q_TRAN(&Philo::hungry);
+            status = Q_TRAN(&Philo::hungry);
+            break;
         }
-        case EAT_SIG:                            // intentionally fall-through
+        // @(/2/0/2/1/1)
+        case EAT_SIG: // intentionally fall through
         case DONE_SIG: {
-                         // EAT or DONE must be for other Philos than this one
-            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
-            return Q_HANDLED();
+            /* EAT or DONE must be for other Philos than this one */
+            Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
+            status = Q_HANDLED();
+            break;
+        }
+        default: {
+            status = Q_SUPER(&QHsm::top);
+            break;
         }
     }
-    return Q_SUPER(&QHsm::top);
+    return status;
 }
-//............................................................................
-QState Philo::hungry(Philo *me, QEvent const *e) {
+// @(/2/0/2/2) ...............................................................
+QP::QState Philo::hungry(Philo * const me, QP::QEvt const * const e) {
+    QP::QState status;
     switch (e->sig) {
+        // @(/2/0/2/2)
         case Q_ENTRY_SIG: {
             TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
             pe->philoNum = PHILO_ID(me);
             AO_Table->POST(pe, me);
-            return Q_HANDLED();
+            status = Q_HANDLED();
+            break;
         }
+        // @(/2/0/2/2/0)
         case EAT_SIG: {
-            if (((TableEvt *)e)->philoNum == PHILO_ID(me)) {
-                return Q_TRAN(&Philo::eating);
+            // @(/2/0/2/2/0/0)
+            if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(me)) {
+                status = Q_TRAN(&Philo::eating);
+            }
+            else {
+                status = Q_UNHANDLED();
             }
             break;
         }
+        // @(/2/0/2/2/1)
         case DONE_SIG: {
-                                // DONE must be for other Philos than this one
-            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
-            return Q_HANDLED();
+            /* DONE must be for other Philos than this one */
+            Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
+            status = Q_HANDLED();
+            break;
+        }
+        default: {
+            status = Q_SUPER(&QHsm::top);
+            break;
         }
     }
-    return Q_SUPER(&QHsm::top);
+    return status;
 }
-//............................................................................
-QState Philo::eating(Philo *me, QEvent const *e) {
+// @(/2/0/2/3) ...............................................................
+QP::QState Philo::eating(Philo * const me, QP::QEvt const * const e) {
+    QP::QState status;
     switch (e->sig) {
+        // @(/2/0/2/3)
         case Q_ENTRY_SIG: {
-            me->m_timeEvt.postIn(me, EAT_TIME);
-            return Q_HANDLED();
+            me->m_timeEvt.postIn(me, eat_time());
+            status = Q_HANDLED();
+            break;
         }
+        // @(/2/0/2/3)
         case Q_EXIT_SIG: {
             TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
             pe->philoNum = PHILO_ID(me);
-            QF::PUBLISH(pe, me);
-            return Q_HANDLED();
+            QP::QF::PUBLISH(pe, me);
+            (void)me->m_timeEvt.disarm();
+            status = Q_HANDLED();
+            break;
         }
+        // @(/2/0/2/3/0)
         case TIMEOUT_SIG: {
-            return Q_TRAN(&Philo::thinking);
+            status = Q_TRAN(&Philo::thinking);
+            break;
         }
-        case EAT_SIG:                            // intentionally fall-through
+        // @(/2/0/2/3/1)
+        case EAT_SIG: // intentionally fall through
         case DONE_SIG: {
-                         // EAT or DONE must be for other Philos than this one
-            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
-            return Q_HANDLED();
+            /* EAT or DONE must be for other Philos than this one */
+            Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me));
+            status = Q_HANDLED();
+            break;
+        }
+        default: {
+            status = Q_SUPER(&QHsm::top);
+            break;
         }
     }
-    return Q_SUPER(&QHsm::top);
+    return status;
 }
+
+
+}                                                             // namespace DPP