/** * @file * * @brief Inlined Routines from the Thread Handler * * This file contains the macro implementation of the inlined * routines from the Thread handler. */ /* * COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. */ #ifndef _RTEMS_SCORE_THREADIMPL_H #define _RTEMS_SCORE_THREADIMPL_H #include #ifdef __cplusplus extern "C" { #endif /** * @addtogroup ScoreThread */ /**@{**/ /** * The following structure contains the information necessary to manage * a thread which it is waiting for a resource. */ #define THREAD_STATUS_PROXY_BLOCKING 0x1111111 /** * Self for the GNU Ada Run-Time */ SCORE_EXTERN void *rtems_ada_self; /** * The following defines the information control block used to * manage this class of objects. */ SCORE_EXTERN Objects_Information _Thread_Internal_information; /** * The following context area contains the context of the "thread" * which invoked the start multitasking routine. This context is * restored as the last action of the stop multitasking routine. Thus * control of the processor can be returned to the environment * which initiated the system. */ SCORE_EXTERN Context_Control _Thread_BSP_context; /** * The following holds how many user extensions are in the system. This * is used to determine how many user extension data areas to allocate * per thread. */ SCORE_EXTERN uint32_t _Thread_Maximum_extensions; /** * The following is used to manage the length of a timeslice quantum. */ SCORE_EXTERN uint32_t _Thread_Ticks_per_timeslice; /** * The following points to the thread whose floating point * context is currently loaded. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) SCORE_EXTERN Thread_Control *_Thread_Allocated_fp; #endif #if !defined(__DYNAMIC_REENT__) /** * The C library re-enter-rant global pointer. Some C library implementations * such as newlib have a single global pointer that changed during a context * switch. The pointer points to that global pointer. The Thread control block * holds a pointer to the task specific data. */ SCORE_EXTERN struct _reent **_Thread_libc_reent; #endif /** * @brief Initialize thread handler. * * This routine performs the initialization necessary for this handler. */ void _Thread_Handler_initialization(void); /** * @brief Create idle thread. * * This routine creates the idle thread. * * @warning No thread should be created before this one. */ void _Thread_Create_idle(void); /** * @brief Start thread multitasking. * * This routine initiates multitasking. It is invoked only as * part of initialization and its invocation is the last act of * the non-multitasking part of the system initialization. * * * - INTERRUPT LATENCY: * + ready chain * + select heir */ void _Thread_Start_multitasking( void ); /** * @brief Allocate the requested stack space for the thread. * * Allocate the requested stack space for the thread. * Set the Start.stack field to the address of the stack. * * @param[in] the_thread is the thread where the stack space is requested * * @retval actual size allocated after any adjustment * @retval zero if the allocation failed */ size_t _Thread_Stack_Allocate( Thread_Control *the_thread, size_t stack_size ); /** * @brief Deallocate thread stack. * * Deallocate the Thread's stack. */ void _Thread_Stack_Free( Thread_Control *the_thread ); /** * @brief Initialize thread. * * This routine initializes the specified the thread. It allocates * all memory associated with this thread. It completes by adding * the thread to the local object table so operations on this * thread id are allowed. * * @note If stack_area is NULL, it is allocated from the workspace. * * @note If the stack is allocated from the workspace, then it is * guaranteed to be of at least minimum size. */ bool _Thread_Initialize( Objects_Information *information, Thread_Control *the_thread, void *stack_area, size_t stack_size, bool is_fp, Priority_Control priority, bool is_preemptible, Thread_CPU_budget_algorithms budget_algorithm, Thread_CPU_budget_algorithm_callout budget_callout, uint32_t isr_level, Objects_Name name ); /** * @brief Initializes thread and executes it. * * This routine initializes the executable information for a thread * and makes it ready to execute. After this routine executes, the * thread competes with all other threads for CPU time. * * @param the_thread is the thread to be initialized * @param the_prototype * @param entry_point * @param pointer_argument * @param numeric_argument * @param[in,out] processor The processor if used to start an idle thread * during system initialization. Must be set to @c NULL to start a normal * thread. */ bool _Thread_Start( Thread_Control *the_thread, Thread_Start_types the_prototype, void *entry_point, void *pointer_argument, Thread_Entry_numeric_type numeric_argument, Per_CPU_Control *processor ); /** * @brief Restarts the specified thread. * * This support routine restarts the specified task in a way that the * next time this thread executes, it will begin execution at its * original starting point. * * TODO: multiple task arg profiles */ bool _Thread_Restart( Thread_Control *the_thread, void *pointer_argument, Thread_Entry_numeric_type numeric_argument ); /** * @brief Resets a thread to its initial state. * * This routine resets a thread to its initial state but does * not restart it. Some APIs do this in separate * operations and this division helps support this. * * @param[in] the_thread is the thread to resets * @param[in] pointer_argument * @param[in] numeric_argument */ void _Thread_Reset( Thread_Control *the_thread, void *pointer_argument, Thread_Entry_numeric_type numeric_argument ); /** * @brief Frees all memory associated with the specified thread. * * This routine frees all memory associated with the specified * thread and removes it from the local object table so no further * operations on this thread are allowed. */ void _Thread_Close( Objects_Information *information, Thread_Control *the_thread ); /** * @brief Removes any set states for @a the_thread. * * This routine removes any set states for @a the_thread. It performs * any necessary scheduling operations including the selection of * a new heir thread. * * - INTERRUPT LATENCY: * + ready chain * + select heir */ void _Thread_Ready( Thread_Control *the_thread ); /** * @brief Clears the indicated STATES for @a the_thread. * * This routine clears the indicated STATES for @a the_thread. It performs * any necessary scheduling operations including the selection of * a new heir thread. * * - INTERRUPT LATENCY: * + priority map * + select heir */ void _Thread_Clear_state( Thread_Control *the_thread, States_Control state ); /** * @brief Sets the indicated @a state for @a the_thread. * * This routine sets the indicated @a state for @a the_thread. It performs * any necessary scheduling operations including the selection of * a new heir thread. * * @param[in] the_thread is the thread to set the state for. * @param[in] state is the state to set the_thread to. * * - INTERRUPT LATENCY: * + ready chain * + select map */ void _Thread_Set_state( Thread_Control *the_thread, States_Control state ); /** * @brief Sets the transient state for a thread. * * This routine sets the Transient state for @a the_thread. It performs * any necessary scheduling operations including the selection of * a new heir thread. * * @param[in] the_thread is the thread to preform the action upon. * * - INTERRUPT LATENCY: * + single case */ void _Thread_Set_transient( Thread_Control *the_thread ); /** * @brief Initializes enviroment for a thread. * * This routine initializes the context of @a the_thread to its * appropriate starting state. * * @param[in] the_thread is the pointer to the thread control block. */ void _Thread_Load_environment( Thread_Control *the_thread ); /** * @brief Wrapper function for all threads. * * This routine is the wrapper function for all threads. It is * the starting point for all threads. The user provided thread * entry point is invoked by this routine. Operations * which must be performed immediately before and after the user's * thread executes are found here. * * @note On entry, it is assumed all interrupts are blocked and that this * routine needs to set the initial isr level. This may or may not * actually be needed by the context switch routine and as a result * interrupts may already be at there proper level. Either way, * setting the initial isr level properly here is safe. */ void _Thread_Handler( void ); /** * @brief Ended the delay of a thread. * * This routine is invoked when a thread must be unblocked at the * end of a time based delay (i.e. wake after or wake when). * It is called by the watchdog handler. * * @param[in] id is the thread id */ void _Thread_Delay_ended( Objects_Id id, void *ignored ); /** * @brief Change the priority of a thread. * * This routine changes the current priority of @a the_thread to * @a new_priority. It performs any necessary scheduling operations * including the selection of a new heir thread. * * @param[in] the_thread is the thread to change * @param[in] new_priority is the priority to set @a the_thread to * @param[in] prepend_it is a switch to prepend the thread */ void _Thread_Change_priority ( Thread_Control *the_thread, Priority_Control new_priority, bool prepend_it ); /** * @brief Set thread priority. * * This routine updates the priority related fields in the_thread * control block to indicate the current priority is now new_priority. */ void _Thread_Set_priority( Thread_Control *the_thread, Priority_Control new_priority ); /** * This routine updates the related suspend fields in the_thread * control block to indicate the current nested level. */ #define _Thread_Suspend( _the_thread ) \ _Thread_Set_state( _the_thread, STATES_SUSPENDED ) /** * This routine updates the related suspend fields in the_thread * control block to indicate the current nested level. A force * parameter of true will force a resume and clear the suspend count. */ #define _Thread_Resume( _the_thread ) \ _Thread_Clear_state( _the_thread, STATES_SUSPENDED ) /** * @brief Maps thread Id to a TCB pointer. * * This function maps thread IDs to thread control * blocks. If ID corresponds to a local thread, then it * returns the_thread control pointer which maps to ID * and @a location is set to OBJECTS_LOCAL. If the thread ID is * global and resides on a remote node, then location is set * to OBJECTS_REMOTE, and the_thread is undefined. * Otherwise, location is set to OBJECTS_ERROR and * the_thread is undefined. * * @param[in] id is the id of the thread. * @param[in] location is the location of the block. * * @note The performance of many RTEMS services depends upon * the quick execution of the "good object" path in this * routine. If there is a possibility of saving a few * cycles off the execution time, this routine is worth * further optimization attention. */ Thread_Control *_Thread_Get ( Objects_Id id, Objects_Locations *location ); /** * @brief Cancel a blocking operation due to ISR. * * This method is used to cancel a blocking operation that was * satisfied from an ISR while the thread executing was in the * process of blocking. * * This method will restore the previous ISR disable level during the cancel * operation. Thus it is an implicit _ISR_Enable(). * * @param[in] sync_state is the synchronization state * @param[in] the_thread is the thread whose blocking is canceled * @param[in] level is the previous ISR disable level * * @note This is a rare routine in RTEMS. It is called with * interrupts disabled and only when an ISR completed * a blocking condition in process. */ void _Thread_blocking_operation_Cancel( Thread_blocking_operation_States sync_state, Thread_Control *the_thread, ISR_Level level ); /** * This routine halts multitasking and returns control to * the "thread" (i.e. the BSP) which initially invoked the * routine which initialized the system. */ RTEMS_INLINE_ROUTINE void _Thread_Stop_multitasking( void ) { #if defined(_CPU_Stop_multitasking) _CPU_Stop_multitasking( &_Thread_BSP_context ); #else /* * This may look a bit of an odd but _Context_Restart_self is just * a very careful restore of a specific context which ensures that * if we were running within the same context, it would work. * * And we will not return to this thread, so there is no point of * saving the context. */ _Context_Restart_self( &_Thread_BSP_context ); #endif /*************************************************************** *************************************************************** * SYSTEM SHUTS DOWN!!! WE DO NOT RETURN TO THIS POINT!!! * *************************************************************** *************************************************************** */ } /** * This function returns true if the_thread is the currently executing * thread, and false otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_executing ( const Thread_Control *the_thread ) { return ( the_thread == _Thread_Executing ); } /** * This function returns true if the_thread is the heir * thread, and false otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_heir ( const Thread_Control *the_thread ) { return ( the_thread == _Thread_Heir ); } /** * This function returns true if the currently executing thread * is also the heir thread, and false otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_executing_also_the_heir( void ) { return ( _Thread_Executing == _Thread_Heir ); } /** * This routine clears any blocking state for the_thread. It performs * any necessary scheduling operations including the selection of * a new heir thread. */ RTEMS_INLINE_ROUTINE void _Thread_Unblock ( Thread_Control *the_thread ) { _Thread_Clear_state( the_thread, STATES_BLOCKED ); } /** * This routine resets the current context of the calling thread * to that of its initial state. */ RTEMS_INLINE_ROUTINE void _Thread_Restart_self( void ) { #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) if ( _Thread_Executing->fp_context != NULL ) _Context_Restore_fp( &_Thread_Executing->fp_context ); #endif _CPU_Context_Restart_self( &_Thread_Executing->Registers ); } /** * This function returns true if the floating point context of * the_thread is currently loaded in the floating point unit, and * false otherwise. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) RTEMS_INLINE_ROUTINE bool _Thread_Is_allocated_fp ( const Thread_Control *the_thread ) { return ( the_thread == _Thread_Allocated_fp ); } #endif /** * This routine is invoked when the currently loaded floating * point context is now longer associated with an active thread. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) RTEMS_INLINE_ROUTINE void _Thread_Deallocate_fp( void ) { _Thread_Allocated_fp = NULL; } #endif /** * This function returns true if dispatching is disabled, and false * otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_context_switch_necessary( void ) { return ( _Thread_Dispatch_necessary ); } /** * This function returns true if the_thread is NULL and false otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_null ( const Thread_Control *the_thread ) { return ( the_thread == NULL ); } /** * @brief Is proxy blocking. * * status which indicates that a proxy is blocking, and false otherwise. */ RTEMS_INLINE_ROUTINE bool _Thread_Is_proxy_blocking ( uint32_t code ) { return (code == THREAD_STATUS_PROXY_BLOCKING); } /** * This routine allocates an internal thread. */ RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Internal_allocate( void ) { return (Thread_Control *) _Objects_Allocate( &_Thread_Internal_information ); } /** * This routine frees an internal thread. */ RTEMS_INLINE_ROUTINE void _Thread_Internal_free ( Thread_Control *the_task ) { _Objects_Free( &_Thread_Internal_information, &the_task->Object ); } RTEMS_INLINE_ROUTINE void _Thread_Set_global_exit_status( uint32_t exit_status ) { Thread_Control *idle = (Thread_Control *) _Thread_Internal_information.local_table[ 1 ]; idle->Wait.return_code = exit_status; } RTEMS_INLINE_ROUTINE uint32_t _Thread_Get_global_exit_status( void ) { const Thread_Control *idle = (const Thread_Control *) _Thread_Internal_information.local_table[ 1 ]; return idle->Wait.return_code; } /** * @brief Issues a thread dispatch if necessary. * * @param[in] executing The executing thread. * @param[in] needs_asr_dispatching Indicates whether or not the API * level signals are pending and a dispatch is necessary. */ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_if_necessary( Thread_Control *executing, bool needs_asr_dispatching ) { if ( _Thread_Dispatch_is_enabled() ) { bool dispatch_necessary = needs_asr_dispatching; if ( !_Thread_Is_heir( executing ) && executing->is_preemptible ) { dispatch_necessary = true; _Thread_Dispatch_necessary = dispatch_necessary; } if ( dispatch_necessary ) { _Thread_Dispatch(); } } } #if !defined(__DYNAMIC_REENT__) /** * This routine returns the C library re-enterant pointer. */ RTEMS_INLINE_ROUTINE struct _reent **_Thread_Get_libc_reent( void ) { return _Thread_libc_reent; } /** * This routine set the C library re-enterant pointer. */ RTEMS_INLINE_ROUTINE void _Thread_Set_libc_reent ( struct _reent **libc_reent ) { _Thread_libc_reent = libc_reent; } #endif /** @}*/ #ifdef __cplusplus } #endif #if defined(RTEMS_MULTIPROCESSING) #include #endif #endif /* end of include file */