µOS++ IIIe Reference  v6.3.15
“Perfekt ist nicht gut genug”
The third edition of µOS++, a POSIX inspired open source system, written in C++.
os-thread.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the µOS++ distribution.
3  * (https://github.com/micro-os-plus)
4  * Copyright (c) 2016 Liviu Ionescu.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #include <cmsis-plus/rtos/os.h>
29 
30 #include <memory>
31 #include <stdexcept>
32 
33 // ----------------------------------------------------------------------------
34 
35 namespace os
36 {
37  namespace rtos
38  {
39  // ------------------------------------------------------------------------
40 
45  std::size_t thread::stack::min_size_bytes_ = port::stack::min_size_bytes;
46 
47  std::size_t thread::stack::default_size_bytes_ =
48  port::stack::default_size_bytes;
49 
54  // ------------------------------------------------------------------------
55  using mutexes_list = utils::intrusive_list<
56  mutex, utils::double_list_links, &mutex::owner_links_>;
57 
58  // ========================================================================
103  const thread::attributes thread::initializer;
104 
154  void
156  {
157  // Align the bottom of the stack.
158  void* pa = bottom_address_;
159  bottom_address_ = static_cast<stack::element_t*> (std::align (
161  size_bytes_));
162 
163  // If there is not enough space for the minimal stack, fail.
164  os_assert_throw(bottom_address_ != nullptr, ENOMEM);
165 
166  element_t* p = bottom_address_;
167  element_t* pend = top ();
168 
169  // Initialise the entire stack with the magic word.
170  for (; p < pend; ++p)
171  {
172  *p = magic;
173  }
174 
175  // Compute the actual size. The -1 is to leave space for the magic.
176  size_bytes_ = ((static_cast<std::size_t> (p - bottom_address_) - 1)
177  * sizeof(element_t));
178  }
179 
192  std::size_t
194  {
195  element_t* p = bottom_address_;
196  std::size_t count = 0;
197  while (*p == magic)
198  {
199  count += sizeof(element_t);
200  ++p;
201  }
202 
203  return count;
204  }
205 
218  void
219  thread::internal_invoke_with_exit_ (thread* thread)
220  {
221 #if defined(OS_TRACE_RTOS_THREAD)
222  trace::printf ("%s() @%p %s\n", __func__, thread, thread->name ());
223 #endif
224 
225  void* exit_ptr;
226 #if defined(__EXCEPTIONS)
227  try
228  {
229  exit_ptr = thread->func_ (thread->func_args_);
230  }
231  catch (std::exception e)
232  {
233  trace::printf ("%s() @%p %s top exception \"%s\".\n", __func__,
234  thread, thread->name (), e.what ());
235  exit_ptr = nullptr;
236  }
237  catch (...)
238  {
239  trace::printf ("%s() @%p %s top exception.\n", __func__, thread,
240  thread->name ());
241  exit_ptr = nullptr;
242  }
243 #else
244  exit_ptr = thread->func_ (thread->func_args_);
245 #endif
246  thread->internal_exit_ (exit_ptr);
247  }
248 
249  thread::thread ()
250  {
251 #if defined(OS_TRACE_RTOS_THREAD)
252  trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
253 #endif
254  }
255 
256  thread::thread (const char* name) :
258  { name }
259  {
260 #if defined(OS_TRACE_RTOS_THREAD)
261  trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
262 #endif
263  }
264 
310  thread::thread (func_t function, func_args_t args, const attributes& attr,
311  const allocator_type& allocator) :
312  thread
313  { nullptr, function, args, attr, allocator }
314  {
315  ;
316  }
317 
359  thread::thread (const char* name, func_t function, func_args_t args,
360  const attributes& attr, const allocator_type& allocator) :
362  { name }
363  {
364 #if defined(OS_TRACE_RTOS_THREAD)
365  trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
366 #endif
367 
368  allocator_ = &allocator;
369 
370  if (attr.th_stack_address != nullptr
371  && attr.th_stack_size_bytes > stack::min_size ())
372  {
373  internal_construct_ (function, args, attr, nullptr, 0);
374  }
375  else
376  {
377  using allocator_type2 = memory::allocator<stack::allocation_element_t>;
378 
379  if (attr.th_stack_size_bytes > stack::min_size ())
380  {
381  allocated_stack_size_elements_ = (attr.th_stack_size_bytes
382  + sizeof(stack::allocation_element_t) - 1)
383  / sizeof(stack::allocation_element_t);
384  }
385  else
386  {
387  allocated_stack_size_elements_ = (stack::default_size ()
388  + sizeof(stack::allocation_element_t) - 1)
389  / sizeof(stack::allocation_element_t);
390  }
391 
392  allocated_stack_address_ =
393  reinterpret_cast<stack::element_t*> (const_cast<allocator_type2&> (allocator).allocate (
394  allocated_stack_size_elements_));
395 
396  // Stack allocation failed.
397  assert(allocated_stack_address_ != nullptr);
398 
399  internal_construct_ (
400  function,
401  args,
402  attr,
403  allocated_stack_address_,
404  allocated_stack_size_elements_
405  * sizeof(stack::allocation_element_t));
406  }
407  }
408 
413  void
414  thread::internal_construct_ (func_t function, func_args_t args,
415  const attributes& attr, void* stack_address,
416  std::size_t stack_size_bytes)
417  {
418  // Don't call this from interrupt handlers.
420 
421  // The thread function must be real.
422  assert(function != nullptr);
423  // Don't forget to set the thread priority.
424  assert(attr.th_priority != priority::none);
425 
426  clock_ = attr.clock != nullptr ? attr.clock : &sysclock;
427 
428  if (stack_address != nullptr)
429  {
430  // The attributes should not define any storage in this case.
431  if (attr.th_stack_size_bytes > stack::min_size ())
432  {
433  // The stack address must be real.
434  assert(attr.th_stack_address == nullptr);
435  }
436 
437  stack ().set (static_cast<stack::element_t*> (stack_address),
438  stack_size_bytes);
439  }
440  else
441  {
442  stack ().set (static_cast<stack::element_t*> (attr.th_stack_address),
443  attr.th_stack_size_bytes);
444  }
445 
446 #if defined(OS_TRACE_RTOS_THREAD)
447  trace::printf ("%s() @%p %s p%u stack{%p,%u}\n", __func__, this, name (),
448  attr.th_priority, stack ().bottom_address_,
449  stack ().size_bytes_);
450 #endif
451 
452  {
453  // Prevent the new thread to execute before all members are set.
454  // ----- Enter critical section -------------------------------------
456 
457  // Get attributes from user structure.
458  prio_assigned_ = attr.th_priority;
459 
460  func_ = function;
461  func_args_ = args;
462 
463  parent_ = this_thread::_thread ();
464  if (scheduler::started () && (parent_ != nullptr))
465  {
466  parent_->children_.link (*this);
467  }
468  else
469  {
470  scheduler::top_threads_list_.link (*this);
471  }
472 
473  stack ().initialize ();
474 
475 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
476 
477  port::thread::create (this);
478  state_ = state::ready;
479 
480 #else
481 
482  // Create the context.
484  &context_, reinterpret_cast<void*> (internal_invoke_with_exit_),
485  this);
486 
487  if (!scheduler::started ())
488  {
489  scheduler::current_thread_ = this;
490  }
491 
492  // Add to ready list, but do not yield yet.
493  resume ();
494 
495 #endif
496  // ----- Exit critical section --------------------------------------
497  }
498  // For just in case the new thread has higher priority.
500  }
501 
521  {
522 #if defined(OS_TRACE_RTOS_THREAD)
523  trace::printf ("%s() @%p %s \n", __func__, this, name ());
524 #endif
525 
526  // Prevent the main thread to destroy itself while running
527  // the exit cleanup code.
528  if (this != &this_thread::thread ())
529  {
530  kill ();
531  }
532  else
533  {
534 #if defined(OS_TRACE_RTOS_THREAD)
535  trace::printf ("%s() @%p %s nop, cannot commit suicide\n", __func__,
536  this, name ());
537 #endif
538  }
539  }
540 
550  void
552  {
553 #if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
554  trace::printf ("%s() @%p %s %u\n", __func__, this, name (),
555  prio_assigned_);
556 #endif
557 
558 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
559 
560  {
561  // ----- Enter critical section -------------------------------------
563 
564  state_ = state::ready;
565  port::thread::resume (this);
566  // ----- Exit critical section --------------------------------------
567  }
568 
569 #else
570 
571  // Don't call this from high priority interrupts.
572  assert(port::interrupts::is_priority_valid ());
573 
574  {
575  // ----- Enter critical section -------------------------------------
577 
578  // If the thread is not already in the ready list, enqueue it.
579  if (ready_node_.next () == nullptr)
580  {
581  scheduler::ready_threads_list_.link (ready_node_);
582  // state::ready set in above link().
583  }
584  // ----- Exit critical section --------------------------------------
585  }
586 
588 
589 #endif
590 
591  }
592 
603  {
604  // trace::printf ("%s() @%p %s\n", __func__, this, name ());
605 
606  if (prio_inherited_ == priority::none)
607  {
608  // The common case is to have no inherited priority;
609  // return the assigned one.
610  return prio_assigned_;
611  }
612  else
613  {
614  // Return the maximum between inherited and assigned.
615  return
616  (prio_inherited_ >= prio_assigned_) ?
617  prio_inherited_ : prio_assigned_;
618  }
619  }
620 
631  {
632  // Don't call this from interrupt handlers.
634 
635  return prio_inherited_;
636  }
637 
657  result_t
659  {
660 #if defined(OS_TRACE_RTOS_THREAD)
661  trace::printf ("%s(%u) @%p %s\n", __func__, prio, this, name ());
662 #endif
663 
664  // Don't call this from interrupt handlers.
666  // Check the priority, it is not in the allowed range.
667  os_assert_err(prio < priority::error, EINVAL);
668  os_assert_err(prio != priority::none, EINVAL);
669 
670  if (prio_assigned_ == prio)
671  {
672  // Optimise, if priority did not change.
673  return result::ok;
674  }
675 
676  prio_assigned_ = prio;
677 
678  result_t res = result::ok;
679 
680 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
681 
682  // The port must perform a context switch.
683  res = port::thread::priority (this, prio);
684 
685 #else
686 
687  if (state_ == state::ready)
688  {
689  // ----- Enter critical section -------------------------------------
691 
692  // Remove from initial location and reinsert according
693  // to new priority.
694  ready_node_.unlink ();
695  scheduler::ready_threads_list_.link (ready_node_);
696  // ----- Exit critical section --------------------------------------
697  }
698 
699  // Mandatory, the priority might have been raised, the
700  // task must be scheduled to run.
702 
703 #endif
704 
705  return res;
706  }
707 
725  result_t
727  {
728 #if defined(OS_TRACE_RTOS_THREAD)
729  trace::printf ("%s(%u) @%p %s\n", __func__, prio, this, name ());
730 #endif
731 
732  // Don't call this from interrupt handlers.
734  // Check the priority, it is not in the allowed range.
735  os_assert_err(prio < priority::error, EINVAL);
736 
737  // Warning: do not check for `priority::none`, since
738  // `mutex::unlock()` sets it when the list of mutexes owned
739  // by a thread is empty.
740 
741  if (prio == prio_inherited_)
742  {
743  // Optimise, if priority did not change.
744  return result::ok;
745  }
746 
747  prio_inherited_ = prio;
748 
749  if (prio_inherited_ < prio_assigned_)
750  {
751  // Optimise, no need to reschedule.
752  return result::ok;
753  }
754 
755  result_t res = result::ok;
756 
757 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
758 
759  // The port must perform a context switch.
760  res = port::thread::priority (this, prio);
761 
762 #else
763 
764  if (state_ == state::ready)
765  {
766  // ----- Enter critical section -------------------------------------
768 
769  // Remove from initial location and reinsert according
770  // to new priority.
771  ready_node_.unlink ();
772  scheduler::ready_threads_list_.link (ready_node_);
773  // ----- Exit critical section --------------------------------------
774  }
775 
776  // Mandatory, the priority might have been raised, the
777  // task must be scheduled to run.
779 
780 #endif
781 
782  return res;
783  }
784 
803  result_t
805  {
806 #if defined(OS_TRACE_RTOS_THREAD)
807  trace::printf ("%s() @%p %s\n", __func__, this, name ());
808 #endif
809 
810  // Don't call this from interrupt handlers.
812 
813 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
814 
815  result_t res = port::thread::detach (this);
816  if (res != result::ok)
817  {
818  return res;
819  }
820 
821 #else
822 
823  // TODO: implement
824 
825 #endif
826 
827  return result::ok;
828  }
829 
858  result_t
859  thread::join (void** exit_ptr)
860  {
861 #if defined(OS_TRACE_RTOS_THREAD)
862  trace::printf ("%s() @%p %s\n", __func__, this, name ());
863 #endif
864 
865  // Don't call this from interrupt handlers.
867  // Don't call this from critical regions.
868  os_assert_err(!scheduler::locked (), EPERM);
869 
870  // Fail if current thread
871  assert(this != this_thread::_thread ());
872 
873  while (state_ != state::destroyed)
874  {
875  joiner_ = this_thread::_thread ();
876  this_thread::_thread ()->internal_suspend_ ();
877  }
878 
879 #if defined(OS_TRACE_RTOS_THREAD)
880  trace::printf ("%s() @%p %s joined\n", __func__, this, name ());
881 #endif
882 
883  if (exit_ptr != nullptr)
884  {
885  *exit_ptr = func_result_;
886  }
887 
888  return result::ok;
889  }
890 
910  result_t
912  {
913 #if defined(OS_TRACE_RTOS_THREAD)
914  trace::printf ("%s() @%p %s\n", __func__, this, name ());
915 #endif
916 
917  // Don't call this from interrupt handlers.
919 
920  // TODO: implement according to POSIX specs.
921  return result::ok;
922  }
923 
935  bool
937  {
938 #if defined(OS_TRACE_RTOS_THREAD)
939  trace::printf ("%s() @%p %s\n", __func__, this, name ());
940 #endif
941 
942  bool tmp = interrupted_;
943  interrupted_ = interrupt;
944 
945  resume ();
946  return tmp;
947  }
948 
959  void
960  thread::internal_suspend_ (void)
961  {
962 #if defined(OS_TRACE_RTOS_THREAD)
963  trace::printf ("%s() @%p %s\n", __func__, this, name ());
964 #endif
965 
966  {
967  // ----- Enter critical section -------------------------------------
969 
970  // Remove this thread from the ready list, if there.
972 
973  state_ = state::suspended;
974  // ----- Exit critical section --------------------------------------
975  }
976 
978  }
979 
980  void
981  thread::internal_exit_ (void* exit_ptr)
982  {
983 #if defined(OS_TRACE_RTOS_THREAD)
984  trace::printf ("%s() @%p %s\n", __func__, this, name ());
985 #endif
986 
987  // Don't call this from interrupt handlers.
988  assert(!interrupts::in_handler_mode ());
989 
990  {
991  // ----- Enter critical section -------------------------------------
993 
994  {
995  // ----- Enter critical section ---------------------------------
997 
998  ready_node_.unlink ();
999 
1000  child_links_.unlink ();
1001  // ----- Exit critical section ----------------------------------
1002  }
1003 
1004  // There must be no children threads still alive.
1005  assert(children_.empty ());
1006  parent_ = nullptr;
1007 
1008  // There must be no more mutexes locked by this thread.
1009  assert(mutexes_.empty ());
1010  assert(acquired_mutexes_ == 0);
1011 
1012  func_result_ = exit_ptr;
1013  // ----- Exit critical section --------------------------------------
1014  }
1015 
1016  {
1017  // ----- Enter critical section -------------------------------------
1019 
1020  // Add to a list of threads to be destroyed by the idle thread.
1021  // Also set state::terminated.
1022  scheduler::terminated_threads_list_.link (ready_node_);
1023  // ----- Exit critical section --------------------------------------
1024  }
1025 
1026 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
1027 
1028  port::thread::destroy_this (this);
1029  // Does not return if the current thread.
1030 
1031 #else
1032 
1033  // At this point, since the thread state is no longer 'running',
1034  // the thread is no longer linked in the READY list.
1036 
1037 #endif
1038 
1039  assert(true);
1040  while (true)
1041  ;
1042 
1043  // Definitely does not return.
1044  }
1045 
1046  void
1047  thread::internal_check_stack_ (void)
1048  {
1049  if (stack ().size () > 0)
1050  {
1051  assert(stack ().check_bottom_magic ());
1052  assert(stack ().check_top_magic ());
1053 
1054 #if defined(OS_TRACE_RTOS_THREAD)
1055  trace::printf ("%s() @%p %s stack: %u/%u bytes used\n", __func__,
1056  this, name (),
1057  stack ().size () - stack ().available (),
1058  stack ().size ());
1059 #endif
1060 
1061  // Clear stack to avoid further checks
1062  stack ().clear ();
1063  }
1064  }
1065 
1066  // Called from kill() and from idle thread.
1067  void
1068  thread::internal_destroy_ (void)
1069  {
1070 #if defined(OS_TRACE_RTOS_THREAD)
1071  trace::printf ("%s() @%p %s\n", __func__, this, name ());
1072 #endif
1073 
1074  internal_check_stack_ ();
1075 
1076  if (allocated_stack_address_ != nullptr)
1077  {
1078  typedef typename std::allocator_traits<allocator_type>::pointer pointer;
1079 
1080  static_cast<allocator_type*> (const_cast<void*> (allocator_))->deallocate (
1081  reinterpret_cast<pointer> (allocated_stack_address_),
1082  allocated_stack_size_elements_);
1083 
1084  allocated_stack_address_ = nullptr;
1085  }
1086 
1087  {
1088  // ----- Enter critical section -------------------------------------
1090 
1091  mutexes_list& mx_list = reinterpret_cast<mutexes_list&> (mutexes_);
1092  while (not mx_list.empty ())
1093  {
1094  auto* mx = mx_list.unlink_head ();
1095 
1096  mx->internal_mark_owner_dead_ ();
1097 
1098  // Unlock the mutex as owned by the thread itself.
1099  mx->internal_unlock_ (this);
1100  }
1101  // ----- Exit critical section --------------------------------------
1102  }
1103 
1104  state_ = state::destroyed;
1105 
1106  if (joiner_ != nullptr)
1107  {
1108  joiner_->resume ();
1109  }
1110  }
1111 
1126  result_t
1128  {
1129 #if defined(OS_TRACE_RTOS_THREAD)
1130  trace::printf ("%s() @%p %s\n", __func__, this, name ());
1131 #endif
1132 
1133  // Don't call this from interrupt handlers.
1135 
1136  {
1137  // ----- Enter critical section -------------------------------------
1139 
1140  if (state_ == state::destroyed)
1141  {
1142 #if defined(OS_TRACE_RTOS_THREAD)
1143  trace::printf ("%s() @%p %s already gone\n", __func__, this,
1144  name ());
1145 #endif
1146  return result::ok; // Already exited itself
1147  }
1148 
1149  {
1150  // ----- Enter critical section ---------------------------------
1152 
1153  // Remove thread from the funeral list and kill it here.
1154  ready_node_.unlink ();
1155 
1156  // If the thread is waiting on an event, remove it from the list.
1157  if (waiting_node_ != nullptr)
1158  {
1159  waiting_node_->unlink ();
1160  }
1161 
1162  // If the thread is waiting on a timeout, remove it from the list.
1163  if (clock_node_ != nullptr)
1164  {
1165  clock_node_->unlink ();
1166  }
1167 
1168  child_links_.unlink ();
1169  // ----- Exit critical section ----------------------------------
1170  }
1171 
1172  // The must be no more children threads alive.
1173  assert(children_.empty ());
1174  parent_ = nullptr;
1175 
1176 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
1177 
1178  port::thread::destroy_other (this);
1179 
1180 #endif
1181 
1182  func_result_ = nullptr;
1183 
1184  internal_destroy_ ();
1185 
1186  // There must be no mutexes locked by this thread.
1187  // Must have been cleaned before.
1188  assert(mutexes_.empty ());
1189  assert(acquired_mutexes_ == 0);
1190 
1191  // ----- Exit critical section --------------------------------------
1192  }
1193 
1194  return result::ok;
1195  }
1196 
1205  result_t
1207  {
1208 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1209  trace::printf ("%s(0x%X) @%p %s <0x%X\n", __func__, mask, this, name (),
1210  event_flags_.mask ());
1211 #endif
1212 
1213  result_t res = event_flags_.raise (mask, oflags);
1214 
1215  this->resume ();
1216 
1217 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1218  trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
1219  event_flags_.mask ());
1220 #endif
1221 
1222  return res;
1223  }
1224 
1229  result_t
1230  thread::internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1231  flags::mode_t mode)
1232  {
1233 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1234  trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
1235  name (), event_flags_.mask ());
1236 #endif
1237 
1238  // Don't call this from interrupt handlers.
1240  // Don't call this from critical regions.
1241  os_assert_err(!scheduler::locked (), EPERM);
1242 
1243  {
1244  // ----- Enter critical section ---------------------------------
1246 
1247  if (event_flags_.check_raised (mask, oflags, mode))
1248  {
1249 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1250  trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1251  this, name (), event_flags_.mask ());
1252 #endif
1253  return result::ok;
1254  }
1255  // ----- Exit critical section ----------------------------------
1256  }
1257 
1258 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1259  clock::timestamp_t begin_timestamp = clock_->now ();
1260 #endif
1261  for (;;)
1262  {
1263  {
1264  // ----- Enter critical section ---------------------------------
1266 
1267  if (event_flags_.check_raised (mask, oflags, mode))
1268  {
1269 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1270  clock::duration_t slept_ticks =
1271  static_cast<clock::duration_t> (clock_->now ()
1272  - begin_timestamp);
1273  trace::printf ("%s(0x%X,%u) in %d @%p %s >0x%X\n", __func__,
1274  mask, mode, slept_ticks, this, name (),
1275  event_flags_.mask ());
1276 #endif
1277  return result::ok;
1278  }
1279  // ----- Exit critical section ----------------------------------
1280  }
1281 
1282  internal_suspend_ ();
1283 
1284  if (interrupted ())
1285  {
1286 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1287  trace::printf ("%s(0x%X,%u) EINTR @%p %s\n", __func__, mask, mode,
1288  this, name ());
1289 #endif
1290  return EINTR;
1291  }
1292  }
1293 
1294  /* NOTREACHED */
1295  return ENOTRECOVERABLE;
1296  }
1297 
1298  result_t
1299  thread::internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1300  flags::mode_t mode)
1301  {
1302 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1303  trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
1304  name (), event_flags_.mask ());
1305 #endif
1306 
1307  // Don't call this from interrupt handlers.
1309 
1310  {
1311  // ----- Enter critical section -------------------------------------
1313 
1314  if (event_flags_.check_raised (mask, oflags, mode))
1315  {
1316 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1317  trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1318  this, name (), event_flags_.mask ());
1319 #endif
1320  return result::ok;
1321  }
1322  else
1323  {
1324 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1325  trace::printf ("%s(0x%X,%u) EWOULDBLOCK @%p %s \n", __func__,
1326  mask, mode, this, name ());
1327 #endif
1328  return EWOULDBLOCK;
1329  }
1330  // ----- Exit critical section --------------------------------------
1331  }
1332  }
1333 
1334  result_t
1335  thread::internal_flags_timed_wait_ (flags::mask_t mask,
1336  clock::duration_t timeout,
1337  flags::mask_t* oflags,
1338  flags::mode_t mode)
1339  {
1340 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1341  trace::printf ("%s(0x%X,%u,%u) @%p %s <0x%X\n", __func__, mask, timeout,
1342  mode, this, name (), event_flags_.mask ());
1343 #endif
1344 
1345  // Don't call this from interrupt handlers.
1347  // Don't call this from critical regions.
1348  os_assert_err(!scheduler::locked (), EPERM);
1349 
1350  {
1351  // ----- Enter critical section -------------------------------------
1353 
1354  if (event_flags_.check_raised (mask, oflags, mode))
1355  {
1356 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1357  trace::printf ("%s(0x%X,%u,%u) @%p %s >0x%X\n", __func__, mask,
1358  timeout, mode, this, name (),
1359  event_flags_.mask ());
1360 #endif
1361  return result::ok;
1362  }
1363  // ----- Exit critical section --------------------------------------
1364  }
1365 
1366  internal::clock_timestamps_list& clock_list = clock_->steady_list ();
1367  clock::timestamp_t timeout_timestamp = clock_->steady_now () + timeout;
1368 
1369 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1370  clock::timestamp_t begin_timestamp = clock_->steady_now ();
1371 #endif
1372 
1373  // Prepare a timeout node pointing to the current thread.
1374  internal::timeout_thread_node timeout_node
1375  { timeout_timestamp, *this };
1376 
1377  for (;;)
1378  {
1379  {
1380  // ----- Enter critical section ---------------------------------
1382 
1383  if (event_flags_.check_raised (mask, oflags, mode))
1384  {
1385 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1386  clock::duration_t slept_ticks =
1387  static_cast<clock::duration_t> (clock_->steady_now ()
1388  - begin_timestamp);
1389  trace::printf ("%s(0x%X,%u,%u) in %u @%p %s >0x%X\n",
1390  __func__, mask, timeout, mode,
1391  static_cast<unsigned int> (slept_ticks), this,
1392  name (), event_flags_.mask ());
1393 #endif
1394  return result::ok;
1395  }
1396 
1397  // Remove this thread from the ready list, if there.
1399 
1400  // Add this thread to the clock timeout list.
1401  clock_list.link (timeout_node);
1402  timeout_node.thread.clock_node_ = &timeout_node;
1403 
1404  state_ = state::suspended;
1405  // ----- Exit critical section ----------------------------------
1406  }
1407 
1409 
1410  {
1411  // ----- Enter critical section ---------------------------------
1413 
1414  // Remove the thread from the clock timeout list,
1415  // if not already removed by the timer.
1416  timeout_node.thread.clock_node_ = nullptr;
1417  timeout_node.unlink ();
1418  // ----- Exit critical section ----------------------------------
1419  }
1420 
1421  if (interrupted ())
1422  {
1423 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1424  trace::printf ("%s(0x%X,%u,%u) EINTR @%p %s\n", __func__, mask,
1425  timeout, mode, this, name ());
1426 #endif
1427  return EINTR;
1428  }
1429 
1430  if (clock_->steady_now () >= timeout_timestamp)
1431  {
1432 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1433  trace::printf ("%s(0x%X,%u,%u) ETIMEDOUT @%p %s\n", __func__,
1434  mask, timeout, mode, this, name ());
1435 #endif
1436  return ETIMEDOUT;
1437  }
1438  }
1439 
1440  return ENOTRECOVERABLE;
1441  }
1442 
1455  thread::internal_flags_get_ (flags::mask_t mask, flags::mode_t mode)
1456  {
1457 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1458  trace::printf ("%s(0x%X) @%p %s\n", __func__, mask, this, name ());
1459 #endif
1460 
1461  // Don't call this from interrupt handlers.
1463 
1464  flags::mask_t ret = event_flags_.get (mask, mode);
1465 
1466 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1467  trace::printf ("%s(0x%X)=0x%X @%p %s\n", __func__, mask,
1468  event_flags_.mask (), this, name ());
1469 #endif
1470  // Return the selected bits.
1471  return ret;
1472  }
1473 
1479  result_t
1480  thread::internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags)
1481  {
1482 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1483  trace::printf ("%s(0x%X) @%p %s <0x%X\n", __func__, mask, this, name (),
1484  event_flags_.mask ());
1485 #endif
1486 
1487  // Don't call this from interrupt handlers.
1489 
1490  result_t res = event_flags_.clear (mask, oflags);
1491 
1492 #if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1493  trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
1494  event_flags_.mask ());
1495 #endif
1496  return res;
1497  }
1498 
1503  // ------------------------------------------------------------------------
1509  namespace this_thread
1510  {
1511 
1516  rtos::thread*
1517  _thread (void)
1518  {
1519  rtos::thread* th;
1520 
1521 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
1522 
1523  th = port::this_thread::thread ();
1524 
1525 #else
1526 
1527  th = scheduler::current_thread_;
1528 
1529 #endif
1530  return th;
1531  }
1532 
1542  rtos::thread&
1543  thread (void)
1544  {
1545  // Don't call this from interrupt handlers.
1547 
1548  rtos::thread* th;
1549 
1550  th = _thread ();
1551 
1552  // Could not get the current thread.
1553  assert(th != nullptr);
1554  return (*th);
1555  }
1556 
1563  void
1564  yield (void)
1565  {
1566  // Don't call this from interrupt handlers.
1568 
1569  if (!scheduler::started ())
1570  {
1571 #if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1572  trace::printf ("%s() nop %s \n", __func__, _thread ()->name ());
1573 #endif
1574  return;
1575  }
1576 
1577 #if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1578  trace::printf ("%s() from %s\n", __func__, _thread ()->name ());
1579 #endif
1580 
1581 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
1582 
1584 
1585 #else
1586 
1588 
1589 #endif
1590 
1591 #if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1592  trace::printf ("%s() to %s\n", __func__, _thread ()->name ());
1593 #endif
1594  }
1595 
1596  } /* namespace this_thread */
1597 
1598  // --------------------------------------------------------------------------
1599  } /* namespace rtos */
1600 } /* namespace os */
Thread attributes.
Definition: os-thread.h:770
static const attributes initializer
Default thread initialiser.
Definition: os-thread.h:968
Terminated and resources (like stack) released.
Definition: os-thread.h:378
void yield(void)
Yield the CPU to the next ready thread.
#define os_assert_throw(__e, __er)
Assert or throw a system error exception.
Definition: os-decls.h:1127
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition: os-clocks.h:81
Thread stack.
Definition: os-thread.h:406
static std::size_t default_size(void)
Get the default stack size.
Definition: os-thread.h:2190
void link(timestamp_node &node)
Add a new thread node to the list.
Definition: os-lists.cpp:384
priority_t th_priority
Thread initial priority.
Definition: os-thread.h:842
virtual ~thread()
Destruct the thread object instance.
Definition: os-thread.cpp:520
List of intrusive nodes.
Definition: lists.h:708
void yield(void)
Yield execution to the next ready thread.
Definition: os-thread.cpp:1564
rtos::clock * clock
Attribute with the address of the clock to be used for timeouts.
Definition: os-decls.h:615
priority_t priority_inherited(void)
Get the inherited scheduling priority.
Definition: os-thread.cpp:630
state_t locked(state_t state)
Lock/unlock the scheduler.
Definition: os-sched.h:899
void deallocate(value_type *addr, std::size_t elements) noexcept
Deallocate the number of memory blocks of type value_type.
Definition: os-memory.h:1500
priority_t priority(void)
Get the current scheduling priority.
Definition: os-thread.cpp:602
static const element_t magic
Definition: os-thread.h:426
Interrupts critical section RAII helper.
Definition: os-sched.h:498
stack::element_t * top(void)
Get the top stack address.
Definition: os-thread.h:2122
void * th_stack_address
Address of the user defined storage for the thread stack.
Definition: os-thread.h:818
void clear(void)
Clear the stack pointer and size.
Definition: os-thread.h:2086
result_t kill(void)
Force thread termination.
Definition: os-thread.cpp:1127
void yield() noexcept
Yield the CPU to the next ready thread.
System namespace.
Double linked list node, with time stamp and thread.
Definition: os-lists.h:213
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition: os-thread.h:2098
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition: os-thread.h:416
static void create(void *context, void *func, void *args)
utils::intrusive_list< mutex, utils::double_list_links, &mutex::owner_links_ > mutexes_list
Definition: os-mutex.cpp:298
Scheduler critical section RAII helper.
Definition: os-sched.h:170
Present in the READY list and competing for CPU.
Definition: os-thread.h:362
pointer unlink_head(void)
Unlink the first element from the list.
Definition: lists.h:1262
object_named_system()
Construct a named system object instance.
Definition: os-decls.h:768
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition: os-thread.h:424
const char * name(void) const
Get object name.
Definition: os-decls.h:760
uint8_t priority_t
Type of variables holding thread priorities.
Definition: os-thread.h:252
A namespace for functions applying to the current thread.
POSIX compliant thread, using the default RTOS allocator.
Definition: os-thread.h:230
bool started(void)
Check if the scheduler was started.
Definition: os-sched.h:827
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition: os-clocks.h:72
std::size_t th_stack_size_bytes
Size of the user defined storage for the thread stack, in bytes.
Definition: os-thread.h:831
Single file µOS++ RTOS definitions.
clock_systick sysclock
The system clock object instance.
Definition: os-clocks.cpp:551
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition: trace.cpp:74
class thread::stack & stack(void)
Get the thread context stack.
Definition: os-thread.h:2396
Function completed; no errors or events occurred.
Definition: os-decls.h:181
Not present in the READY list, waiting for an event.
Definition: os-thread.h:370
thread(func_t function, func_args_t args, const attributes &attr=initializer, const allocator_type &allocator=allocator_type())
Construct a thread object instance.
Definition: os-thread.cpp:310
result_t cancel(void)
Cancel thread execution.
Definition: os-thread.cpp:911
static std::size_t min_size(void)
Get the min stack size.
Definition: os-thread.h:2166
bool empty(void) const
Check if the list is empty.
Definition: lists.h:1032
result_t join(void **exit_ptr=nullptr)
Wait for thread termination.
Definition: os-thread.cpp:859
void initialize(void)
Align the pointers and initialise to a known pattern.
Ordered list of time stamp nodes.
Definition: os-lists.h:657
void *(*)(func_args_t args) func_t
Type of thread function.
Definition: os-thread.h:397
thread & thread(void)
Get the current running thread.
Definition: os-thread.cpp:1543
uint32_t mask_t
Type of variables holding flags masks.
Definition: os-decls.h:265
uint32_t mode_t
Type of variables holding flags modes.
Definition: os-decls.h:275
uint32_t result_t
Type of values returned by RTOS functions.
Definition: os-decls.h:96
void resume(void)
Resume the thread.
Definition: os-thread.cpp:551
bool interrupt(bool interrupt=true)
Set the interrupt flag, possibly interrupting the thread.
Definition: os-thread.cpp:936
result_t flags_raise(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Raise thread event flags.
Definition: os-thread.cpp:1206
allocator_stateless_default_resource< T > allocator
Type of allocator used by the system objects. Must be stateless.
Definition: os-types.h:57
Standard allocator based on the RTOS system default memory manager.
Definition: os-decls.h:82
std::size_t available(void)
Compute how much available stack remains.
Definition: os-thread.cpp:193
_func_args_t func_args_t
Type of thread function arguments.
Definition: os-thread.h:389
bool interrupted(void)
Check if interrupted.
Definition: os-thread.h:2326
result_t detach(void)
Detach a thread.
Definition: os-thread.cpp:804
#define os_assert_err(__e, __er)
Assert or return an error.
Definition: os-decls.h:1112
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition: os-sched.h:1091