source: rtems/cpukit/include/rtems/score/threadimpl.h @ 01d5944

5
Last change on this file since 01d5944 was 01d5944, checked in by Sebastian Huber <sebastian.huber@…>, on 12/09/19 at 13:48:34

score: Move thread stack allocation

Move thread stack allocation to caller side of _Thread_Initialize().

Update #3835.

  • Property mode set to 100644
File size: 68.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreThread
5 *
6 * @brief Inlined Routines from the Thread Handler
7 *
8 * This file contains the macro implementation of the inlined
9 * routines from the Thread handler.
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2008.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  Copyright (c) 2014, 2017 embedded brains GmbH.
17 *
18 *  The license and distribution terms for this file may be
19 *  found in the file LICENSE in this distribution or at
20 *  http://www.rtems.org/license/LICENSE.
21 */
22
23#ifndef _RTEMS_SCORE_THREADIMPL_H
24#define _RTEMS_SCORE_THREADIMPL_H
25
26#include <rtems/score/thread.h>
27#include <rtems/score/assert.h>
28#include <rtems/score/chainimpl.h>
29#include <rtems/score/interr.h>
30#include <rtems/score/isr.h>
31#include <rtems/score/objectimpl.h>
32#include <rtems/score/schedulernodeimpl.h>
33#include <rtems/score/statesimpl.h>
34#include <rtems/score/status.h>
35#include <rtems/score/sysstate.h>
36#include <rtems/score/timestampimpl.h>
37#include <rtems/score/threadqimpl.h>
38#include <rtems/score/todimpl.h>
39#include <rtems/score/watchdogimpl.h>
40#include <rtems/config.h>
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/**
47 * @addtogroup RTEMSScoreThread
48 *
49 * @{
50 */
51
52/**
53 *  Self for the GNU Ada Run-Time
54 */
55extern void *rtems_ada_self;
56
57/**
58 * @brief Object identifier of the global constructor thread.
59 *
60 * This variable is set by _RTEMS_tasks_Initialize_user_tasks_body() or
61 * _POSIX_Threads_Initialize_user_threads_body().
62 *
63 * It is consumed by _Thread_Handler().
64 */
65extern Objects_Id _Thread_Global_constructor;
66
67/**
68 *  The following points to the thread whose floating point
69 *  context is currently loaded.
70 */
71#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
72extern Thread_Control *_Thread_Allocated_fp;
73#endif
74
75#if defined(RTEMS_SMP)
76#define THREAD_OF_SCHEDULER_HELP_NODE( node ) \
77  RTEMS_CONTAINER_OF( node, Thread_Control, Scheduler.Help_node )
78#endif
79
80typedef bool ( *Thread_Visitor )( Thread_Control *the_thread, void *arg );
81
82/**
83 * @brief Calls the visitor with all threads and the given argument until
84 *      it is done.
85 *
86 * @param visitor Function that gets a thread and @a arg as parameters and
87 *      returns if it is done.
88 * @param arg Parameter for @a visitor
89 */
90void _Thread_Iterate(
91  Thread_Visitor  visitor,
92  void           *arg
93);
94
95/**
96 * @brief Initializes the thread information
97 *
98 * @param[out] information Information to initialize.
99 */
100void _Thread_Initialize_information( Thread_Information *information );
101
102/**
103 * @brief Initializes thread handler.
104 *
105 * This routine performs the initialization necessary for this handler.
106 */
107void _Thread_Handler_initialization(void);
108
109/**
110 * @brief Creates idle thread.
111 *
112 * This routine creates the idle thread.
113 *
114 * @warning No thread should be created before this one.
115 */
116void _Thread_Create_idle(void);
117
118/**
119 * @brief Starts thread multitasking.
120 *
121 * This routine initiates multitasking.  It is invoked only as
122 * part of initialization and its invocation is the last act of
123 * the non-multitasking part of the system initialization.
124 */
125void _Thread_Start_multitasking( void ) RTEMS_NO_RETURN;
126
127/**
128 * @brief The configuration of a new thread to initialize.
129 */
130typedef struct {
131  /**
132   * @brief The scheduler control instance for the thread.
133   */
134  const struct _Scheduler_Control *scheduler;
135
136  /**
137   * @brief The starting address of the stack area.
138   */
139  void *stack_area;
140
141  /**
142   * @brief The size of the stack area in bytes.
143   */
144  size_t stack_size;
145
146  /**
147   * @brief The address of the allocated stack area or NULL.
148   */
149  void *allocated_stack;
150
151  /**
152   * @brief The new thread's priority.
153   */
154  Priority_Control priority;
155
156  /**
157   * @brief The thread's budget algorithm.
158   */
159  Thread_CPU_budget_algorithms budget_algorithm;
160
161  /**
162   * @brief The thread's initial budget callout.
163   */
164  Thread_CPU_budget_algorithm_callout budget_callout;
165
166  /**
167   * @brief Name of the object for the thread.
168   */
169  Objects_Name name;
170
171  /**
172   * @brief The thread's initial ISR level.
173   */
174  uint32_t isr_level;
175
176  /**
177   * @brief Indicates whether the thread needs a floating-point area.
178   */
179  bool is_fp;
180
181  /**
182   * @brief Indicates whether the new thread is preemptible.
183   */
184  bool is_preemptible;
185} Thread_Configuration;
186
187/**
188 * @brief Initializes thread.
189 *
190 * This routine initializes the specified the thread.  It allocates
191 * all memory associated with this thread.  It completes by adding
192 * the thread to the local object table so operations on this
193 * thread id are allowed.
194 *
195 * @note If stack_area is NULL, it is allocated from the workspace.
196 *
197 * @note If the stack is allocated from the workspace, then it is
198 *       guaranteed to be of at least minimum size.
199 *
200 * @param information The thread information.
201 * @param the_thread The thread to initialize.
202 * @param config The configuration of the thread to initialize.
203 *
204 * @retval true The thread initialization was successful.
205 * @retval false The thread initialization failed.
206 */
207bool _Thread_Initialize(
208  Thread_Information         *information,
209  Thread_Control             *the_thread,
210  const Thread_Configuration *config
211);
212
213/**
214 * @brief Initializes thread and executes it.
215 *
216 * This routine initializes the executable information for a thread
217 * and makes it ready to execute.  After this routine executes, the
218 * thread competes with all other threads for CPU time.
219 *
220 * @param the_thread The thread to be started.
221 * @param entry The thread entry information.
222 */
223bool _Thread_Start(
224  Thread_Control                 *the_thread,
225  const Thread_Entry_information *entry,
226  ISR_lock_Context               *lock_context
227);
228
229/**
230 * @brief Restarts the currently executing thread.
231 *
232 * @param[in, out] executing The currently executing thread.
233 * @param entry The start entry information for @a executing.
234 * @param lock_context The lock context.
235 */
236void _Thread_Restart_self(
237  Thread_Control                 *executing,
238  const Thread_Entry_information *entry,
239  ISR_lock_Context               *lock_context
240) RTEMS_NO_RETURN;
241
242/**
243 * @brief Restarts the thread.
244 *
245 * @param[in, out] the_thread The thread to restart.
246 * @param entry The start entry information for @a the_thread.
247 * @param lock_context The lock context.
248 *
249 * @retval true The operation was successful.
250 * @retval false The operation failed.
251 */
252bool _Thread_Restart_other(
253  Thread_Control                 *the_thread,
254  const Thread_Entry_information *entry,
255  ISR_lock_Context               *lock_context
256);
257
258/**
259 * @brief Yields the currently executing thread.
260 *
261 * @param[in, out] executing The thread that performs a yield.
262 */
263void _Thread_Yield( Thread_Control *executing );
264
265/**
266 * @brief Changes the currently executing thread to a new state with the sets.
267 *
268 * @param clear States to clear.
269 * @param set States to set.
270 * @param ignore States to ignore.
271 *
272 * @return The previous state the thread was in.
273 */
274Thread_Life_state _Thread_Change_life(
275  Thread_Life_state clear,
276  Thread_Life_state set,
277  Thread_Life_state ignore
278);
279
280/**
281 * @brief Set the thread to life protected.
282 *
283 * Calls _Thread_Change_life with the given state AND THREAD_LIFE_PROTECTED to
284 * set and THREAD_LIFE_PROTECTED to clear.
285 *
286 * @param state The states to set.
287 *
288 * @return The previous state the thread was in.
289 */
290Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state );
291
292/**
293 * @brief Kills all zombie threads in the system.
294 *
295 * Threads change into the zombie state as the last step in the thread
296 * termination sequence right before a context switch to the heir thread is
297 * initiated.  Since the thread stack is still in use during this phase we have
298 * to postpone the thread stack reclamation until this point.  On SMP
299 * configurations we may have to busy wait for context switch completion here.
300 */
301void _Thread_Kill_zombies( void );
302
303/**
304 * @brief Exits the currently executing thread.
305 *
306 * @param[in, out] executing The currently executing thread.
307 * @param set The states to set.
308 * @param[out] exit_value Contains the exit value of the thread.
309 */
310void _Thread_Exit(
311  Thread_Control    *executing,
312  Thread_Life_state  set,
313  void              *exit_value
314);
315
316/**
317 * @brief Joins the currently executing thread with the given thread to wait
318 *      for.
319 *
320 * @param[in, out] the_thread The thread to wait for.
321 * @param waiting_for_join The states control for the join.
322 * @param[in, out] executing The currently executing thread.
323 * @param queue_context The thread queue context.
324 */
325void _Thread_Join(
326  Thread_Control       *the_thread,
327  States_Control        waiting_for_join,
328  Thread_Control       *executing,
329  Thread_queue_Context *queue_context
330);
331
332/**
333 * @brief Cancels the thread.
334 *
335 * @param[in, out] the_thread The thread to cancel.
336 * @param executing The currently executing thread.
337 * @param exit_value The exit value for the thread.
338 */
339void _Thread_Cancel(
340  Thread_Control *the_thread,
341  Thread_Control *executing,
342  void           *exit_value
343);
344
345typedef struct {
346  Thread_queue_Context  Base;
347  Thread_Control       *cancel;
348} Thread_Close_context;
349
350/**
351 * @brief Closes the thread.
352 *
353 * Closes the thread object and starts the thread termination sequence.  In
354 * case the executing thread is not terminated, then this function waits until
355 * the terminating thread reached the zombie state.
356 *
357 * @param the_thread The thread to close.
358 * @param executing The currently executing thread.
359 * @param[in, out] context The thread close context.
360 */
361void _Thread_Close(
362  Thread_Control       *the_thread,
363  Thread_Control       *executing,
364  Thread_Close_context *context
365);
366
367/**
368 * @brief Checks if the thread is ready.
369 *
370 * @param the_thread The thread to check if it is ready.
371 *
372 * @retval true The thread is currently in the ready state.
373 * @retval false The thread is currently not ready.
374 */
375RTEMS_INLINE_ROUTINE bool _Thread_Is_ready( const Thread_Control *the_thread )
376{
377  return _States_Is_ready( the_thread->current_state );
378}
379
380/**
381 * @brief Clears the specified thread state without locking the lock context.
382 *
383 * In the case the previous state is a non-ready state and the next state is
384 * the ready state, then the thread is unblocked by the scheduler.
385 *
386 * @param[in, out] the_thread The thread.
387 * @param state The state to clear.  It must not be zero.
388 *
389 * @return The thread's previous state.
390 */
391States_Control _Thread_Clear_state_locked(
392  Thread_Control *the_thread,
393  States_Control  state
394);
395
396/**
397 * @brief Clears the specified thread state.
398 *
399 * In the case the previous state is a non-ready state and the next state is
400 * the ready state, then the thread is unblocked by the scheduler.
401 *
402 * @param[in, out] the_thread The thread.
403 * @param state The state to clear.  It must not be zero.
404 *
405 * @return The previous state.
406 */
407States_Control _Thread_Clear_state(
408  Thread_Control *the_thread,
409  States_Control  state
410);
411
412/**
413 * @brief Sets the specified thread state without locking the lock context.
414 *
415 * In the case the previous state is the ready state, then the thread is blocked
416 * by the scheduler.
417 *
418 * @param[in, out] the_thread The thread.
419 * @param state The state to set.  It must not be zero.
420 *
421 * @return The previous state.
422 */
423States_Control _Thread_Set_state_locked(
424  Thread_Control *the_thread,
425  States_Control  state
426);
427
428/**
429 * @brief Sets the specified thread state.
430 *
431 * In the case the previous state is the ready state, then the thread is blocked
432 * by the scheduler.
433 *
434 * @param[in, out] the_thread The thread.
435 * @param state The state to set.  It must not be zero.
436 *
437 * @return The previous state.
438 */
439States_Control _Thread_Set_state(
440  Thread_Control *the_thread,
441  States_Control  state
442);
443
444/**
445 * @brief Initializes enviroment for a thread.
446 *
447 * This routine initializes the context of @a the_thread to its
448 * appropriate starting state.
449 *
450 * @param[in, out] the_thread The pointer to the thread control block.
451 */
452void _Thread_Load_environment(
453  Thread_Control *the_thread
454);
455
456/**
457 * @brief Calls the start kinds idle entry of the thread.
458 *
459 * @param executing The currently executing thread.
460 */
461void _Thread_Entry_adaptor_idle( Thread_Control *executing );
462
463/**
464 * @brief Calls the start kinds numeric entry of the thread.
465 *
466 * @param executing The currently executing thread.
467 */
468void _Thread_Entry_adaptor_numeric( Thread_Control *executing );
469
470/**
471 * @brief Calls the start kinds pointer entry of the thread.
472 *
473 * Stores the return value in the Wait.return_argument of the thread.
474 *
475 * @param executing The currently executing thread.
476 */
477void _Thread_Entry_adaptor_pointer( Thread_Control *executing );
478
479/**
480 * @brief Wrapper function for all threads.
481 *
482 * This routine is the wrapper function for all threads.  It is
483 * the starting point for all threads.  The user provided thread
484 * entry point is invoked by this routine.  Operations
485 * which must be performed immediately before and after the user's
486 * thread executes are found here.
487 *
488 * @note On entry, it is assumed all interrupts are blocked and that this
489 * routine needs to set the initial isr level.  This may or may not
490 * actually be needed by the context switch routine and as a result
491 * interrupts may already be at there proper level.  Either way,
492 * setting the initial isr level properly here is safe.
493 */
494void _Thread_Handler( void );
495
496/**
497 * @brief Acquires the lock context in a critical section.
498 *
499 * @param the_thread The thread to acquire the lock context.
500 * @param lock_context The lock context.
501 */
502RTEMS_INLINE_ROUTINE void _Thread_State_acquire_critical(
503  Thread_Control   *the_thread,
504  ISR_lock_Context *lock_context
505)
506{
507  _Thread_queue_Do_acquire_critical( &the_thread->Join_queue, lock_context );
508}
509
510/**
511 * @brief Disables interrupts and acquires the lock_context.
512 *
513 * @param the_thread The thread to acquire the lock context.
514 * @param lock_context The lock context.
515 */
516RTEMS_INLINE_ROUTINE void _Thread_State_acquire(
517  Thread_Control   *the_thread,
518  ISR_lock_Context *lock_context
519)
520{
521  _ISR_lock_ISR_disable( lock_context );
522  _Thread_State_acquire_critical( the_thread, lock_context );
523}
524
525/**
526 * @brief Disables interrupts and acquires the lock context for the currently
527 *      executing thread.
528 *
529 * @param lock_context The lock context.
530 *
531 * @return The currently executing thread.
532 */
533RTEMS_INLINE_ROUTINE Thread_Control *_Thread_State_acquire_for_executing(
534  ISR_lock_Context *lock_context
535)
536{
537  Thread_Control *executing;
538
539  _ISR_lock_ISR_disable( lock_context );
540  executing = _Thread_Executing;
541  _Thread_State_acquire_critical( executing, lock_context );
542
543  return executing;
544}
545
546/**
547 * @brief Release the lock context in a critical section.
548 *
549 * @param the_thread The thread to release the lock context.
550 * @param lock_context The lock context.
551 */
552RTEMS_INLINE_ROUTINE void _Thread_State_release_critical(
553  Thread_Control   *the_thread,
554  ISR_lock_Context *lock_context
555)
556{
557  _Thread_queue_Do_release_critical( &the_thread->Join_queue, lock_context );
558}
559
560/**
561 * @brief Releases the lock context and enables interrupts.
562 *
563 * @param[in, out] the_thread The thread to release the lock context.
564 * @param[out] lock_context The lock context.
565 */
566RTEMS_INLINE_ROUTINE void _Thread_State_release(
567  Thread_Control   *the_thread,
568  ISR_lock_Context *lock_context
569)
570{
571  _Thread_State_release_critical( the_thread, lock_context );
572  _ISR_lock_ISR_enable( lock_context );
573}
574
575/**
576 * @brief Checks if the thread is owner of the lock of the join queue.
577 *
578 * @param the_thread The thread for the verification.
579 *
580 * @retval true The thread is owner of the lock of the join queue.
581 * @retval false The thread is not owner of the lock of the join queue.
582 */
583#if defined(RTEMS_DEBUG)
584RTEMS_INLINE_ROUTINE bool _Thread_State_is_owner(
585  const Thread_Control *the_thread
586)
587{
588  return _Thread_queue_Is_lock_owner( &the_thread->Join_queue );
589}
590#endif
591
592/**
593 * @brief Performs the priority actions specified by the thread queue context
594 * along the thread queue path.
595 *
596 * The caller must be the owner of the thread wait lock.
597 *
598 * @param start_of_path The start thread of the thread queue path.
599 * @param queue_context The thread queue context specifying the thread queue
600 *   path and initial thread priority actions.
601 *
602 * @see _Thread_queue_Path_acquire_critical().
603 */
604void _Thread_Priority_perform_actions(
605  Thread_Control       *start_of_path,
606  Thread_queue_Context *queue_context
607);
608
609/**
610 * @brief Adds the specified thread priority node to the corresponding thread
611 * priority aggregation.
612 *
613 * The caller must be the owner of the thread wait lock.
614 *
615 * @param the_thread The thread.
616 * @param priority_node The thread priority node to add.
617 * @param queue_context The thread queue context to return an updated set of
618 *   threads for _Thread_Priority_update().  The thread queue context must be
619 *   initialized via _Thread_queue_Context_clear_priority_updates() before a
620 *   call of this function.
621 *
622 * @see _Thread_Wait_acquire().
623 */
624void _Thread_Priority_add(
625  Thread_Control       *the_thread,
626  Priority_Node        *priority_node,
627  Thread_queue_Context *queue_context
628);
629
630/**
631 * @brief Removes the specified thread priority node from the corresponding
632 * thread priority aggregation.
633 *
634 * The caller must be the owner of the thread wait lock.
635 *
636 * @param the_thread The thread.
637 * @param priority_node The thread priority node to remove.
638 * @param queue_context The thread queue context to return an updated set of
639 *   threads for _Thread_Priority_update().  The thread queue context must be
640 *   initialized via _Thread_queue_Context_clear_priority_updates() before a
641 *   call of this function.
642 *
643 * @see _Thread_Wait_acquire().
644 */
645void _Thread_Priority_remove(
646  Thread_Control       *the_thread,
647  Priority_Node        *priority_node,
648  Thread_queue_Context *queue_context
649);
650
651/**
652 * @brief Propagates a thread priority value change in the specified thread
653 * priority node to the corresponding thread priority aggregation.
654 *
655 * The caller must be the owner of the thread wait lock.
656 *
657 * @param the_thread The thread.
658 * @param[out] priority_node The thread priority node to change.
659 * @param prepend_it In case this is true, then the thread is prepended to
660 *   its priority group in its home scheduler instance, otherwise it is
661 *   appended.
662 * @param queue_context The thread queue context to return an updated set of
663 *   threads for _Thread_Priority_update().  The thread queue context must be
664 *   initialized via _Thread_queue_Context_clear_priority_updates() before a
665 *   call of this function.
666 *
667 * @see _Thread_Wait_acquire().
668 */
669void _Thread_Priority_changed(
670  Thread_Control       *the_thread,
671  Priority_Node        *priority_node,
672  bool                  prepend_it,
673  Thread_queue_Context *queue_context
674);
675
676/**
677 * @brief Changes the thread priority value of the specified thread priority
678 * node in the corresponding thread priority aggregation.
679 *
680 * The caller must be the owner of the thread wait lock.
681 *
682 * @param the_thread The thread.
683 * @param[out] priority_node The thread priority node to change.
684 * @param new_priority The new thread priority value of the thread priority
685 *   node to change.
686 * @param prepend_it In case this is true, then the thread is prepended to
687 *   its priority group in its home scheduler instance, otherwise it is
688 *   appended.
689 * @param queue_context The thread queue context to return an updated set of
690 *   threads for _Thread_Priority_update().  The thread queue context must be
691 *   initialized via _Thread_queue_Context_clear_priority_updates() before a
692 *   call of this function.
693 *
694 * @see _Thread_Wait_acquire().
695 */
696RTEMS_INLINE_ROUTINE void _Thread_Priority_change(
697  Thread_Control       *the_thread,
698  Priority_Node        *priority_node,
699  Priority_Control      new_priority,
700  bool                  prepend_it,
701  Thread_queue_Context *queue_context
702)
703{
704  _Priority_Node_set_priority( priority_node, new_priority );
705  _Thread_Priority_changed(
706    the_thread,
707    priority_node,
708    prepend_it,
709    queue_context
710  );
711}
712
713/**
714 * @brief Replaces the victim priority node with the replacement priority node
715 * in the corresponding thread priority aggregation.
716 *
717 * The caller must be the owner of the thread wait lock.
718 *
719 * @param the_thread The thread.
720 * @param victim_node The victim thread priority node.
721 * @param replacement_node The replacement thread priority node.
722 *
723 * @see _Thread_Wait_acquire().
724 */
725void _Thread_Priority_replace(
726  Thread_Control *the_thread,
727  Priority_Node  *victim_node,
728  Priority_Node  *replacement_node
729);
730
731/**
732 * @brief Updates the priority of all threads in the set
733 *
734 * @param queue_context The thread queue context to return an updated set of
735 *   threads for _Thread_Priority_update().  The thread queue context must be
736 *   initialized via _Thread_queue_Context_clear_priority_updates() before a
737 *   call of this function.
738 *
739 * @see _Thread_Priority_add(), _Thread_Priority_change(),
740 *   _Thread_Priority_changed() and _Thread_Priority_remove().
741 */
742void _Thread_Priority_update( Thread_queue_Context *queue_context );
743
744/**
745 * @brief Updates the priority of the thread and changes it sticky level.
746 *
747 * @param the_thread The thread.
748 * @param sticky_level_change The new value for the sticky level.
749 */
750#if defined(RTEMS_SMP)
751void _Thread_Priority_and_sticky_update(
752  Thread_Control *the_thread,
753  int             sticky_level_change
754);
755#endif
756
757/**
758 * @brief Checks if the left thread priority is less than the right thread
759 *      priority in the intuitive sense of priority.
760 *
761 * @param left The left thread priority.
762 * @param right The right thread priority.
763 *
764 * @retval true The left priority is less in the intuitive sense.
765 * @retval false The left priority is greater or equal in the intuitive sense.
766 */
767RTEMS_INLINE_ROUTINE bool _Thread_Priority_less_than(
768  Priority_Control left,
769  Priority_Control right
770)
771{
772  return left > right;
773}
774
775/**
776 * @brief Returns the highest priority of the left and right thread priorities
777 * in the intuitive sense of priority.
778 *
779 * @param left The left thread priority.
780 * @param right The right thread priority.
781 *
782 * @return The highest priority in the intuitive sense of priority.
783 */
784RTEMS_INLINE_ROUTINE Priority_Control _Thread_Priority_highest(
785  Priority_Control left,
786  Priority_Control right
787)
788{
789  return _Thread_Priority_less_than( left, right ) ? right : left;
790}
791
792/**
793 * @brief Gets object information for the object id.
794 *
795 * @param id The id of the object information.
796 *
797 * @retval pointer The object information for this id.
798 * @retval NULL The object id is not valid.
799 */
800RTEMS_INLINE_ROUTINE Objects_Information *_Thread_Get_objects_information(
801  Objects_Id id
802)
803{
804  uint32_t the_api;
805
806  the_api = _Objects_Get_API( id );
807
808  if ( !_Objects_Is_api_valid( the_api ) ) {
809    return NULL;
810  }
811
812  /*
813   * Threads are always first class :)
814   *
815   * There is no need to validate the object class of the object identifier,
816   * since this will be done by the object get methods.
817   */
818  return _Objects_Information_table[ the_api ][ 1 ];
819}
820
821/**
822 * @brief Gets a thread by its identifier.
823 *
824 * @see _Objects_Get().
825 *
826 * @param id The id of the thread.
827 * @param lock_context The lock context.
828 */
829Thread_Control *_Thread_Get(
830  Objects_Id         id,
831  ISR_lock_Context  *lock_context
832);
833
834/**
835 * @brief Gets the cpu of the thread's scheduler.
836 *
837 * @param thread The thread.
838 *
839 * @return The cpu of the thread's scheduler.
840 */
841RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_Get_CPU(
842  const Thread_Control *thread
843)
844{
845#if defined(RTEMS_SMP)
846  return thread->Scheduler.cpu;
847#else
848  (void) thread;
849
850  return _Per_CPU_Get();
851#endif
852}
853
854/**
855 * @brief Sets the cpu of the thread's scheduler.
856 *
857 * @param[out] thread The thread.
858 * @param cpu The cpu to set.
859 */
860RTEMS_INLINE_ROUTINE void _Thread_Set_CPU(
861  Thread_Control *thread,
862  Per_CPU_Control *cpu
863)
864{
865#if defined(RTEMS_SMP)
866  thread->Scheduler.cpu = cpu;
867#else
868  (void) thread;
869  (void) cpu;
870#endif
871}
872
873/**
874 * @brief Checks if the thread is the currently executing thread.
875 *
876 * This function returns true if the_thread is the currently executing
877 * thread, and false otherwise.
878 *
879 * @param the_thread The thread to verify if it is the currently executing thread.
880 *
881 * @retval true @a the_thread is the currently executing one.
882 * @retval false @a the_thread is not the currently executing one.
883 */
884RTEMS_INLINE_ROUTINE bool _Thread_Is_executing (
885  const Thread_Control *the_thread
886)
887{
888  return ( the_thread == _Thread_Executing );
889}
890
891#if defined(RTEMS_SMP)
892/**
893 * @brief Checks if the thread executes currently on some processor in the
894 * system.
895 *
896 * Do not confuse this with _Thread_Is_executing() which checks only the
897 * current processor.
898 *
899 * @param the_thread The thread for the verification.
900 *
901 * @retval true @a the_thread is the currently executing one.
902 * @retval false @a the_thread is not the currently executing one.
903 */
904RTEMS_INLINE_ROUTINE bool _Thread_Is_executing_on_a_processor(
905  const Thread_Control *the_thread
906)
907{
908  return _CPU_Context_Get_is_executing( &the_thread->Registers );
909}
910#endif
911
912/**
913 * @brief Checks if the thread is the heir.
914 *
915 * This function returns true if the_thread is the heir
916 * thread, and false otherwise.
917 *
918 * @param the_thread The thread for the verification.
919 *
920 * @retval true @a the_thread is the heir.
921 * @retval false @a the_thread is not the heir.
922 */
923RTEMS_INLINE_ROUTINE bool _Thread_Is_heir (
924  const Thread_Control *the_thread
925)
926{
927  return ( the_thread == _Thread_Heir );
928}
929
930/**
931 * @brief Unblocks the thread.
932 *
933 * This routine clears any blocking state for the_thread.  It performs
934 * any necessary scheduling operations including the selection of
935 * a new heir thread.
936 *
937 * @param[in, out] the_thread The thread to unblock.
938 */
939RTEMS_INLINE_ROUTINE void _Thread_Unblock (
940  Thread_Control *the_thread
941)
942{
943  _Thread_Clear_state( the_thread, STATES_BLOCKED );
944}
945
946/**
947 * @brief Checks if the floating point context of the thread is currently
948 *      loaded in the floating point unit.
949 *
950 * This function returns true if the floating point context of
951 * the_thread is currently loaded in the floating point unit, and
952 * false otherwise.
953 *
954 * @param the_thread The thread for the verification.
955 *
956 * @retval true The floating point context of @a the_thread is currently
957 *      loaded in the floating point unit.
958 * @retval false The floating point context of @a the_thread is currently not
959 *      loaded in the floating point unit.
960 */
961#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
962RTEMS_INLINE_ROUTINE bool _Thread_Is_allocated_fp (
963  const Thread_Control *the_thread
964)
965{
966  return ( the_thread == _Thread_Allocated_fp );
967}
968#endif
969
970/*
971 * If the CPU has hardware floating point, then we must address saving
972 * and restoring it as part of the context switch.
973 *
974 * The second conditional compilation section selects the algorithm used
975 * to context switch between floating point tasks.  The deferred algorithm
976 * can be significantly better in a system with few floating point tasks
977 * because it reduces the total number of save and restore FP context
978 * operations.  However, this algorithm can not be used on all CPUs due
979 * to unpredictable use of FP registers by some compilers for integer
980 * operations.
981 */
982
983/**
984 * @brief Saves the executing thread's floating point area.
985 *
986 * @param executing The currently executing thread.
987 */
988RTEMS_INLINE_ROUTINE void _Thread_Save_fp( Thread_Control *executing )
989{
990#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
991#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
992  if ( executing->fp_context != NULL )
993    _Context_Save_fp( &executing->fp_context );
994#endif
995#endif
996}
997
998/**
999 * @brief Restores the executing thread's floating point area.
1000 *
1001 * @param executing The currently executing thread.
1002 */
1003RTEMS_INLINE_ROUTINE void _Thread_Restore_fp( Thread_Control *executing )
1004{
1005#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
1006#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
1007  if ( (executing->fp_context != NULL) &&
1008       !_Thread_Is_allocated_fp( executing ) ) {
1009    if ( _Thread_Allocated_fp != NULL )
1010      _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
1011    _Context_Restore_fp( &executing->fp_context );
1012    _Thread_Allocated_fp = executing;
1013  }
1014#else
1015  if ( executing->fp_context != NULL )
1016    _Context_Restore_fp( &executing->fp_context );
1017#endif
1018#endif
1019}
1020
1021/**
1022 * @brief Deallocates the currently loaded floating point context.
1023 *
1024 * This routine is invoked when the currently loaded floating
1025 * point context is now longer associated with an active thread.
1026 */
1027#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
1028RTEMS_INLINE_ROUTINE void _Thread_Deallocate_fp( void )
1029{
1030  _Thread_Allocated_fp = NULL;
1031}
1032#endif
1033
1034/**
1035 * @brief Checks if dispatching is disabled.
1036 *
1037 * This function returns true if dispatching is disabled, and false
1038 * otherwise.
1039 *
1040 * @retval true Dispatching is disabled.
1041 * @retval false Dispatching is enabled.
1042 */
1043RTEMS_INLINE_ROUTINE bool _Thread_Is_context_switch_necessary( void )
1044{
1045  return ( _Thread_Dispatch_necessary );
1046}
1047
1048/**
1049 * @brief Checks if the thread is NULL.
1050 *
1051 * @param the_thread The thread for the verification.
1052 *
1053 * @retval true The thread is @c NULL.
1054 * @retval false The thread is not @c NULL.
1055 */
1056RTEMS_INLINE_ROUTINE bool _Thread_Is_null (
1057  const Thread_Control *the_thread
1058)
1059{
1060  return ( the_thread == NULL );
1061}
1062
1063/**
1064 * @brief Gets the maximum number of internal threads.
1065 *
1066 * @return The maximum number of internal threads.
1067 */
1068RTEMS_INLINE_ROUTINE uint32_t _Thread_Get_maximum_internal_threads(void)
1069{
1070  /* Idle threads */
1071  uint32_t maximum_internal_threads =
1072    rtems_configuration_get_maximum_processors();
1073
1074  /* MPCI thread */
1075#if defined(RTEMS_MULTIPROCESSING)
1076  if ( _System_state_Is_multiprocessing ) {
1077    ++maximum_internal_threads;
1078  }
1079#endif
1080
1081  return maximum_internal_threads;
1082}
1083
1084/**
1085 * @brief Allocates an internal thread and returns it.
1086 *
1087 * @retval pointer Pointer to the allocated Thread_Control.
1088 * @retval NULL The operation failed.
1089 */
1090RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Internal_allocate( void )
1091{
1092  return (Thread_Control *)
1093    _Objects_Allocate_unprotected( &_Thread_Information.Objects );
1094}
1095
1096/**
1097 * @brief Gets the heir of the processor and makes it executing.
1098 *
1099 * Must be called with interrupts disabled.  The thread dispatch necessary
1100 * indicator is cleared as a side-effect.
1101 *
1102 * @param[in, out] cpu_self The processor to get the heir of.
1103 *
1104 * @return The heir thread.
1105 *
1106 * @see _Thread_Dispatch(), _Thread_Start_multitasking() and
1107 * _Thread_Dispatch_update_heir().
1108 */
1109RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Get_heir_and_make_it_executing(
1110  Per_CPU_Control *cpu_self
1111)
1112{
1113  Thread_Control *heir;
1114
1115  heir = cpu_self->heir;
1116  cpu_self->dispatch_necessary = false;
1117  cpu_self->executing = heir;
1118
1119  return heir;
1120}
1121
1122/**
1123 * @brief Updates the cpu time used of the thread.
1124 *
1125 * @param[in, out] the_thread The thread to add additional cpu time that is
1126 *      used.
1127 * @param cpu The cpu.
1128 */
1129RTEMS_INLINE_ROUTINE void _Thread_Update_CPU_time_used(
1130  Thread_Control  *the_thread,
1131  Per_CPU_Control *cpu
1132)
1133{
1134  Timestamp_Control last;
1135  Timestamp_Control ran;
1136
1137  last = cpu->cpu_usage_timestamp;
1138  _TOD_Get_uptime( &cpu->cpu_usage_timestamp );
1139  _Timestamp_Subtract( &last, &cpu->cpu_usage_timestamp, &ran );
1140  _Timestamp_Add_to( &the_thread->cpu_time_used, &ran );
1141}
1142
1143/**
1144 * @brief Updates the used cpu time for the heir and dispatches a new heir.
1145 *
1146 * @param[in, out] cpu_self The current processor.
1147 * @param[in, out] cpu_for_heir The processor to do a dispatch on.
1148 * @param heir The new heir for @a cpu_for_heir.
1149 */
1150#if defined( RTEMS_SMP )
1151RTEMS_INLINE_ROUTINE void _Thread_Dispatch_update_heir(
1152  Per_CPU_Control *cpu_self,
1153  Per_CPU_Control *cpu_for_heir,
1154  Thread_Control  *heir
1155)
1156{
1157  _Thread_Update_CPU_time_used( cpu_for_heir->heir, cpu_for_heir );
1158
1159  cpu_for_heir->heir = heir;
1160
1161  _Thread_Dispatch_request( cpu_self, cpu_for_heir );
1162}
1163#endif
1164
1165/**
1166 * @brief Gets the used cpu time of the thread and stores it in the given
1167 *      Timestamp_Control.
1168 *
1169 * @param the_thread The thread to get the used cpu time of.
1170 * @param[out] cpu_time_used Stores the used cpu time of @a the_thread.
1171 */
1172void _Thread_Get_CPU_time_used(
1173  Thread_Control    *the_thread,
1174  Timestamp_Control *cpu_time_used
1175);
1176
1177/**
1178 * @brief Initializes the control chain of the action control.
1179 *
1180 * @param[out] action_control The action control to initialize.
1181 */
1182RTEMS_INLINE_ROUTINE void _Thread_Action_control_initialize(
1183  Thread_Action_control *action_control
1184)
1185{
1186  _Chain_Initialize_empty( &action_control->Chain );
1187}
1188
1189/**
1190 * @brief Initializes the Thread action.
1191 *
1192 * @param[out] action The Thread_Action to initialize.
1193 */
1194RTEMS_INLINE_ROUTINE void _Thread_Action_initialize(
1195  Thread_Action *action
1196)
1197{
1198  _Chain_Set_off_chain( &action->Node );
1199}
1200
1201/**
1202 * @brief Adds a post switch action to the thread with the given handler.
1203 *
1204 * @param[in, out] the_thread The thread.
1205 * @param[in,  out] action The action to add.
1206 * @param handler The handler for the action.
1207 */
1208RTEMS_INLINE_ROUTINE void _Thread_Add_post_switch_action(
1209  Thread_Control        *the_thread,
1210  Thread_Action         *action,
1211  Thread_Action_handler  handler
1212)
1213{
1214  Per_CPU_Control *cpu_of_thread;
1215
1216  _Assert( _Thread_State_is_owner( the_thread ) );
1217
1218  cpu_of_thread = _Thread_Get_CPU( the_thread );
1219
1220  action->handler = handler;
1221
1222  _Thread_Dispatch_request( _Per_CPU_Get(), cpu_of_thread );
1223
1224  _Chain_Append_if_is_off_chain_unprotected(
1225    &the_thread->Post_switch_actions.Chain,
1226    &action->Node
1227  );
1228}
1229
1230/**
1231 * @brief Checks if the thread life state is restarting.
1232 *
1233 * @param life_state The thread life state for the verification.
1234 *
1235 * @retval true @a life_state is restarting.
1236 * @retval false @a life_state is not restarting.
1237 */
1238RTEMS_INLINE_ROUTINE bool _Thread_Is_life_restarting(
1239  Thread_Life_state life_state
1240)
1241{
1242  return ( life_state & THREAD_LIFE_RESTARTING ) != 0;
1243}
1244
1245/**
1246 * @brief Checks if the thread life state is terminating.
1247 *
1248 * @param life_state The thread life state for the verification.
1249 *
1250 * @retval true @a life_state is terminating.
1251 * @retval false @a life_state is not terminating.
1252 */
1253RTEMS_INLINE_ROUTINE bool _Thread_Is_life_terminating(
1254  Thread_Life_state life_state
1255)
1256{
1257  return ( life_state & THREAD_LIFE_TERMINATING ) != 0;
1258}
1259
1260/**
1261 * @brief Checks if the thread life state allos life change.
1262 *
1263 * @param life_state The thread life state for the verification.
1264 *
1265 * @retval true @a life_state allows life change.
1266 * @retval false @a life_state does not allow life change.
1267 */
1268RTEMS_INLINE_ROUTINE bool _Thread_Is_life_change_allowed(
1269  Thread_Life_state life_state
1270)
1271{
1272  return ( life_state
1273    & ( THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED ) ) == 0;
1274}
1275
1276/**
1277 * @brief Checks if the thread life state is life changing.
1278 *
1279 * @param life_state The thread life state for the verification.
1280 *
1281 * @retval true @a life_state is life changing.
1282 * @retval false @a life_state is not life changing.
1283 */
1284RTEMS_INLINE_ROUTINE bool _Thread_Is_life_changing(
1285  Thread_Life_state life_state
1286)
1287{
1288  return ( life_state
1289    & ( THREAD_LIFE_RESTARTING | THREAD_LIFE_TERMINATING ) ) != 0;
1290}
1291
1292/**
1293 * @brief Checks if the thread is joinable.
1294 *
1295 * @param the_thread The thread for the verification.
1296 *
1297 * @retval true @a life_state is joinable.
1298 * @retval false @a life_state is not joinable.
1299 */
1300RTEMS_INLINE_ROUTINE bool _Thread_Is_joinable(
1301  const Thread_Control *the_thread
1302)
1303{
1304  _Assert( _Thread_State_is_owner( the_thread ) );
1305  return ( the_thread->Life.state & THREAD_LIFE_DETACHED ) == 0;
1306}
1307
1308/**
1309 * @brief Increments the thread's resource count.
1310 *
1311 * @param[in, out] the_thread The thread to increase the resource count of.
1312 */
1313RTEMS_INLINE_ROUTINE void _Thread_Resource_count_increment(
1314  Thread_Control *the_thread
1315)
1316{
1317#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
1318  ++the_thread->resource_count;
1319#else
1320  (void) the_thread;
1321#endif
1322}
1323
1324/**
1325 * @brief Decrements the thread's resource count.
1326 *
1327 * @param[in, out] the_thread The thread to decrement the resource count of.
1328 */
1329RTEMS_INLINE_ROUTINE void _Thread_Resource_count_decrement(
1330  Thread_Control *the_thread
1331)
1332{
1333#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
1334  --the_thread->resource_count;
1335#else
1336  (void) the_thread;
1337#endif
1338}
1339
1340#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
1341/**
1342 * @brief Checks if the thread owns resources.
1343 *
1344 * Resources are accounted with the Thread_Control::resource_count resource
1345 * counter.  This counter is used by mutex objects for example.
1346 *
1347 * @param the_thread The thread.
1348 *
1349 * @retval true The thread owns resources.
1350 * @retval false The thread does not own resources.
1351 */
1352RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
1353  const Thread_Control *the_thread
1354)
1355{
1356  return the_thread->resource_count != 0;
1357}
1358#endif
1359
1360#if defined(RTEMS_SMP)
1361/**
1362 * @brief Cancels the thread's need for help.
1363 *
1364 * @param the_thread The thread to cancel the help request of.
1365 * @param cpu The cpu to get the lock context of in order to
1366 *      cancel the help request.
1367 */
1368RTEMS_INLINE_ROUTINE void _Thread_Scheduler_cancel_need_for_help(
1369  Thread_Control  *the_thread,
1370  Per_CPU_Control *cpu
1371)
1372{
1373  ISR_lock_Context lock_context;
1374
1375  _Per_CPU_Acquire( cpu, &lock_context );
1376
1377  if ( !_Chain_Is_node_off_chain( &the_thread->Scheduler.Help_node ) ) {
1378    _Chain_Extract_unprotected( &the_thread->Scheduler.Help_node );
1379    _Chain_Set_off_chain( &the_thread->Scheduler.Help_node );
1380  }
1381
1382  _Per_CPU_Release( cpu, &lock_context );
1383}
1384#endif
1385
1386/**
1387 * @brief Gets the home scheduler of the thread.
1388 *
1389 * @param the_thread The thread to get the home scheduler of.
1390 *
1391 * @return The thread's home scheduler.
1392 */
1393RTEMS_INLINE_ROUTINE const Scheduler_Control *_Thread_Scheduler_get_home(
1394  const Thread_Control *the_thread
1395)
1396{
1397#if defined(RTEMS_SMP)
1398  return the_thread->Scheduler.home_scheduler;
1399#else
1400  (void) the_thread;
1401  return &_Scheduler_Table[ 0 ];
1402#endif
1403}
1404
1405/**
1406 * @brief Gets the scheduler's home node.
1407 *
1408 * @param the_thread The thread to get the home node of.
1409 *
1410 * @return The thread's home node.
1411 */
1412RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_home_node(
1413  const Thread_Control *the_thread
1414)
1415{
1416#if defined(RTEMS_SMP)
1417  _Assert( !_Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
1418  return SCHEDULER_NODE_OF_THREAD_WAIT_NODE(
1419    _Chain_First( &the_thread->Scheduler.Wait_nodes )
1420  );
1421#else
1422  return the_thread->Scheduler.nodes;
1423#endif
1424}
1425
1426/**
1427 * @brief Gets the thread's scheduler node by index.
1428 *
1429 * @param the_thread The thread of which to get a scheduler node.
1430 * @param scheduler_index The index of the desired scheduler node.
1431 *
1432 * @return The scheduler node with the specified index.
1433 */
1434RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_node_by_index(
1435  const Thread_Control *the_thread,
1436  size_t                scheduler_index
1437)
1438{
1439#if defined(RTEMS_SMP)
1440  return (Scheduler_Node *)
1441    ( (uintptr_t) the_thread->Scheduler.nodes
1442      + scheduler_index * _Scheduler_Node_size );
1443#else
1444  _Assert( scheduler_index == 0 );
1445  (void) scheduler_index;
1446  return the_thread->Scheduler.nodes;
1447#endif
1448}
1449
1450#if defined(RTEMS_SMP)
1451/**
1452 * @brief Acquires the lock context in a critical section.
1453 *
1454 * @param the_thread The thread to acquire the lock context.
1455 * @param lock_context The lock context.
1456 */
1457RTEMS_INLINE_ROUTINE void _Thread_Scheduler_acquire_critical(
1458  Thread_Control   *the_thread,
1459  ISR_lock_Context *lock_context
1460)
1461{
1462  _ISR_lock_Acquire( &the_thread->Scheduler.Lock, lock_context );
1463}
1464
1465/**
1466 * @brief Releases the lock context in a critical section.
1467 *
1468 * @param the_thread The thread to release the lock context.
1469 * @param lock_context The lock context.
1470 */
1471RTEMS_INLINE_ROUTINE void _Thread_Scheduler_release_critical(
1472  Thread_Control   *the_thread,
1473  ISR_lock_Context *lock_context
1474)
1475{
1476  _ISR_lock_Release( &the_thread->Scheduler.Lock, lock_context );
1477}
1478
1479/**
1480 * @brief Process the thread's scheduler requests.
1481 *
1482 * @param[in, out] the_thread The thread for the operation.
1483 */
1484void _Thread_Scheduler_process_requests( Thread_Control *the_thread );
1485
1486/**
1487 * @brief Add a scheduler request to the thread.
1488 *
1489 * @param[in, out] the_thread The thread to add a scheduler request to.
1490 * @param[in, out] scheduler_node The scheduler node for the request.
1491 * @param request The request to add.
1492 */
1493RTEMS_INLINE_ROUTINE void _Thread_Scheduler_add_request(
1494  Thread_Control         *the_thread,
1495  Scheduler_Node         *scheduler_node,
1496  Scheduler_Node_request  request
1497)
1498{
1499  ISR_lock_Context       lock_context;
1500  Scheduler_Node_request current_request;
1501
1502  _Thread_Scheduler_acquire_critical( the_thread, &lock_context );
1503
1504  current_request = scheduler_node->Thread.request;
1505
1506  if ( current_request == SCHEDULER_NODE_REQUEST_NOT_PENDING ) {
1507    _Assert(
1508      request == SCHEDULER_NODE_REQUEST_ADD
1509        || request == SCHEDULER_NODE_REQUEST_REMOVE
1510    );
1511    _Assert( scheduler_node->Thread.next_request == NULL );
1512    scheduler_node->Thread.next_request = the_thread->Scheduler.requests;
1513    the_thread->Scheduler.requests = scheduler_node;
1514  } else if ( current_request != SCHEDULER_NODE_REQUEST_NOTHING ) {
1515    _Assert(
1516      ( current_request == SCHEDULER_NODE_REQUEST_ADD
1517        && request == SCHEDULER_NODE_REQUEST_REMOVE )
1518      || ( current_request == SCHEDULER_NODE_REQUEST_REMOVE
1519        && request == SCHEDULER_NODE_REQUEST_ADD )
1520    );
1521    request = SCHEDULER_NODE_REQUEST_NOTHING;
1522  }
1523
1524  scheduler_node->Thread.request = request;
1525
1526  _Thread_Scheduler_release_critical( the_thread, &lock_context );
1527}
1528
1529/**
1530 * @brief Adds a wait node to the thread and adds a corresponding
1531 *      request to the thread.
1532 *
1533 * @param[in, out] the_thread The thread to add the wait node to.
1534 * @param scheduler_node The scheduler node which provides the wait node.
1535 */
1536RTEMS_INLINE_ROUTINE void _Thread_Scheduler_add_wait_node(
1537  Thread_Control *the_thread,
1538  Scheduler_Node *scheduler_node
1539)
1540{
1541  _Chain_Append_unprotected(
1542    &the_thread->Scheduler.Wait_nodes,
1543    &scheduler_node->Thread.Wait_node
1544  );
1545  _Thread_Scheduler_add_request(
1546    the_thread,
1547    scheduler_node,
1548    SCHEDULER_NODE_REQUEST_ADD
1549  );
1550}
1551
1552/**
1553 * @brief Remove a wait node from the thread and add a corresponding request to
1554 *      it.
1555 *
1556 * @param the_thread The thread to add the request to remove a wait node.
1557 * @param scheduler_node The scheduler node to remove a wait node from.
1558 */
1559RTEMS_INLINE_ROUTINE void _Thread_Scheduler_remove_wait_node(
1560  Thread_Control *the_thread,
1561  Scheduler_Node *scheduler_node
1562)
1563{
1564  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
1565  _Thread_Scheduler_add_request(
1566    the_thread,
1567    scheduler_node,
1568    SCHEDULER_NODE_REQUEST_REMOVE
1569  );
1570}
1571#endif
1572
1573/**
1574 * @brief Returns the priority of the thread.
1575 *
1576 * Returns the user API and thread wait information relevant thread priority.
1577 * This includes temporary thread priority adjustments due to locking
1578 * protocols, a job release or the POSIX sporadic server for example.
1579 *
1580 * @param the_thread The thread of which to get the priority.
1581 *
1582 * @return The priority of the thread.
1583 */
1584RTEMS_INLINE_ROUTINE Priority_Control _Thread_Get_priority(
1585  const Thread_Control *the_thread
1586)
1587{
1588  Scheduler_Node *scheduler_node;
1589
1590  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1591  return _Priority_Get_priority( &scheduler_node->Wait.Priority );
1592}
1593
1594/**
1595 * @brief Returns the unmapped priority of the thread.
1596 *
1597 * @param the_thread The thread of which to get the unmapped priority.
1598 *
1599 * @return The unmapped priority of the thread.
1600 */
1601RTEMS_INLINE_ROUTINE Priority_Control _Thread_Get_unmapped_priority(
1602  const Thread_Control *the_thread
1603)
1604{
1605  return SCHEDULER_PRIORITY_UNMAP( _Thread_Get_priority( the_thread ) );
1606}
1607
1608/**
1609 * @brief Returns the unmapped real priority of the thread.
1610 *
1611 * @param the_thread The thread of which to get the unmapped real priority.
1612 *
1613 * @return The unmapped real priority of the thread.
1614 */
1615RTEMS_INLINE_ROUTINE Priority_Control _Thread_Get_unmapped_real_priority(
1616  const Thread_Control *the_thread
1617)
1618{
1619  return SCHEDULER_PRIORITY_UNMAP( the_thread->Real_priority.priority );
1620}
1621
1622/**
1623 * @brief Acquires the thread wait default lock inside a critical section
1624 * (interrupts disabled).
1625 *
1626 * @param[in, out] the_thread The thread.
1627 * @param lock_context The lock context used for the corresponding lock
1628 *   release.
1629 *
1630 * @see _Thread_Wait_release_default_critical().
1631 */
1632RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default_critical(
1633  Thread_Control   *the_thread,
1634  ISR_lock_Context *lock_context
1635)
1636{
1637  _ISR_lock_Acquire( &the_thread->Wait.Lock.Default, lock_context );
1638}
1639
1640/**
1641 * @brief Acquires the thread wait default lock and returns the executing
1642 * thread.
1643 *
1644 * @param lock_context The lock context used for the corresponding lock
1645 *   release.
1646 *
1647 * @return The executing thread.
1648 *
1649 * @see _Thread_Wait_release_default().
1650 */
1651RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Wait_acquire_default_for_executing(
1652  ISR_lock_Context *lock_context
1653)
1654{
1655  Thread_Control *executing;
1656
1657  _ISR_lock_ISR_disable( lock_context );
1658  executing = _Thread_Executing;
1659  _Thread_Wait_acquire_default_critical( executing, lock_context );
1660
1661  return executing;
1662}
1663
1664/**
1665 * @brief Acquires the thread wait default lock and disables interrupts.
1666 *
1667 * @param[in, out] the_thread The thread.
1668 * @param[out] lock_context The lock context used for the corresponding lock
1669 *   release.
1670 *
1671 * @see _Thread_Wait_release_default().
1672 */
1673RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default(
1674  Thread_Control   *the_thread,
1675  ISR_lock_Context *lock_context
1676)
1677{
1678  _ISR_lock_ISR_disable( lock_context );
1679  _Thread_Wait_acquire_default_critical( the_thread, lock_context );
1680}
1681
1682/**
1683 * @brief Releases the thread wait default lock inside a critical section
1684 * (interrupts disabled).
1685 *
1686 * The previous interrupt status is not restored.
1687 *
1688 * @param[in, out] the_thread The thread.
1689 * @param lock_context The lock context used for the corresponding lock
1690 *   acquire.
1691 */
1692RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default_critical(
1693  Thread_Control   *the_thread,
1694  ISR_lock_Context *lock_context
1695)
1696{
1697  _ISR_lock_Release( &the_thread->Wait.Lock.Default, lock_context );
1698}
1699
1700/**
1701 * @brief Releases the thread wait default lock and restores the previous
1702 * interrupt status.
1703 *
1704 * @param[in, out] the_thread The thread.
1705 * @param[out] lock_context The lock context used for the corresponding lock
1706 *   acquire.
1707 */
1708RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default(
1709  Thread_Control   *the_thread,
1710  ISR_lock_Context *lock_context
1711)
1712{
1713  _Thread_Wait_release_default_critical( the_thread, lock_context );
1714  _ISR_lock_ISR_enable( lock_context );
1715}
1716
1717#if defined(RTEMS_SMP)
1718#define THREAD_QUEUE_CONTEXT_OF_REQUEST( node ) \
1719  RTEMS_CONTAINER_OF( node, Thread_queue_Context, Lock_context.Wait.Gate.Node )
1720
1721/**
1722 * @brief Removes the first pending wait lock request.
1723 *
1724 * @param the_thread The thread to remove the request from.
1725 * @param queue_lock_context The queue lock context.
1726 */
1727RTEMS_INLINE_ROUTINE void _Thread_Wait_remove_request_locked(
1728  Thread_Control            *the_thread,
1729  Thread_queue_Lock_context *queue_lock_context
1730)
1731{
1732  Chain_Node *first;
1733
1734  _Chain_Extract_unprotected( &queue_lock_context->Wait.Gate.Node );
1735  first = _Chain_First( &the_thread->Wait.Lock.Pending_requests );
1736
1737  if ( first != _Chain_Tail( &the_thread->Wait.Lock.Pending_requests ) ) {
1738    _Thread_queue_Gate_open( (Thread_queue_Gate *) first );
1739  }
1740}
1741
1742/**
1743 * @brief Acquires the wait queue inside a critical section.
1744 *
1745 * @param queue The queue that acquires.
1746 * @param queue_lock_context The queue lock context.
1747 */
1748RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_queue_critical(
1749  Thread_queue_Queue        *queue,
1750  Thread_queue_Lock_context *queue_lock_context
1751)
1752{
1753  _Thread_queue_Queue_acquire_critical(
1754    queue,
1755    &_Thread_Executing->Potpourri_stats,
1756    &queue_lock_context->Lock_context
1757  );
1758}
1759
1760/**
1761 * @brief Releases the wait queue inside a critical section.
1762 *
1763 * @param queue The queue that releases.
1764 * @param queue_lock_context The queue lock context.
1765 */
1766RTEMS_INLINE_ROUTINE void _Thread_Wait_release_queue_critical(
1767  Thread_queue_Queue        *queue,
1768  Thread_queue_Lock_context *queue_lock_context
1769)
1770{
1771  _Thread_queue_Queue_release_critical(
1772    queue,
1773    &queue_lock_context->Lock_context
1774  );
1775}
1776#endif
1777
1778/**
1779 * @brief Acquires the thread wait lock inside a critical section (interrupts
1780 * disabled).
1781 *
1782 * @param[in, out] the_thread The thread.
1783 * @param[in, out] queue_context The thread queue context for the corresponding
1784 *   _Thread_Wait_release_critical().
1785 */
1786RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_critical(
1787  Thread_Control       *the_thread,
1788  Thread_queue_Context *queue_context
1789)
1790{
1791#if defined(RTEMS_SMP)
1792  Thread_queue_Queue *queue;
1793
1794  _Thread_Wait_acquire_default_critical(
1795    the_thread,
1796    &queue_context->Lock_context.Lock_context
1797  );
1798
1799  queue = the_thread->Wait.queue;
1800  queue_context->Lock_context.Wait.queue = queue;
1801
1802  if ( queue != NULL ) {
1803    _Thread_queue_Gate_add(
1804      &the_thread->Wait.Lock.Pending_requests,
1805      &queue_context->Lock_context.Wait.Gate
1806    );
1807    _Thread_Wait_release_default_critical(
1808      the_thread,
1809      &queue_context->Lock_context.Lock_context
1810    );
1811    _Thread_Wait_acquire_queue_critical( queue, &queue_context->Lock_context );
1812
1813    if ( queue_context->Lock_context.Wait.queue == NULL ) {
1814      _Thread_Wait_release_queue_critical(
1815        queue,
1816        &queue_context->Lock_context
1817      );
1818      _Thread_Wait_acquire_default_critical(
1819        the_thread,
1820        &queue_context->Lock_context.Lock_context
1821      );
1822      _Thread_Wait_remove_request_locked(
1823        the_thread,
1824        &queue_context->Lock_context
1825      );
1826      _Assert( the_thread->Wait.queue == NULL );
1827    }
1828  }
1829#else
1830  (void) the_thread;
1831  (void) queue_context;
1832#endif
1833}
1834
1835/**
1836 * @brief Acquires the thread wait default lock and disables interrupts.
1837 *
1838 * @param[in, out] the_thread The thread.
1839 * @param[in, out] queue_context The thread queue context for the corresponding
1840 *   _Thread_Wait_release().
1841 */
1842RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire(
1843  Thread_Control       *the_thread,
1844  Thread_queue_Context *queue_context
1845)
1846{
1847  _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
1848  _Thread_Wait_acquire_critical( the_thread, queue_context );
1849}
1850
1851/**
1852 * @brief Releases the thread wait lock inside a critical section (interrupts
1853 * disabled).
1854 *
1855 * The previous interrupt status is not restored.
1856 *
1857 * @param[in, out] the_thread The thread.
1858 * @param[in, out] queue_context The thread queue context used for corresponding
1859 *   _Thread_Wait_acquire_critical().
1860 */
1861RTEMS_INLINE_ROUTINE void _Thread_Wait_release_critical(
1862  Thread_Control       *the_thread,
1863  Thread_queue_Context *queue_context
1864)
1865{
1866#if defined(RTEMS_SMP)
1867  Thread_queue_Queue *queue;
1868
1869  queue = queue_context->Lock_context.Wait.queue;
1870
1871  if ( queue != NULL ) {
1872    _Thread_Wait_release_queue_critical(
1873      queue, &queue_context->Lock_context
1874    );
1875    _Thread_Wait_acquire_default_critical(
1876      the_thread,
1877      &queue_context->Lock_context.Lock_context
1878    );
1879    _Thread_Wait_remove_request_locked(
1880      the_thread,
1881      &queue_context->Lock_context
1882    );
1883  }
1884
1885  _Thread_Wait_release_default_critical(
1886    the_thread,
1887    &queue_context->Lock_context.Lock_context
1888  );
1889#else
1890  (void) the_thread;
1891  (void) queue_context;
1892#endif
1893}
1894
1895/**
1896 * @brief Releases the thread wait lock and restores the previous interrupt
1897 * status.
1898 *
1899 * @param[in, out] the_thread The thread.
1900 * @param[in, out] queue_context The thread queue context used for corresponding
1901 *   _Thread_Wait_acquire().
1902 */
1903RTEMS_INLINE_ROUTINE void _Thread_Wait_release(
1904  Thread_Control       *the_thread,
1905  Thread_queue_Context *queue_context
1906)
1907{
1908  _Thread_Wait_release_critical( the_thread, queue_context );
1909  _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
1910}
1911
1912/**
1913 * @brief Claims the thread wait queue.
1914 *
1915 * The caller must not be the owner of the default thread wait lock.  The
1916 * caller must be the owner of the corresponding thread queue lock.  The
1917 * registration of the corresponding thread queue operations is deferred and
1918 * done after the deadlock detection.  This is crucial to support timeouts on
1919 * SMP configurations.
1920 *
1921 * @param[in, out] the_thread The thread.
1922 * @param[in, out] queue The new thread queue.
1923 *
1924 * @see _Thread_Wait_claim_finalize() and _Thread_Wait_restore_default().
1925 */
1926RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
1927  Thread_Control     *the_thread,
1928  Thread_queue_Queue *queue
1929)
1930{
1931  ISR_lock_Context lock_context;
1932
1933  _Thread_Wait_acquire_default_critical( the_thread, &lock_context );
1934
1935  _Assert( the_thread->Wait.queue == NULL );
1936
1937#if defined(RTEMS_SMP)
1938  _Chain_Initialize_empty( &the_thread->Wait.Lock.Pending_requests );
1939  _Chain_Initialize_node( &the_thread->Wait.Lock.Tranquilizer.Node );
1940  _Thread_queue_Gate_close( &the_thread->Wait.Lock.Tranquilizer );
1941#endif
1942
1943  the_thread->Wait.queue = queue;
1944
1945  _Thread_Wait_release_default_critical( the_thread, &lock_context );
1946}
1947
1948/**
1949 * @brief Finalizes the thread wait queue claim via registration of the
1950 * corresponding thread queue operations.
1951 *
1952 * @param[in, out] the_thread The thread.
1953 * @param operations The corresponding thread queue operations.
1954 */
1955RTEMS_INLINE_ROUTINE void _Thread_Wait_claim_finalize(
1956  Thread_Control                *the_thread,
1957  const Thread_queue_Operations *operations
1958)
1959{
1960  the_thread->Wait.operations = operations;
1961}
1962
1963/**
1964 * @brief Removes a thread wait lock request.
1965 *
1966 * On SMP configurations, removes a thread wait lock request.
1967 *
1968 * On other configurations, this function does nothing.
1969 *
1970 * @param[in, out] the_thread The thread.
1971 * @param[in, out] queue_lock_context The thread queue lock context used for
1972 *   corresponding _Thread_Wait_acquire().
1973 */
1974RTEMS_INLINE_ROUTINE void _Thread_Wait_remove_request(
1975  Thread_Control            *the_thread,
1976  Thread_queue_Lock_context *queue_lock_context
1977)
1978{
1979#if defined(RTEMS_SMP)
1980  ISR_lock_Context lock_context;
1981
1982  _Thread_Wait_acquire_default( the_thread, &lock_context );
1983  _Thread_Wait_remove_request_locked( the_thread, queue_lock_context );
1984  _Thread_Wait_release_default( the_thread, &lock_context );
1985#else
1986  (void) the_thread;
1987  (void) queue_lock_context;
1988#endif
1989}
1990
1991/**
1992 * @brief Restores the default thread wait queue and operations.
1993 *
1994 * The caller must be the owner of the current thread wait queue lock.
1995 *
1996 * On SMP configurations, the pending requests are updated to use the stale
1997 * thread queue operations.
1998 *
1999 * @param[in, out] the_thread The thread.
2000 *
2001 * @see _Thread_Wait_claim().
2002 */
2003RTEMS_INLINE_ROUTINE void _Thread_Wait_restore_default(
2004  Thread_Control *the_thread
2005)
2006{
2007#if defined(RTEMS_SMP)
2008  ISR_lock_Context  lock_context;
2009  Chain_Node       *node;
2010  const Chain_Node *tail;
2011
2012  _Thread_Wait_acquire_default_critical( the_thread, &lock_context );
2013
2014  node = _Chain_First( &the_thread->Wait.Lock.Pending_requests );
2015  tail = _Chain_Immutable_tail( &the_thread->Wait.Lock.Pending_requests );
2016
2017  if ( node != tail ) {
2018    do {
2019      Thread_queue_Context *queue_context;
2020
2021      queue_context = THREAD_QUEUE_CONTEXT_OF_REQUEST( node );
2022      queue_context->Lock_context.Wait.queue = NULL;
2023
2024      node = _Chain_Next( node );
2025    } while ( node != tail );
2026
2027    _Thread_queue_Gate_add(
2028      &the_thread->Wait.Lock.Pending_requests,
2029      &the_thread->Wait.Lock.Tranquilizer
2030    );
2031  } else {
2032    _Thread_queue_Gate_open( &the_thread->Wait.Lock.Tranquilizer );
2033  }
2034#endif
2035
2036  the_thread->Wait.queue = NULL;
2037  the_thread->Wait.operations = &_Thread_queue_Operations_default;
2038
2039#if defined(RTEMS_SMP)
2040  _Thread_Wait_release_default_critical( the_thread, &lock_context );
2041#endif
2042}
2043
2044/**
2045 * @brief Tranquilizes the thread after a wait on a thread queue.
2046 *
2047 * After the violent blocking procedure this function makes the thread calm and
2048 * peaceful again so that it can carry out its normal work.
2049 *
2050 * On SMP configurations, ensures that all pending thread wait lock requests
2051 * completed before the thread is able to begin a new thread wait procedure.
2052 *
2053 * On other configurations, this function does nothing.
2054 *
2055 * It must be called after a _Thread_Wait_claim() exactly once
2056 *  - after the corresponding thread queue lock was released, and
2057 *  - the default wait state is restored or some other processor is about to do
2058 *    this.
2059 *
2060 * @param the_thread The thread.
2061 */
2062RTEMS_INLINE_ROUTINE void _Thread_Wait_tranquilize(
2063  Thread_Control *the_thread
2064)
2065{
2066#if defined(RTEMS_SMP)
2067  _Thread_queue_Gate_wait( &the_thread->Wait.Lock.Tranquilizer );
2068#else
2069  (void) the_thread;
2070#endif
2071}
2072
2073/**
2074 * @brief Cancels a thread wait on a thread queue.
2075 *
2076 * @param[in, out] the_thread The thread.
2077 * @param queue_context The thread queue context used for corresponding
2078 *   _Thread_Wait_acquire().
2079 */
2080RTEMS_INLINE_ROUTINE void _Thread_Wait_cancel(
2081  Thread_Control       *the_thread,
2082  Thread_queue_Context *queue_context
2083)
2084{
2085  Thread_queue_Queue *queue;
2086
2087  queue = the_thread->Wait.queue;
2088
2089#if defined(RTEMS_SMP)
2090  if ( queue != NULL ) {
2091    _Assert( queue_context->Lock_context.Wait.queue == queue );
2092#endif
2093
2094    ( *the_thread->Wait.operations->extract )(
2095      queue,
2096      the_thread,
2097      queue_context
2098    );
2099    _Thread_Wait_restore_default( the_thread );
2100
2101#if defined(RTEMS_SMP)
2102    _Assert( queue_context->Lock_context.Wait.queue == NULL );
2103    queue_context->Lock_context.Wait.queue = queue;
2104  }
2105#endif
2106}
2107
2108/**
2109 * @brief The initial thread wait flags value set by _Thread_Initialize().
2110 */
2111#define THREAD_WAIT_FLAGS_INITIAL 0x0U
2112
2113/**
2114 * @brief Mask to get the thread wait state flags.
2115 */
2116#define THREAD_WAIT_STATE_MASK 0xffU
2117
2118/**
2119 * @brief Indicates that the thread begins with the blocking operation.
2120 *
2121 * A blocking operation consists of an optional watchdog initialization and the
2122 * setting of the appropriate thread blocking state with the corresponding
2123 * scheduler block operation.
2124 */
2125#define THREAD_WAIT_STATE_INTEND_TO_BLOCK 0x1U
2126
2127/**
2128 * @brief Indicates that the thread completed the blocking operation.
2129 */
2130#define THREAD_WAIT_STATE_BLOCKED 0x2U
2131
2132/**
2133 * @brief Indicates that a condition to end the thread wait occurred.
2134 *
2135 * This could be a timeout, a signal, an event or a resource availability.
2136 */
2137#define THREAD_WAIT_STATE_READY_AGAIN 0x4U
2138
2139/**
2140 * @brief Mask to get the thread wait class flags.
2141 */
2142#define THREAD_WAIT_CLASS_MASK 0xff00U
2143
2144/**
2145 * @brief Indicates that the thread waits for an event.
2146 */
2147#define THREAD_WAIT_CLASS_EVENT 0x100U
2148
2149/**
2150 * @brief Indicates that the thread waits for a system event.
2151 */
2152#define THREAD_WAIT_CLASS_SYSTEM_EVENT 0x200U
2153
2154/**
2155 * @brief Indicates that the thread waits for an object.
2156 */
2157#define THREAD_WAIT_CLASS_OBJECT 0x400U
2158
2159/**
2160 * @brief Indicates that the thread waits for a period.
2161 */
2162#define THREAD_WAIT_CLASS_PERIOD 0x800U
2163
2164/**
2165 * @brief Sets the thread's wait flags.
2166 *
2167 * @param[in, out] the_thread The thread to set the wait flags of.
2168 * @param flags The flags to set.
2169 */
2170RTEMS_INLINE_ROUTINE void _Thread_Wait_flags_set(
2171  Thread_Control    *the_thread,
2172  Thread_Wait_flags  flags
2173)
2174{
2175#if defined(RTEMS_SMP)
2176  _Atomic_Store_uint( &the_thread->Wait.flags, flags, ATOMIC_ORDER_RELAXED );
2177#else
2178  the_thread->Wait.flags = flags;
2179#endif
2180}
2181
2182/**
2183 * @brief Gets the thread's wait flags according to the ATOMIC_ORDER_RELAXED.
2184 *
2185 * @param the_thread The thread to get the wait flags of.
2186 *
2187 * @return The thread's wait flags.
2188 */
2189RTEMS_INLINE_ROUTINE Thread_Wait_flags _Thread_Wait_flags_get(
2190  const Thread_Control *the_thread
2191)
2192{
2193#if defined(RTEMS_SMP)
2194  return _Atomic_Load_uint( &the_thread->Wait.flags, ATOMIC_ORDER_RELAXED );
2195#else
2196  return the_thread->Wait.flags;
2197#endif
2198}
2199
2200/**
2201 * @brief Gets the thread's wait flags according to the ATOMIC_ORDER_ACQUIRE.
2202 *
2203 * @param the_thread The thread to get the wait flags of.
2204 *
2205 * @return The thread's wait flags.
2206 */
2207RTEMS_INLINE_ROUTINE Thread_Wait_flags _Thread_Wait_flags_get_acquire(
2208  const Thread_Control *the_thread
2209)
2210{
2211#if defined(RTEMS_SMP)
2212  return _Atomic_Load_uint( &the_thread->Wait.flags, ATOMIC_ORDER_ACQUIRE );
2213#else
2214  return the_thread->Wait.flags;
2215#endif
2216}
2217
2218/**
2219 * @brief Tries to change the thread wait flags with release semantics in case
2220 * of success.
2221 *
2222 * Must be called inside a critical section (interrupts disabled).
2223 *
2224 * In case the wait flags are equal to the expected wait flags, then the wait
2225 * flags are set to the desired wait flags.
2226 *
2227 * @param the_thread The thread.
2228 * @param expected_flags The expected wait flags.
2229 * @param desired_flags The desired wait flags.
2230 *
2231 * @retval true The wait flags were equal to the expected wait flags.
2232 * @retval false The wait flags were not equal to the expected wait flags.
2233 */
2234RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_release(
2235  Thread_Control    *the_thread,
2236  Thread_Wait_flags  expected_flags,
2237  Thread_Wait_flags  desired_flags
2238)
2239{
2240  _Assert( _ISR_Get_level() != 0 );
2241
2242#if defined(RTEMS_SMP)
2243  return _Atomic_Compare_exchange_uint(
2244    &the_thread->Wait.flags,
2245    &expected_flags,
2246    desired_flags,
2247    ATOMIC_ORDER_RELEASE,
2248    ATOMIC_ORDER_RELAXED
2249  );
2250#else
2251  bool success = ( the_thread->Wait.flags == expected_flags );
2252
2253  if ( success ) {
2254    the_thread->Wait.flags = desired_flags;
2255  }
2256
2257  return success;
2258#endif
2259}
2260
2261/**
2262 * @brief Tries to change the thread wait flags with acquire semantics.
2263 *
2264 * In case the wait flags are equal to the expected wait flags, then the wait
2265 * flags are set to the desired wait flags.
2266 *
2267 * @param the_thread The thread.
2268 * @param expected_flags The expected wait flags.
2269 * @param desired_flags The desired wait flags.
2270 *
2271 * @retval true The wait flags were equal to the expected wait flags.
2272 * @retval false The wait flags were not equal to the expected wait flags.
2273 */
2274RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_acquire(
2275  Thread_Control    *the_thread,
2276  Thread_Wait_flags  expected_flags,
2277  Thread_Wait_flags  desired_flags
2278)
2279{
2280#if defined(RTEMS_SMP)
2281  return _Atomic_Compare_exchange_uint(
2282    &the_thread->Wait.flags,
2283    &expected_flags,
2284    desired_flags,
2285    ATOMIC_ORDER_ACQUIRE,
2286    ATOMIC_ORDER_ACQUIRE
2287  );
2288#else
2289  bool      success;
2290  ISR_Level level;
2291
2292  _ISR_Local_disable( level );
2293
2294  success = _Thread_Wait_flags_try_change_release(
2295    the_thread,
2296    expected_flags,
2297    desired_flags
2298  );
2299
2300  _ISR_Local_enable( level );
2301  return success;
2302#endif
2303}
2304
2305/**
2306 * @brief Returns the object identifier of the object containing the current
2307 * thread wait queue.
2308 *
2309 * This function may be used for debug and system information purposes.  The
2310 * caller must be the owner of the thread lock.
2311 *
2312 * @param the_thread The thread.
2313 *
2314 * @retval 0 The thread waits on no thread queue currently, the thread wait
2315 *   queue is not contained in an object, or the current thread state provides
2316 *   insufficient information, e.g. the thread is in the middle of a blocking
2317 *   operation.
2318 * @retval other The object identifier of the object containing the thread wait
2319 *   queue.
2320 */
2321Objects_Id _Thread_Wait_get_id( const Thread_Control *the_thread );
2322
2323/**
2324 * @brief Get the status of the wait return code of the thread.
2325 *
2326 * @param the_thread The thread to get the status of the wait return code of.
2327 */
2328RTEMS_INLINE_ROUTINE Status_Control _Thread_Wait_get_status(
2329  const Thread_Control *the_thread
2330)
2331{
2332  return (Status_Control) the_thread->Wait.return_code;
2333}
2334
2335/**
2336 * @brief Cancels a blocking operation so that the thread can continue its
2337 * execution.
2338 *
2339 * In case this function actually cancelled the blocking operation, then the
2340 * thread wait return code is set to the specified status.
2341 *
2342 * A specialization of this function is _Thread_Timeout().
2343 *
2344 * @param[in, out] the_thread The thread.
2345 * @param status The thread wait status.
2346 */
2347void _Thread_Continue( Thread_Control *the_thread, Status_Control status );
2348
2349/**
2350 * @brief General purpose thread wait timeout.
2351 *
2352 * @param the_watchdog The thread timer watchdog.
2353 */
2354void _Thread_Timeout( Watchdog_Control *the_watchdog );
2355
2356/**
2357 * @brief Initializes the thread timer.
2358 *
2359 * @param [in, out] timer The timer to initialize.
2360 * @param cpu The cpu for the operation.
2361 */
2362RTEMS_INLINE_ROUTINE void _Thread_Timer_initialize(
2363  Thread_Timer_information *timer,
2364  Per_CPU_Control          *cpu
2365)
2366{
2367  _ISR_lock_Initialize( &timer->Lock, "Thread Timer" );
2368  timer->header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ];
2369  _Watchdog_Preinitialize( &timer->Watchdog, cpu );
2370}
2371
2372/**
2373 * @brief Adds timeout ticks to the thread.
2374 *
2375 * @param[in, out] the_thread The thread to add the timeout ticks to.
2376 * @param cpu The cpu for the operation.
2377 * @param ticks The ticks to add to the timeout ticks.
2378 */
2379RTEMS_INLINE_ROUTINE void _Thread_Add_timeout_ticks(
2380  Thread_Control    *the_thread,
2381  Per_CPU_Control   *cpu,
2382  Watchdog_Interval  ticks
2383)
2384{
2385  ISR_lock_Context lock_context;
2386
2387  _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
2388
2389  the_thread->Timer.header =
2390    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ];
2391  the_thread->Timer.Watchdog.routine = _Thread_Timeout;
2392  _Watchdog_Per_CPU_insert_ticks( &the_thread->Timer.Watchdog, cpu, ticks );
2393
2394  _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
2395}
2396
2397/**
2398 * @brief Inserts the cpu's watchdog realtime into the thread's timer.
2399 *
2400 * @param[in, out] the_thread for the operation.
2401 * @param cpu The cpu to get the watchdog header from.
2402 * @param routine The watchdog routine for the thread.
2403 * @param expire Expiration for the watchdog.
2404 */
2405RTEMS_INLINE_ROUTINE void _Thread_Timer_insert_realtime(
2406  Thread_Control                 *the_thread,
2407  Per_CPU_Control                *cpu,
2408  Watchdog_Service_routine_entry  routine,
2409  uint64_t                        expire
2410)
2411{
2412  ISR_lock_Context  lock_context;
2413  Watchdog_Header  *header;
2414
2415  _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
2416
2417  header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ];
2418  the_thread->Timer.header = header;
2419  the_thread->Timer.Watchdog.routine = routine;
2420  _Watchdog_Per_CPU_insert( &the_thread->Timer.Watchdog, cpu, header, expire );
2421
2422  _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
2423}
2424
2425/**
2426 * @brief Remove the watchdog timer from the thread.
2427 *
2428 * @param[in, out] the_thread The thread to remove the watchdog from.
2429 */
2430RTEMS_INLINE_ROUTINE void _Thread_Timer_remove( Thread_Control *the_thread )
2431{
2432  ISR_lock_Context lock_context;
2433
2434  _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
2435
2436  _Watchdog_Per_CPU_remove(
2437    &the_thread->Timer.Watchdog,
2438#if defined(RTEMS_SMP)
2439    the_thread->Timer.Watchdog.cpu,
2440#else
2441    _Per_CPU_Get(),
2442#endif
2443    the_thread->Timer.header
2444  );
2445
2446  _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
2447}
2448
2449/**
2450 * @brief Remove the watchdog timer from the thread and unblock if necessary.
2451 *
2452 * @param[in, out] the_thread The thread to remove the watchdog from and unblock
2453 *      if necessary.
2454 * @param queue The thread queue.
2455 */
2456RTEMS_INLINE_ROUTINE void _Thread_Remove_timer_and_unblock(
2457  Thread_Control     *the_thread,
2458  Thread_queue_Queue *queue
2459)
2460{
2461  _Thread_Wait_tranquilize( the_thread );
2462  _Thread_Timer_remove( the_thread );
2463
2464#if defined(RTEMS_MULTIPROCESSING)
2465  if ( _Objects_Is_local_id( the_thread->Object.id ) ) {
2466    _Thread_Unblock( the_thread );
2467  } else {
2468    _Thread_queue_Unblock_proxy( queue, the_thread );
2469  }
2470#else
2471  (void) queue;
2472  _Thread_Unblock( the_thread );
2473#endif
2474}
2475
2476/**
2477 * @brief Sets the name of the thread.
2478 *
2479 * @param[out] the_thread  The thread to change the name of.
2480 * @param name The new name for the thread.
2481 *
2482 * @retval STATUS_SUCCESSFUL The operation succeeded.
2483 * @retval STATUS_RESULT_TOO_LARGE The name was too long.
2484 */
2485Status_Control _Thread_Set_name(
2486  Thread_Control *the_thread,
2487  const char     *name
2488);
2489
2490/**
2491 * @brief Gets the name of the thread.
2492 *
2493 * @param the_thread The thread to get the name of.
2494 * @param[out] buffer Contains the thread's name.
2495 * @param buffer_size The size of @a buffer.
2496 *
2497 * @return The number of bytes copied to @a buffer.
2498 */
2499size_t _Thread_Get_name(
2500  const Thread_Control *the_thread,
2501  char                 *buffer,
2502  size_t                buffer_size
2503);
2504
2505#if defined(RTEMS_SMP)
2506#define THREAD_PIN_STEP 2
2507
2508#define THREAD_PIN_PREEMPTION 1
2509
2510/**
2511 * @brief Unpins the thread.
2512 *
2513 * @param executing The currently executing thread.
2514 * @param cpu_self The cpu for the operation.
2515 */
2516void _Thread_Do_unpin(
2517  Thread_Control  *executing,
2518  Per_CPU_Control *cpu_self
2519);
2520#endif
2521
2522/**
2523 * @brief Pin the executing thread.
2524 *
2525 * @param executing The currently executing thread.
2526 */
2527RTEMS_INLINE_ROUTINE void _Thread_Pin( Thread_Control *executing )
2528{
2529#if defined(RTEMS_SMP)
2530  _Assert( executing == _Thread_Executing );
2531
2532  executing->Scheduler.pin_level += THREAD_PIN_STEP;
2533#else
2534  (void) executing;
2535#endif
2536}
2537
2538/**
2539 * @brief Unpins the thread.
2540 *
2541 * @param executing The currently executing thread.
2542 * @param cpu_self The cpu for the operation.
2543 */
2544RTEMS_INLINE_ROUTINE void _Thread_Unpin(
2545  Thread_Control  *executing,
2546  Per_CPU_Control *cpu_self
2547)
2548{
2549#if defined(RTEMS_SMP)
2550  unsigned int pin_level;
2551
2552  _Assert( executing == _Thread_Executing );
2553
2554  pin_level = executing->Scheduler.pin_level;
2555  _Assert( pin_level > 0 );
2556
2557  if (
2558    RTEMS_PREDICT_TRUE(
2559      pin_level != ( THREAD_PIN_STEP | THREAD_PIN_PREEMPTION )
2560    )
2561  ) {
2562    executing->Scheduler.pin_level = pin_level - THREAD_PIN_STEP;
2563  } else {
2564    _Thread_Do_unpin( executing, cpu_self );
2565  }
2566#else
2567  (void) executing;
2568  (void) cpu_self;
2569#endif
2570}
2571
2572/** @}*/
2573
2574#ifdef __cplusplus
2575}
2576#endif
2577
2578#if defined(RTEMS_MULTIPROCESSING)
2579#include <rtems/score/threadmp.h>
2580#endif
2581
2582#endif
2583/* end of include file */
Note: See TracBrowser for help on using the repository browser.