CHSM  4.4.1
chsm.h
Go to the documentation of this file.
1 /*
2 ** CHSM Language System
3 ** chsm.h -- Run-Time library declarations
4 **
5 ** Copyright (C) 1996-2010 Paul J. Lucas & Fabio Riccardi
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #ifndef chsm_H
23 #define chsm_H
24 
55 // standard
56 #include <list>
57 #ifdef CHSM_MULTITHREADED
58 #include <pthread.h>
59 #endif
60 
65 #define CHSM_NS Concurrent_Hierarchical_State_Machine
66 
67 namespace CHSM_NS {
68  class machine;
69  class state;
70  class parent;
71  class cluster;
72  class set;
73  class event;
74  struct transition;
75 
76 // macros to aid in argument-lists
77 #define CHSM_FORMAL(X) X
78 #define CHSM_ACTUAL(X) /* nothing */
79 
80 #ifdef CHSM_MULTITHREADED
81 
89 class mutex_lock {
90 public:
104  mutex_lock( pthread_mutex_t &m );
105 
109  ~mutex_lock();
110 
111 private:
112  int prev_cancel_state_;
113  pthread_mutex_t &mutex_;
114 
115  mutex_lock( mutex_lock& ); // forbid copy
116  mutex_lock& operator=( mutex_lock const& ); // forbid assignment
117 };
118 
120 
121 inline mutex_lock::mutex_lock( pthread_mutex_t &m ) : mutex_( m ) {
122  pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &prev_cancel_state_ );
123  pthread_mutex_lock( &mutex_ );
124 }
125 
126 inline mutex_lock::~mutex_lock() {
127  pthread_mutex_unlock( &mutex_ );
128  pthread_setcancelstate( prev_cancel_state_, 0 );
129  pthread_testcancel();
130 }
131 #endif /* CHSM_MULTITHREADED */
132 
133 //=============================================================================
134 
145 class state {
146 public:
147  //
148  // The constructor arguments must have horribly long names to avoid a name
149  // collision with user-defined state names in the mem-initializers in the
150  // resultant C++ code. We use macros to make life easier.
151  //
152 # define CHSM_STATE_ARG_LIST(A) \
153  A(CHSM_NS::machine&) chsm_machine_, \
154  A(char const*) chsm_name_, \
155  A(CHSM_NS::parent*) chsm_parent_, \
156  A(CHSM_NS::state::action) chsm_enter_action_, \
157  A(CHSM_NS::state::action) chsm_exit_action_, \
158  A(CHSM_NS::event*) chsm_enter_event_, \
159  A(CHSM_NS::event*) chsm_exit_event_
160 
166 # define CHSM_STATE_ARGS CHSM_STATE_ARG_LIST(CHSM_FORMAL)
167 
174 # define CHSM_STATE_INIT CHSM_STATE_ARG_LIST(CHSM_ACTUAL)
175 
179  typedef int id;
180 
188  typedef void (machine::*action)( state const &s, event const &trigger );
189 
206 
210  ~state();
211 
217  bool active() const { return state_ & S_active; }
218 
225  virtual void deep_clear();
226 
232  char const* name() const { return name_; }
233 
239  parent* parent_of() const { return parent_; }
240 
241  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
242 
243 protected:
249  machine &machine_;
250 
272  virtual bool enter( event const &trigger, state *from_child = 0 );
273 
296  virtual bool exit( event const &trigger, state *to = 0 );
297 
298 private:
299  char const *const name_;
300  parent *const parent_;
301 
302  enum {
303  S_inactive = 0x00,
304  S_active = 0x01,
305  //
306  // S_active_disabled is used to prevent making more than one
307  // nondeterministic transition from the same state. See the comments
308  // in event.c for more information.
309  //
310  S_active_disabled = 0x02 | S_active
311  };
312  unsigned state_;
313 
319  event *const enter_event_, *const exit_event_;
320 
324  action const enter_action_, exit_action_;
325 
326  friend class cluster;
327  friend class event;
328  friend class machine;
329  friend class parent;
330  friend class set;
331 };
332 
333 //=============================================================================
334 
350 struct transition {
359  typedef bool (machine::*condition)( event const &trigger );
360 
367  typedef void (machine::*action)( event const &trigger );
368 
377  typedef state* (machine::*target)( event const &trigger );
378 
383  condition condition_;
384 
389 
394 
399  target target_;
400 
404  action action_;
405 
411  bool is_internal() const;
412 
422  static bool is_legal( state const *s1, state const *s2 );
423 };
424 
425 //=============================================================================
426 
434 class event {
435 protected:
436  /*
437  ** Note: Even though this section is protected (as opposed to private), it
438  ** is so that derived classes emitted by the CHSM-to-C++ compiler will have
439  ** access and it is not the intent that end users will.
440  */
441 
442  //
443  // These typedefs are placed up here because they are used in the
444  // CHSM_EVENT_ARGS macro used in event's constructor.
445  //
446  typedef int transition_id;
447  typedef transition_id const *transition_list;
448 
458  machine &machine_;
459 
460 public:
461  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
462 
463 # define CHSM_EVENT_ARG_LIST(A) \
464  A(CHSM_NS::machine*) chsm_machine_, \
465  A(transition_list) chsm_transition_list_, \
466  A(char const*) chsm_name_, \
467  A(CHSM_NS::event*) chsm_base_event_
468 
474 # define CHSM_EVENT_ARGS CHSM_EVENT_ARG_LIST(CHSM_FORMAL)
475 
482 # define CHSM_EVENT_INIT CHSM_EVENT_ARG_LIST(CHSM_ACTUAL)
483 
487  event( CHSM_EVENT_ARGS );
488 
492  virtual ~event();
493 
498  void operator()() { lock_broadcast(); }
499 
507  template<typename EventClass> bool is_type() const {
508  return dynamic_cast<EventClass const*>( this );
509  }
510 
516  char const* name() const { return name_; }
517 
518  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
519 
520 public:
521  /*
522  ** Note: Even though this section is public (as opposed to private), it
523  ** is so that code emitted by the CHSM-to-C++ compiler will have access and
524  ** it is not the intent that end users will.
525  */
526 
527  struct param_block;
528  friend struct param_block;
529 
537  struct param_block {
543  param_block( event const &e ) : chsm_event_( e ) { }
544 
548  virtual ~param_block();
549 
550  protected:
551  /*
552  ** Note: Even though this section is protected (as opposed to private),
553  ** it is so that derived classes emitted by the CHSM-to-C++ compiler
554  ** will have access and it is not the intent that end users will.
555  */
556 
560  event const &chsm_event_;
561 
568  machine& chsm() const { return chsm_event_.machine_; }
569 
577  virtual bool precondition() const;
578 
579  friend class event;
580  };
581 
582 protected:
583  /*
584  ** Note: Even though this section is protected (as opposed to private),
585  ** it is so that derived classes emitted by the CHSM-to-C++ compiler will
586  ** have access and it is not the intent that end users will.
587  */
588 
597  unsigned in_progress_;
598 
604  void *param_block_;
605 
616  void broadcast( void *param_block );
617 
618 #ifdef CHSM_MULTITHREADED
619 
626  class machine_lock : public mutex_lock {
627  public:
628  machine_lock( machine& );
629  };
630 #endif /* CHSM_MULTITHREADED */
631 
632 private:
638  transition_list const transitions_;
639 
640  char const *const name_;
641  event *const base_event_;
642  static int const no_transition_id_;
643 
648  bool empty() const;
649 
654  void lock_broadcast();
655 
657  typedef transition value_type;
658 
660  typedef value_type const* const_pointer;
661 
663  typedef value_type const& const_reference;
664 
665  class const_iterator;
666  friend class const_iterator;
667 
672  class const_iterator {
673  public:
677  const_iterator() { }
678 
683  transition_id id() const { return *t_id_; }
684 
690  const_reference operator*() const { return t_[ *t_id_ ]; }
691 
697  const_pointer operator->() const { return &operator*(); }
698 
704  const_iterator& operator++() {
705  ++t_id_;
706  bump();
707  return *this;
708  }
709 
716  const_iterator operator++(int) {
717  const_iterator const temp = *this;
718  ++*this;
719  return temp;
720  }
721 
729  friend bool operator==( const_iterator const &i,
730  const_iterator const &j ) {
731  return *i.t_id_ == *j.t_id_;
732  }
733 
741  friend bool operator!=( const_iterator const &i,
742  const_iterator const &j ) {
743  return !( i == j );
744  }
745 
746  protected:
747  const_pointer t_; // machine's transitions
748  transition_list t_id_;
749  event const *base_event_;
750 
751  const_iterator( const_pointer, transition_list, event const* );
752 
753  private:
754  void bump();
755 
756  friend class event;
757  };
758 
764  const_iterator begin() const;
765 
771  const_iterator end() const {
772  return const_iterator( 0, &no_transition_id_, 0 );
773  }
774 
780  void broadcasted();
781 
782  friend class machine;
783  friend bool state::enter( event const&, state* );
784  friend bool state::exit ( event const&, state* );
785 };
786 
788 
789 inline bool event::empty() const {
790  return *transitions_ == no_transition_id_;
791 }
792 
804 inline bool operator==( event const &a, event const &b ) {
805  return &a == &b;
806 }
807 
819 inline bool operator!=( event const &a, event const &b ) {
820  return !( a == b );
821 }
822 
823 //=============================================================================
824 
832 class machine {
840  static event prime_;
841 
842 public:
843  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
844 
845  //
846  // The constructor arguments must have horribly long names to avoid a
847  // name collision with user-defined constructor arguments in derived
848  // classes. We use macros to make life easier.
849  //
850 # define CHSM_MACHINE_ARG_LIST(A) \
851  A(CHSM_NS::state*) chsm_state_ A([]), \
852  A(CHSM_NS::cluster&) chsm_root_, \
853  A(CHSM_NS::transition const) chsm_transition_ A([]), \
854  A(CHSM_NS::event const*) chsm_taken_ A([]), \
855  A(CHSM_NS::state*) chsm_target_ A([]), \
856  A(int) chsm_transitions_in_machine_
857 
863 # define CHSM_MACHINE_ARGS CHSM_MACHINE_ARG_LIST(CHSM_FORMAL)
864 
871 # define CHSM_MACHINE_INIT CHSM_MACHINE_ARG_LIST(CHSM_ACTUAL)
872 
876  virtual ~machine();
877 
883  bool active() const;
884 
892  virtual bool enter( event const &trigger = prime_ );
893 
901  virtual bool exit( event const &trigger = prime_ );
902 
904  typedef state value_type;
905 
907  typedef value_type const* const_pointer;
908 
910  typedef value_type const& const_reference;
911 
917  public:
922 
928  const_reference operator*() const { return **p_; }
929 
935  const_pointer operator->() const { return *p_; }
936 
941  const_iterator& operator++() { return ++p_, *this; }
942 
949  const_iterator operator++(int) { return const_iterator( p_++ ); }
950 
958  friend bool operator==( const_iterator const &i,
959  const_iterator const &j ) {
960  return *i.p_ == *j.p_;
961  }
962 
970  friend bool operator!=( const_iterator const &i,
971  const_iterator const &j ) {
972  return !( i == j );
973  }
974 
975  private:
976  typedef const_pointer const *iter_type;
977  iter_type p_;
978  const_iterator( iter_type p ) : p_( p ) { }
979  friend class machine;
980  };
981 
987  return const_iterator( (const_iterator::iter_type)state_ );
988  }
989 
995  const_iterator end() const {
996  return const_iterator( (const_iterator::iter_type)&nil_ );
997  }
998 
999  enum {
1004  D_none = 0x00,
1005 
1010  D_enex = 0x01,
1011 
1016  D_event = 0x02,
1017 
1022  D_alg = 0x04,
1023 
1028  D_all = D_enex | D_event | D_alg
1029  };
1030 
1036  unsigned debug() const { return debug_; }
1037 
1046  unsigned debug( unsigned state ) {
1047  unsigned const temp = debug_;
1048  debug_ = state;
1049  return temp;
1050  }
1051 
1057  void dump_state() const;
1058 
1059  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1060 
1061 protected:
1079 
1080 private:
1084  typedef std::list<event*> event_queue;
1085 
1090  state *const *const state_;
1091 
1095  cluster &root_;
1096 
1101  transition const *const transition_;
1102 
1107  int const transitions_in_machine_;
1108 
1114  event const **const taken_;
1115 
1120  state **const target_;
1121 
1126  bool in_progress_;
1127 
1128  event_queue event_queue_;
1129  unsigned debug_;
1130  static void *const nil_;
1131  static int const no_state_id_;
1132 
1133 #ifdef CHSM_MULTITHREADED
1134  mutable pthread_mutex_t machine_lock_;
1135 #endif
1136 
1139  void algorithm();
1140 
1141  friend class event;
1142  friend class event::machine_lock;
1143  friend class parent;
1144  friend struct transition;
1145 };
1146 
1147 //=============================================================================
1148 
1156 class parent : public state {
1157 protected:
1163  typedef int const* child_list;
1164 
1165 public:
1166 # define CHSM_PARENT_ARG_LIST(A) \
1167  CHSM_STATE_ARG_LIST(A), \
1168  A(child_list) chsm_children_
1169 
1175 # define CHSM_PARENT_ARGS CHSM_PARENT_ARG_LIST(CHSM_FORMAL)
1176 
1183 # define CHSM_PARENT_INIT CHSM_PARENT_ARG_LIST(CHSM_ACTUAL)
1184 
1187 
1190 
1192  typedef value_type const* const_pointer;
1193 
1196 
1198  typedef value_type const& const_reference;
1199 
1205  virtual void deep_clear();
1206 
1211  bool empty() const { return *children_ == no_child_id_; }
1212 
1217  reference front() { return *(machine_.state_)[*children_]; }
1218 
1223  const_reference front() const { return *(machine_.state_)[*children_]; }
1224 
1225  class iterator;
1226  friend class iterator;
1227 
1232  class iterator {
1233  public:
1237  iterator() { }
1238 
1244  reference operator* () const { return *p_[ *c_ ]; }
1245 
1251  pointer operator->() const { return p_[ *c_ ]; }
1252 
1258  return ++c_, *this;
1259  }
1260 
1267  return iterator( p_, c_++ );
1268  }
1269 
1277  friend bool operator==( iterator const &i, iterator const &j ) {
1278  return *i.c_ == *j.c_;
1279  }
1280 
1288  friend bool operator!=( iterator const &i, iterator const &j ) {
1289  return !( i == j );
1290  }
1291 
1292  protected:
1293  pointer const *p_;
1294  child_list c_;
1295  iterator( pointer const *p, child_list c ) : p_( p ), c_( c ) { }
1296  friend class parent;
1297  };
1298 
1305  return iterator( machine_.state_, children_ );
1306  }
1307 
1314  return iterator( 0, &no_child_id_ );
1315  }
1316 
1317  class const_iterator;
1318  friend class const_iterator;
1319 
1325  public:
1330 
1336  const_reference operator*() const { return *p_[ *c_ ]; }
1337 
1343  const_pointer operator->() const { return p_[ *c_ ]; }
1344 
1350  return ++c_, *this;
1351  }
1352 
1359  return const_iterator( p_, c_++ );
1360  }
1361 
1369  friend bool operator==( const_iterator const &i,
1370  const_iterator const &j ) {
1371  return *i.c_ == *j.c_;
1372  }
1373 
1381  friend bool operator!=( const_iterator const &i,
1382  const_iterator const &j ) {
1383  return !( i == j );
1384  }
1385 
1386  protected:
1387  pointer const *p_;
1388  child_list c_;
1389  const_iterator( pointer const *p, child_list c ) : p_( p ), c_( c ) { }
1390  friend class parent;
1391  };
1392 
1399  return const_iterator( machine_.state_, children_ );
1400  }
1401 
1408  return const_iterator( 0, &no_child_id_ );
1409  }
1410 
1411  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1412 
1413 protected:
1420 
1431  virtual bool switch_child( state *child );
1432 
1433  // for access to switch_child()
1434  friend bool state::enter( event const&, state* );
1435 
1436 private:
1437  child_list const children_;
1438  static int const no_child_id_;
1439 };
1440 
1441 //=============================================================================
1442 
1463 class cluster : public parent {
1464 public:
1465 # define CHSM_CLUSTER_ARG_LIST(A) \
1466  CHSM_PARENT_ARG_LIST(A), \
1467  A(bool) chsm_history_
1468 
1474 # define CHSM_CLUSTER_ARGS CHSM_CLUSTER_ARG_LIST(CHSM_FORMAL)
1475 
1482 # define CHSM_CLUSTER_INIT CHSM_CLUSTER_ARG_LIST(CHSM_ACTUAL)
1483 
1490  cluster( CHSM_CLUSTER_ARGS );
1491 
1495  void clear() { last_child_ = &front(); }
1496 
1501  virtual void deep_clear();
1502 
1513  virtual bool enter( event const &trigger, state *from_child = 0 );
1514 
1524  virtual bool exit( event const &trigger, state *to = 0 );
1525 
1526  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1527 
1528 private:
1529  bool const history_; // do we have a history?
1530  state *active_child_, *last_child_;
1531 
1532  // inherited
1533  virtual bool switch_child( state* );
1534 };
1535 
1536 //=============================================================================
1537 
1548 class set : public parent {
1549 public:
1550 # define CHSM_SET_ARG_LIST(A) \
1551  CHSM_PARENT_ARG_LIST(A)
1552 
1558 # define CHSM_SET_ARGS CHSM_SET_ARG_LIST(CHSM_FORMAL)
1559 
1566 # define CHSM_SET_INIT CHSM_SET_ARG_LIST(CHSM_ACTUAL)
1567 
1575 
1584  virtual bool enter( event const &trigger, state *from_child = 0 );
1585 
1594  virtual bool exit( event const &trigger, state *to = 0 );
1595 };
1596 
1598 
1599 inline event::const_iterator event::begin() const {
1600  //
1601  // This has to be defined down here so that the declaration for the machine
1602  // class has been seen by the C++ compiler.
1603  //
1604  return const_iterator( machine_.transition_, transitions_, base_event_ );
1605 }
1606 
1607 #ifdef CHSM_MULTITHREADED
1608 inline event::machine_lock::machine_lock( machine &m ) :
1609  mutex_lock( m.machine_lock_ )
1610 {
1611 }
1612 #endif /* CHSM_MULTITHREADED */
1613 
1614 inline bool machine::active() const {
1615  //
1616  // A machine as a whole is active only if its root cluster is.
1617  //
1618  return root_.active();
1619 }
1620 
1621 inline bool transition::is_internal() const {
1622  return to_id_ == machine::no_state_id_ && !target_;
1623 }
1624 
1625 } // namespace
1626 
1628 
1633 #ifndef CHSM_NO_ALIAS_NS
1634 
1638 # ifndef CHSM_NS_ALIAS
1639 # define CHSM_NS_ALIAS CHSM
1640 # endif
1641 
1642 namespace CHSM_NS_ALIAS = CHSM_NS;
1643 
1644 #endif /* CHSM_NO_ALIAS_NS */
1645 
1646 #endif /* chsm_H */
1647 /* vim:set et sw=4 ts=4: */