Bare Metal Programming Tool Kit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
rtos.h
1 //***************************************************************************
2 //
3 // file : bmptk/core/rtos.h
4 //
5 // LICENSE (MIT expat license, copy of bmptk/license.txt)
6 //
7 // Copyright (c) 2012
8 // Wouter van Ooijen (wouter@voti.nl)
9 // Marten Wensink
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be included
20 // in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE..
29 //
30 //***************************************************************************
31 
32 #include <iostream>
33 #include <limits>
34 
35 namespace bmptk {
36 
37 namespace rtos {
38 
39 #define global_logging 0
40 
41 #define BMPTK_RTOS_STATISTICS_ENABLED 1
42 
44 const unsigned int BMPTK_RTOS_DEFAULT_STACK_SIZE = 2048;
45 
47 const unsigned int BMPTK_RTOS_MAX_PRIORITY = 10000;
48 
49 // the macro BMPTK_RTOS_STATISTICS is used to prefix a single line
50 // that will be commented out when statistics is disabled
51 #if BMPTK_RTOS_STATISTICS_ENABLED
52  #define BMPTK_RTOS_STATISTICS( x ) x
53 #else
54  #define BMPTK_RTOS_STATISTICS( x )
55 #endif
56 
57 class task;
58 class event;
59 class waitable;
60 class flag;
61 class timer;
62 class clock;
63 class mutex;
64 template <class T> class mailbox;
65 template <class T, const int SIZE> class channel;
66 template <class T> class pool;
67 class mailbox_base;
68 class channel_base;
69 class pool_base;
70 class waitable_set;
71 class callback;
72 
73 
74 //************************************************************************
75 //
76 // some supporting stuff
77 //
78 //************************************************************************
79 
81 //
84 void run();
85 
87 //
89 task * current_task();
90 
92 void print( std::ostream & stream );
93 
95 //
102 void statistics_clear();
103 
105 void display_statistics();
106 
107 
108 //************************************************************************
109 //
110 // class event
111 //
113 //
126 //
127 //************************************************************************
128 
129 class event {
130 public:
131 
133  void print( std::ostream & s, bool header ) const;
134 
136  bool operator==( const event & rhs ) const;
137 
139  bool operator==( const waitable & rhs ) const;
140 
142  bool operator!=( const event & rhs ) const {
143  return ! ( *this == rhs );
144  }
145 
147  bool operator!=( const waitable & rhs ) const {
148  return ! ( *this == rhs );
149  }
150 
152  //
155  event operator+( const event & rhs ) const;
156 
157 private:
158 
160  task * t;
161 
163  //
166  unsigned int mask;
167 
169  event( task * t, unsigned int mask ): t( t ), mask( mask ){}
170 
171  friend class waitable_set;
172  friend class waitable;
173  friend class channel_base;
174  friend void beat();
175  friend class flag;
176  friend class callback;
177  friend class clock;
178  friend class timer;
179 };
180 
181 
182 //************************************************************************
183 //
184 // class waitable
185 //
187 //
215 //
216 //************************************************************************
217 
218 class waitable : public event {
219 public:
220 
222  //
225  virtual void clear();
226 
227 protected:
228 
230  //
232  waitable( task * task , const char *name );
233 
235  void set();
236 
237  BMPTK_RTOS_STATISTICS( const char *waitable_name; )
238 
239  friend class waitable_set;
240 };
241 
242 
243 //************************************************************************
244 //
245 // class flag
246 //
248 //
278 //
279 //************************************************************************
280 
281 class flag : public waitable {
282 public:
283 
285  //
288  flag( task * t, const char *name = "" );
289 
291  //
294  void set ();
295 
297  void print( std::ostream & s, bool header = true ) const;
298 
299 private:
300 
301  // this information is needed for statistics only
302  BMPTK_RTOS_STATISTICS( flag *next_flag; )
303  BMPTK_RTOS_STATISTICS( unsigned int n_sets; )
304  BMPTK_RTOS_STATISTICS( unsigned int n_gets; )
305 
306  friend class event;
307  friend class waitable_set;
308  friend void add( flag * f );
309  friend void print( std::ostream & stream );
310 };
311 
312 
313 //************************************************************************
314 //
315 // class waitable_set
316 //
317 // This is an private implementation construct, it is not documented
318 //
319 //************************************************************************
320 
321 #ifndef DOXYDOC
322 
323 class waitable_set {
324 private:
325  event wait( unsigned int mask );
326 
327 public:
328  task * client;
329  unsigned int current_waitables;
330  unsigned int requested_waitables;
331  unsigned int used;
332 
333  waitable_set( task * client ):
334  client( client ),
335  current_waitables( 0 ),
336  requested_waitables( 0 ),
337  used( 0 ) {}
338 
339  unsigned int waitable_allocate();
340  void set( const waitable &w );
341  void clear( const waitable &w );
342 
343  event wait(){ return wait( ~0 ); }
344  event wait( const waitable & w ){
345  return wait( w.mask );
346  }
347  event wait( const event & set ){
348  return wait( set.mask );
349  }
350 };
351 
352 #endif
353 
354 
355 //************************************************************************
356 //
357 // class task
358 //
360 //
411 //
412 //************************************************************************
413 
414 class task {
415 
416 private:
417 
418  // The rtos uses block() and unblock() to implement the
419  // synhronisation mechanisms (waitables).
420  bool task_is_blocked;
421 
422  // a lower number means a higher priority, 0 is highest
423  unsigned int task_priority;
424 
425  // timer for sleep() call
426  timer * sleep_timer;
427 
428  friend void task_trampoline();
429  friend void sleep_until( time t );
430 
431 protected:
432 
433  // task name, only for statistics
434  BMPTK_RTOS_STATISTICS( const char *task_name; )
435 
437  //
460  virtual void main() = 0;
461 
462 public:
463 
465  //
476  task(
477  unsigned int priority = BMPTK_RTOS_MAX_PRIORITY,
478  const char * tname = "",
479  unsigned int stacksize = BMPTK_RTOS_DEFAULT_STACK_SIZE
480  );
481 
483  virtual ~task () {
484  fatal_error_detected( "task destructor called" );
485  }
486 
488  //
491  void release();
492 
494  unsigned int priority() const {
495  return task_priority;
496  }
497 
499  const char * name() const {
500  #if BMPTK_RTOS_STATISTICS_ENABLED
501  return task_name;
502  #else
503  return "";
504  #endif
505  }
506 
508  bool is_ready() const {
509  return ! task_is_blocked;
510  }
512  bool is_blocked() const {
513  return task_is_blocked;
514  }
515 
517  void print( std::ostream & stream, bool header = true ) const;
518 
520  //
533  event wait(){ return waitables.wait(); }
534 
536  //
538  event wait( const waitable & w ){
539  return waitables.wait( w );
540  }
541 
543  //
545  event wait( const event & set ){
546  return waitables.wait( set );
547  }
548 
550  void set( flag &w ){
551  w.set();
552  }
553 
555  //
563  ignore_this_activation = true;
564  }
565 
566 private:
567 
569  void statistics_clear(){
570  runtime_max = 0 * ms;
571  activations = 0;
572  }
573 
575  waitable_set waitables;
576 
578  void block();
579 
581  void unblock();
582 
584  int activated;
585  time latency_max;
586  time runtime_max;
587  int activations;
588  bool ignore_this_activation;
589 
591  task * nextTask;
592 
594  task * next_mutex_waiter;
595 
598 
599  friend class periodic_task;
600  friend class waitable_set;
601  friend class flag;
602  friend class waitable;
603  friend class mutex;
604  friend void print( std::ostream & stream );
605  friend void do_statistics_clear();
606  friend void add( task * new_task );
607  friend void beat();
608  // friend void channel_base::print( std::ostream & stream, bool header ) const;
609 };
610 
611 
612 //************************************************************************
613 //
614 // class callback
615 //
616 // rtos private implementation class
617 //
618 //************************************************************************
619 
620 #ifndef DOXYDOC
621 
622 class callback : public waitable {
623 public:
624 
625  callback( task *t, const char *name );
626 
627  // a callback should never be destroyed
628  virtual ~callback() {
629  fatal_error_detected( "callback destructor called" );
630  }
631 
632  // the time_up function must be provided by a derived class
633  virtual void time_up( void ) = 0;
634 
636  void print( std::ostream & s, bool header = true ) const;
637 
638 protected:
639 
640  // the callback must be called at t
641  void await( time t ){
642  deadline = t;
643  running = true;
644  }
645 
646  // the callback must fire <time> from now
647  void start( time t ){
648  await( bmptk::current_time() + t );
649  }
650 
651  // the callback must fire in the future, at a multiple of
652  // <time> from the last firing
653  void restart( time t ){
654  time now = bmptk::current_time();
655  while( deadline <= now ){
656  deadline += t;
657  }
658  running = true;
659  }
660 
661  // abort a started timer
662  virtual void cancel(){
663  running = false;
664  }
665 
666  // true iff the timer is running
667  bool running;
668 
669  // the moment the callback should be called
670  time deadline;
671 
672  // for the rtos to link timers in a chain
673  callback * next_callback;
674 
675  friend class task;
676  friend void beat();
677  friend void add( callback * t );
678  friend void handle_callbacks( time t );
679 };
680 
681 #endif
682 
683 
684 //************************************************************************
685 //
686 // class timer
687 //
689 //
712 //
713 //************************************************************************
714 
715 class timer : public callback {
716 public:
717 
719  timer( task * t, const char *name = "" );
720 
722  //
727  void set( time t );
728 
730  //
734  void await( time t );
735 
737  //
740  void cancel();
741 
743  void print( std::ostream & s, bool header = true ) const;
744 
745 private:
746 
747  void time_up();
748  BMPTK_RTOS_STATISTICS( timer *next_timer; )
749  BMPTK_RTOS_STATISTICS( unsigned int n_sets; )
750  BMPTK_RTOS_STATISTICS( unsigned int n_cancels; )
751 
752  friend void add( timer * t );
753  friend void print( std::ostream & stream );
754  friend void beat();
755 };
756 
757 //************************************************************************
758 //
759 // class clock
760 //
762 //
777 //
778 //************************************************************************
779 
780 class clock : public callback {
781 public:
782 
784  //
786  clock(
787  task * t,
788  time interval,
789  const char *name = ""
790  );
791 
793  //
795  void clear(){ waitable::clear(); }
796 
799  return _interval;
800  }
801 
803  void print( std::ostream & s, bool header = true ) const;
804 
805 private:
806  void time_up();
807  time _interval;
808  BMPTK_RTOS_STATISTICS( clock *next_clock; )
809  BMPTK_RTOS_STATISTICS( unsigned int ticks; )
810 
811  friend void add( clock * c );
812  friend void beat();
813  friend void print( std::ostream & stream );
814 };
815 
816 
817 //************************************************************************
818 //
819 // class pool_base
820 //
822 //
823 //************************************************************************
824 
825 #ifndef DOXYDOC
826 
827 class pool_base {
828 public:
829 
830  pool_base( const char * name );
831  ~pool_base() {
832  fatal_error_detected( "pool destructor called" );
833  }
834  void print( std::ostream & s, bool header = true ) const;
835 
836 #if BMPTK_RTOS_STATISTICS_ENABLED
837  unsigned int reads;
838  unsigned int writes;
839  pool_base * next_pool;
840  const char * pool_name;
841 #endif
842 
843 };
844 
845 #endif
846 
847 
848 //************************************************************************
849 //
850 // class pool
851 //
853 //
892 //
893 //************************************************************************
894 
895 template <class T> class pool : public pool_base {
896 public:
897 
899  //
905  pool( const char *name = "" ): pool_base( name ){}
906 
908  //
916  void write (T item) {
917  BMPTK_RTOS_STATISTICS( reads++; )
918  data = item;
919  }
920 
922  //
924  T read (void) {
925  BMPTK_RTOS_STATISTICS( writes++; )
926  return data;
927  }
928 
929 private:
930  T data;
931 };
932 
933 
934 //************************************************************************
935 //
936 // class mutex
937 //
939 //
968 //
969 //************************************************************************
970 
971 class mutex {
972 public:
973 
975  //
977  mutex( const char *name = "" );
978 
980  //
982  ~mutex();
983 
985  void print( std::ostream & stream, bool header = true ) const;
986 
996  void wait (void);
997 
999  //
1007  void signal (void);
1008 
1009 private:
1010 
1011  task * owner; // current owner of the mutex
1012  task * waiters; // head of the waiting tasks queue
1013 
1014 #if BMPTK_RTOS_STATISTICS_ENABLED
1015  const char * mutex_name; // for logging
1016  mutex *next_mutex; // queue of all mutexes, for logging
1017  int wait_count; // counts # wait calls;
1018 #endif
1019 
1020  friend void add( mutex * m );
1021  friend void print( std::ostream & stream );
1022 };
1023 
1024 
1025 //************************************************************************
1026 //
1027 // class mailbox_base
1028 //
1029 // rtos private implementation class
1030 //
1031 //************************************************************************
1032 
1033 #ifndef DOXYDOC
1034 
1035 class mailbox_base {
1036 public:
1037  mailbox_base( const char *name );
1038 
1039  ~mailbox_base() {
1040  fatal_error_detected( "mailbox destructor called" );
1041  }
1042 
1043  void print( std::ostream & s, bool header = true ) const;
1044 
1045  task * client;
1046 #if BMPTK_RTOS_STATISTICS_ENABLED
1047  const char * mailbox_name;
1048  unsigned int writes;
1049  mailbox_base *next_mailbox;
1050 #endif
1051 
1052 };
1053 
1054 #endif
1055 
1056 //************************************************************************
1057 //
1058 // class mailbox
1059 //
1061 //
1087 //
1088 //************************************************************************
1089 
1090 template <class T> class mailbox : mailbox_base {
1091 public:
1092 
1094  //
1100  mailbox( const char *name = "" ): mailbox_base( name ){}
1101 
1103  //
1111  void write( const T item ) {
1112  BMPTK_RTOS_STATISTICS( writes++; )
1113  data = item;
1114  if ( client != 0 ) {
1115  // someone is waiting to read, unblock it
1116  client->unblock();
1117  } else {
1118  // block until the reader gets the data
1119  client = bmptk::rtos::current_task();
1120  client->block();
1121  }
1122  }
1123 
1125  //
1133  T read (void) {
1134  if ( client == 0 ) {
1135  // no writer yet, so wait for a writer
1136  client = bmptk::rtos::current_task();
1137  client->block();
1138  }
1139  else {
1140  // unblock the writer
1141  // but first make sure the client is 0 !
1142  task *temp = client;
1143  client = 0;
1144  temp->unblock();
1145  }
1146  return data;
1147  }
1148 
1149 private:
1150  T data;
1151 };
1152 
1153 //************************************************************************
1154 //
1155 // class channel_base
1156 //
1157 // rtos private implementation class
1158 //
1159 //************************************************************************
1160 
1161 #ifndef DOXYDOC
1162 
1163 class channel_base : public waitable{
1164 public:
1165  virtual ~channel_base() {
1166  fatal_error_detected( "channel destructor called" );
1167  }
1168 
1169  void print( std::ostream & s, bool header = true ) const;
1170 
1171 protected:
1172 public:
1173 
1174  channel_base( task * t, const char *name );
1175 
1176 #if BMPTK_RTOS_STATISTICS_ENABLED
1177  const char *channel_name;
1178  channel_base *next_channel;
1179  int writes;
1180  int ignores;
1181 #endif
1182 
1183  int qSize;
1184  int head;
1185  int tail;
1186 };
1187 
1188 #endif
1189 
1190 //************************************************************************
1191 //
1192 // class channel
1193 //
1195 //
1249 //
1250 //************************************************************************
1251 
1252 template <class T, const int SIZE> class channel : public channel_base {
1253 public:
1254 
1256  //
1259  channel( task * t, const char *name = "" ): channel_base( t, name ){}
1260 
1262  void write( T item ) {
1263  if( qSize < SIZE ) {
1264  BMPTK_RTOS_STATISTICS( writes++; )
1265  queue[head] = item;
1266  if( ++head == SIZE ) {
1267  head = 0;
1268  }
1269  qSize += 1;
1270  waitable::set();
1271  } else {
1272  BMPTK_RTOS_STATISTICS( ignores++; )
1273  }
1274  }
1275 
1277  T read() {
1278  if( qSize == 0 ) {
1279  t->wait( *this );
1280  }
1281 
1282  if( qSize == 0 ) {
1283  fatal_error_detected( "channel should not be empty now");
1284  }
1285  T buf = queue[ tail ];
1286  if( ++tail == SIZE ) {
1287  tail = 0;
1288  }
1289  qSize -= 1;
1290  if( qSize > 0 ) {
1291  waitable::set();
1292  } else {
1293  waitable::clear();
1294  }
1295  return buf;
1296  }
1297 
1299  void clear (void) {
1300  qSize = 0;
1301  head = tail = 0;
1302  waitable::clear();
1303  }
1304 
1305 private:
1306  T queue[ SIZE] ;
1307 };
1308 
1309 
1311 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::task & t );
1312 
1314 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::flag & f );
1315 
1317 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::event & e );
1318 
1320 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::callback & c );
1321 
1323 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::timer & t );
1324 
1326 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::clock & c );
1327 
1329 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::channel_base & c );
1330 
1332 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::mutex & m );
1333 
1335 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::mailbox_base & m );
1336 
1338 std::ostream & operator<< ( std::ostream & s, const bmptk::rtos::pool_base & p );
1339 
1340 
1341 
1342 }; // namespace rtos;
1343 
1344 }; // namespace bmptk;