source: rtems/cpukit/include/rtems/score/threadimpl.h @ 3657cde

5
Last change on this file since 3657cde was 3657cde, checked in by Andreas Dachsberger <andreas.dachsberger@…>, on 04/16/19 at 10:40:38

doxygen: score: adjust doc in threadimpl.h to doxygen guidelines

Update #3706.

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