rtems_task Floating_point_task_1( rtems_task_argument argument ) { Scheduler_priority_Context *scheduler_context = _Scheduler_priority_Get_context( _Scheduler_Get( _Thread_Get_executing() ) ); Thread_Control *executing; FP_DECLARE; context_switch_restore_1st_fp_time = benchmark_timer_read(); executing = _Thread_Get_executing(); set_thread_executing( (Thread_Control *) _Chain_First(&scheduler_context->Ready[FP2_PRIORITY]) ); /* do not force context switch */ set_thread_dispatch_necessary( false ); _Thread_Dispatch_disable(); benchmark_timer_initialize(); #if (CPU_HARDWARE_FP == 1) || (CPU_SOFTWARE_FP == 1) _Context_Save_fp( &executing->fp_context ); _Context_Restore_fp( &_Thread_Get_executing()->fp_context ); #endif _Context_Switch( &executing->Registers, &_Thread_Get_executing()->Registers ); /* switch to Floating_point_task_2 */ context_switch_save_idle_restore_initted_time = benchmark_timer_read(); FP_LOAD( 1.0 ); executing = _Thread_Get_executing(); set_thread_executing( (Thread_Control *) _Chain_First(&scheduler_context->Ready[FP2_PRIORITY]) ); benchmark_timer_initialize(); #if (CPU_HARDWARE_FP == 1) || (CPU_SOFTWARE_FP == 1) _Context_Save_fp( &executing->fp_context ); _Context_Restore_fp( &_Thread_Get_executing()->fp_context ); #endif _Context_Switch( &executing->Registers, &_Thread_Get_executing()->Registers ); /* switch to Floating_point_task_2 */ }
rtems_task Floating_point_task_1( rtems_task_argument argument ) { Chain_Control *ready_queues; Thread_Control *executing; FP_DECLARE; context_switch_restore_1st_fp_time = benchmark_timer_read(); executing = _Thread_Executing; ready_queues = (Chain_Control *) _Scheduler.information; _Thread_Executing = (Thread_Control *) _Chain_First(&ready_queues[FP2_PRIORITY]); /* do not force context switch */ _Thread_Dispatch_necessary = false; _Thread_Disable_dispatch(); benchmark_timer_initialize(); #if (CPU_HARDWARE_FP == 1) || (CPU_SOFTWARE_FP == 1) _Context_Save_fp( &executing->fp_context ); _Context_Restore_fp( &_Thread_Executing->fp_context ); #endif _Context_Switch( &executing->Registers, &_Thread_Executing->Registers ); /* switch to Floating_point_task_2 */ context_switch_save_idle_restore_initted_time = benchmark_timer_read(); FP_LOAD( 1.0 ); executing = _Thread_Executing; ready_queues = (Chain_Control *) _Scheduler.information; _Thread_Executing = (Thread_Control *) _Chain_First(&ready_queues[FP2_PRIORITY]); /* do not force context switch */ _Thread_Dispatch_necessary = false; _Thread_Disable_dispatch(); benchmark_timer_initialize(); #if (CPU_HARDWARE_FP == 1) || (CPU_SOFTWARE_FP == 1) _Context_Save_fp( &executing->fp_context ); _Context_Restore_fp( &_Thread_Executing->fp_context ); #endif _Context_Switch( &executing->Registers, &_Thread_Executing->Registers ); /* switch to Floating_point_task_2 */ }
rtems_task Middle_task( rtems_task_argument argument ) { Chain_Control *ready_queues; thread_dispatch_no_fp_time = benchmark_timer_read(); _Thread_Set_state( _Thread_Executing, STATES_SUSPENDED ); Middle_tcb = _Thread_Executing; ready_queues = (Chain_Control *) _Scheduler.information; _Thread_Executing = (Thread_Control *) _Chain_First(&ready_queues[LOW_PRIORITY]); /* do not force context switch */ _Thread_Dispatch_necessary = false; _Thread_Disable_dispatch(); benchmark_timer_initialize(); _Context_Switch( &Middle_tcb->Registers, &_Thread_Executing->Registers ); benchmark_timer_initialize(); _Context_Switch(&Middle_tcb->Registers, &Low_tcb->Registers); }
rtems_task Middle_task( rtems_task_argument argument ) { Scheduler_priority_Context *scheduler_context = _Scheduler_priority_Get_context( _Scheduler_Get( _Thread_Get_executing() ) ); thread_dispatch_no_fp_time = benchmark_timer_read(); _Thread_Set_state( _Thread_Get_executing(), STATES_SUSPENDED ); Middle_tcb = _Thread_Get_executing(); set_thread_executing( (Thread_Control *) _Chain_First(&scheduler_context->Ready[LOW_PRIORITY]) ); /* do not force context switch */ set_thread_dispatch_necessary( false ); _Thread_Dispatch_disable(); benchmark_timer_initialize(); _Context_Switch( &Middle_tcb->Registers, &_Thread_Get_executing()->Registers ); benchmark_timer_initialize(); _Context_Switch(&Middle_tcb->Registers, &Low_tcb->Registers); }
void _Scheduler_priority_Yield(void) { Scheduler_priority_Per_thread *sched_info; ISR_Level level; Thread_Control *executing; Chain_Control *ready; executing = _Thread_Executing; sched_info = (Scheduler_priority_Per_thread *) executing->scheduler_info; ready = sched_info->ready_chain; _ISR_Disable( level ); if ( !_Chain_Has_only_one_node( ready ) ) { _Chain_Extract_unprotected( &executing->Object.Node ); _Chain_Append_unprotected( ready, &executing->Object.Node ); _ISR_Flash( level ); if ( _Thread_Is_heir( executing ) ) _Thread_Heir = (Thread_Control *) _Chain_First( ready ); _Thread_Dispatch_necessary = true; } else if ( !_Thread_Is_heir( executing ) ) _Thread_Dispatch_necessary = true; _ISR_Enable( level ); }
void _Thread_Scheduler_ask_for_help( Thread_Control *the_thread ) { Chain_Node *node; const Chain_Node *tail; node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); do { Scheduler_Node *scheduler_node; const Scheduler_Control *scheduler; ISR_lock_Context lock_context; bool success; scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); _Scheduler_Acquire_critical( scheduler, &lock_context ); success = ( *scheduler->Operations.ask_for_help )( scheduler, the_thread, scheduler_node ); _Scheduler_Release_critical( scheduler, &lock_context ); if ( success ) { break; } node = _Chain_Next( node ); } while ( node != tail ); }
void _Scheduler_simple_Ready_queue_enqueue_first( Thread_Control *the_thread ) { Chain_Control *ready; Chain_Node *the_node; Thread_Control *current; ready = (Chain_Control *)_Scheduler.information; current = (Thread_Control *)ready; /* * Do NOT need to check for end of chain because there is always * at least one task on the ready chain -- the IDLE task. It can * never block, should never attempt to obtain a semaphore or mutex, * and thus will always be there. */ for ( the_node = _Chain_First(ready) ; ; the_node = the_node->next ) { current = (Thread_Control *) the_node; /* break when AT HEAD OF (or PAST) our priority */ if ( the_thread->current_priority <= current->current_priority ) { current = (Thread_Control *)current->Object.Node.previous; break; } } /* enqueue */ _Chain_Insert_unprotected( (Chain_Node *)current, &the_thread->Object.Node ); }
void _SMP_Multicast_actions_process( void ) { SMP_lock_Context lock_context; uint32_t cpu_self_index; SMP_Multicast_action *node; SMP_Multicast_action *next; _SMP_lock_ISR_disable_and_acquire( &_SMP_Multicast.Lock, &lock_context ); cpu_self_index = _SMP_Get_current_processor(); node = (SMP_Multicast_action *) _Chain_First( &_SMP_Multicast.Actions ); while ( !_Chain_Is_tail( &_SMP_Multicast.Actions, &node->Node ) ) { next = (SMP_Multicast_action *) _Chain_Next( &node->Node ); if ( _Processor_mask_Is_set( &node->targets, cpu_self_index ) ) { _Processor_mask_Clear( &node->targets, cpu_self_index ); ( *node->handler )( node->arg ); if ( _Processor_mask_Is_zero( &node->targets ) ) { _Chain_Extract_unprotected( &node->Node ); _Atomic_Store_ulong( &node->done, 1, ATOMIC_ORDER_RELEASE ); } } node = next; } _SMP_lock_Release_and_ISR_enable( &_SMP_Multicast.Lock, &lock_context ); }
static void _Watchdog_Insert_fixup( Watchdog_Header *header, Watchdog_Control *the_watchdog, Watchdog_Interval delta, Watchdog_Control *next_watchdog, Watchdog_Interval delta_next ) { const Chain_Node *iterator_tail; Chain_Node *iterator_node; next_watchdog->delta_interval = delta_next - delta; iterator_node = _Chain_First( &header->Iterators ); iterator_tail = _Chain_Immutable_tail( &header->Iterators ); while ( iterator_node != iterator_tail ) { Watchdog_Iterator *iterator; iterator = (Watchdog_Iterator *) iterator_node; if ( iterator->current == &next_watchdog->Node ) { iterator->current = &the_watchdog->Node; } iterator_node = _Chain_Next( iterator_node ); } }
static inline CORE_mutex_Status _CORE_mutex_Pop_priority( CORE_mutex_Control *mutex, Thread_Control *holder ) { /* * Check whether the holder release the mutex in LIFO order if not return * error code. */ if ( _Chain_First( holder->lock_mutex ) != &mutex->queue.lock_queue ) { mutex->nest_count++; return CORE_MUTEX_RELEASE_NOT_ORDER; } /* * This pops the first node from the list. */ _Chain_Get_first_unprotected( &holder->lock_mutex ); if ( mutex->queue.priority_before != holder->current_priority ) _Thread_Change_priority( holder, mutex->queue.priority_before, true ); return CORE_MUTEX_STATUS_SUCCESSFUL; }
void _Objects_MP_Close ( Objects_Information *information, Objects_Id the_id ) { Chain_Control *the_chain; Chain_Node *the_node; Objects_MP_Control *the_object; the_chain = &information->global_table[ _Objects_Get_node( the_id ) ]; for ( the_node = _Chain_First( the_chain ) ; !_Chain_Is_tail( the_chain, the_node ) ; the_node = _Chain_Next( the_node ) ) { the_object = (Objects_MP_Control *) the_node; if ( _Objects_Are_ids_equal( the_object->Object.id, the_id ) ) { _Chain_Extract( the_node ); _Objects_MP_Free_global_object( the_object ); return; } } _Terminate( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_INVALID_GLOBAL_ID ); }
void _Watchdog_Report_chain( const char *name, Chain_Control *header ) { ISR_Level level; Chain_Node *node; _ISR_Disable( level ); printk( "Watchdog Chain: %s %p\n", name, header ); if ( !_Chain_Is_empty( header ) ) { for ( node = _Chain_First( header ) ; node != _Chain_Tail(header) ; node = node->next ) { Watchdog_Control *watch = (Watchdog_Control *) node; _Watchdog_Report( NULL, watch ); } printk( "== end of %s \n", name ); } else { printk( "Chain is empty\n" ); } _ISR_Enable( level ); }
static Thread_Control *_Thread_queue_FIFO_first( Thread_queue_Heads *heads ) { Chain_Control *fifo = &heads->Heads.Fifo; return _Chain_Is_empty( fifo ) ? NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_First( fifo ) ); }
static Thread_Control *_Scheduler_simple_SMP_Get_highest_ready( Scheduler_Context *context ) { Scheduler_simple_SMP_Context *self = _Scheduler_simple_SMP_Get_self( context ); return (Thread_Control *) _Chain_First( &self->Ready ); }
Thread_Control *_Thread_queue_First_fifo( Thread_queue_Control *the_thread_queue ) { if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) return (Thread_Control *) _Chain_First( &the_thread_queue->Queues.Fifo ); return NULL; }
static void _Watchdog_Remove_it( Watchdog_Header *header, Watchdog_Control *the_watchdog ) { Chain_Node *next; Watchdog_Interval delta; const Chain_Node *iterator_tail; Chain_Node *iterator_node; _Assert( the_watchdog->state == WATCHDOG_ACTIVE ); the_watchdog->state = WATCHDOG_INACTIVE; the_watchdog->stop_time = _Watchdog_Ticks_since_boot; next = _Chain_Next( &the_watchdog->Node ); delta = the_watchdog->delta_interval; if ( next != _Chain_Tail( &header->Watchdogs ) ) { Watchdog_Control *next_watchdog; next_watchdog = (Watchdog_Control *) next; next_watchdog->delta_interval += delta; } _Chain_Extract_unprotected( &the_watchdog->Node ); iterator_node = _Chain_First( &header->Iterators ); iterator_tail = _Chain_Immutable_tail( &header->Iterators ); while ( iterator_node != iterator_tail ) { Watchdog_Iterator *iterator; iterator = (Watchdog_Iterator *) iterator_node; if ( iterator->current == next ) { iterator->delta_interval += delta; } if ( iterator->current == &the_watchdog->Node ) { Chain_Node *previous = _Chain_Previous( &the_watchdog->Node ); iterator->current = previous; if ( previous != _Chain_Head( &header->Watchdogs ) ) { Watchdog_Control *previous_watchdog; previous_watchdog = (Watchdog_Control *) previous; iterator->delta_interval += previous_watchdog->delta_interval; } } iterator_node = _Chain_Next( iterator_node ); } }
void _Objects_MP_Is_remote ( Objects_Information *information, Objects_Id the_id, Objects_Locations *location, Objects_Control **the_object ) { uint32_t node; Chain_Control *the_chain; Chain_Node *the_node; Objects_MP_Control *the_global_object; node = _Objects_Get_node( the_id ); /* * NOTE: The local node was search (if necessary) by * _Objects_Name_to_id_XXX before this was invoked. * * The NODE field of an object id cannot be 0 * because 0 is an invalid node number. */ if ( node == 0 || _Objects_Is_local_node( node ) || node > _Objects_Maximum_nodes || information->global_table == NULL ) { *location = OBJECTS_ERROR; *the_object = NULL; return; } _Thread_Disable_dispatch(); the_chain = &information->global_table[ node ]; for ( the_node = _Chain_First( the_chain ) ; !_Chain_Is_tail( the_chain, the_node ) ; the_node = _Chain_Next( the_node ) ) { the_global_object = (Objects_MP_Control *) the_node; if ( _Objects_Are_ids_equal( the_global_object->Object.id, the_id ) ) { _Thread_Unnest_dispatch(); *location = OBJECTS_REMOTE; *the_object = (Objects_Control *) the_global_object; return; } } _Thread_Enable_dispatch(); *location = OBJECTS_ERROR; *the_object = NULL; }
rtems_task Task_2( rtems_task_argument argument ) { #if defined(RTEMS_SMP) rtems_interrupt_level level; #endif Chain_Control *ready_queues; #if (MUST_WAIT_FOR_INTERRUPT == 1) while ( Interrupt_occurred == 0 ); #endif end_time = benchmark_timer_read(); put_time( "rtems interrupt: entry overhead returns to preempting task", Interrupt_enter_time, 1, 0, timer_overhead ); put_time( "rtems interrupt: exit overhead returns to preempting task", end_time, 1, 0, 0 ); fflush( stdout ); /* * Switch back to the other task to exit the test. */ #if defined(RTEMS_SMP) rtems_interrupt_disable(level); #endif ready_queues = (Chain_Control *) _Scheduler.information; _Thread_Executing = (Thread_Control *) _Chain_First(&ready_queues[LOW_PRIORITY]); _Thread_Dispatch_necessary = 1; #if defined(RTEMS_SMP) rtems_interrupt_enable(level); #endif _Thread_Dispatch(); }
void _Objects_Shrink_information( Objects_Information *information ) { uint32_t block_count; uint32_t block; uint32_t index_base; /* * Search the list to find block or chunk with all objects inactive. */ index_base = _Objects_Get_index( information->minimum_id ); block_count = (information->maximum - index_base) / information->allocation_size; for ( block = 0; block < block_count; block++ ) { if ( information->inactive_per_block[ block ] == information->allocation_size ) { Chain_Node *node = _Chain_First( &information->Inactive ); const Chain_Node *tail = _Chain_Immutable_tail( &information->Inactive ); uint32_t index_end = index_base + information->allocation_size; while ( node != tail ) { Objects_Control *object = (Objects_Control *) node; uint32_t index = _Objects_Get_index( object->id ); /* * Get the next node before the node is extracted */ node = _Chain_Next( node ); if ( index >= index_base && index < index_end ) { _Chain_Extract( &object->Node ); } } /* * Free the memory and reset the structures in the object' information */ _Workspace_Free( information->object_blocks[ block ] ); information->object_blocks[ block ] = NULL; information->inactive_per_block[ block ] = 0; information->inactive -= information->allocation_size; return; } index_base += information->allocation_size; } }
static Thread_Control *_Thread_queue_FIFO_first( Thread_queue_Heads *heads ) { Chain_Control *fifo = &heads->Heads.Fifo; Chain_Node *first; _Assert( !_Chain_Is_empty( fifo ) ); first = _Chain_First( fifo ); return THREAD_CHAIN_NODE_TO_THREAD( first ); }
/* * _POSIX_Keys_Run_destructors * * 17.1.1 Thread-Specific Data Key Create, P1003.1c/Draft 10, p. 163 * * NOTE: This is the routine executed when a thread exits to * run through all the keys and do the destructor action. */ void _POSIX_Keys_Run_destructors( Thread_Control *thread ) { Chain_Control *chain; POSIX_Keys_Key_value_pair *iter, *next; void *value; void (*destructor) (void *); POSIX_Keys_Control *the_key; Objects_Locations location; _Thread_Disable_dispatch(); chain = &( (POSIX_API_Control *)thread->API_Extensions[ THREAD_API_POSIX ] )->Key_Chain; iter = (POSIX_Keys_Key_value_pair *) _Chain_First( chain ); while ( !_Chain_Is_tail( chain, &iter->Key_values_per_thread_node ) ) { next = (POSIX_Keys_Key_value_pair *) _Chain_Next( &iter->Key_values_per_thread_node ); /** * remove key from rbtree and chain. * here Chain_Node *iter can be convert to POSIX_Keys_Key_value_pair *, * because Chain_Node is the first member of POSIX_Keys_Key_value_pair * structure. */ _RBTree_Extract( &_POSIX_Keys_Key_value_lookup_tree, &iter->Key_value_lookup_node ); _Chain_Extract_unprotected( &iter->Key_values_per_thread_node ); /** * run key value's destructor if destructor and value are both non-null. */ the_key = _POSIX_Keys_Get( iter->key, &location ); destructor = the_key->destructor; value = iter->value; if ( destructor != NULL && value != NULL ) (*destructor)( value ); _Objects_Put( &the_key->Object ); _POSIX_Keys_Key_value_pair_free( iter ); iter = next; } _Thread_Enable_dispatch(); }
static Thread_Control *_Thread_queue_FIFO_first( Thread_queue_Heads *heads ) { Chain_Control *fifo; Chain_Node *first; Scheduler_Node *scheduler_node; fifo = &heads->Heads.Fifo; _Assert( !_Chain_Is_empty( fifo ) ); first = _Chain_First( fifo ); scheduler_node = SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( first ); return _Scheduler_Node_get_owner( scheduler_node ); }
rtems_task Task_2( rtems_task_argument argument ) { Thread_Control *executing = _Thread_Get_executing(); Scheduler_priority_Context *scheduler_context = _Scheduler_priority_Get_context( _Scheduler_Get( executing ) ); ISR_lock_Context lock_context; #if (MUST_WAIT_FOR_INTERRUPT == 1) while ( Interrupt_occurred == 0 ); #endif end_time = benchmark_timer_read(); put_time( "rtems interrupt: entry overhead returns to preempting task", Interrupt_enter_time, 1, 0, timer_overhead ); put_time( "rtems interrupt: exit overhead returns to preempting task", end_time, 1, 0, 0 ); fflush( stdout ); /* * Switch back to the other task to exit the test. */ _Scheduler_Acquire( executing, &lock_context ); _Thread_Executing = (Thread_Control *) _Chain_First(&scheduler_context->Ready[LOW_PRIORITY]); _Thread_Dispatch_necessary = 1; _Scheduler_Release( executing, &lock_context ); _Thread_Dispatch(); }
Thread_Control *_Thread_queue_First_priority ( Thread_queue_Control *the_thread_queue ) { uint32_t index; for( index=0 ; index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ; index++ ) { if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) return (Thread_Control *) _Chain_First( &the_thread_queue->Queues.Priority[ index ] ); } return NULL; }
Thread_Control *_Thread_MP_Find_proxy ( Objects_Id the_id ) { Chain_Node *proxy_node; Thread_Control *the_thread; ISR_Level level; restart: _ISR_Disable( level ); for ( proxy_node = _Chain_First( &_Thread_MP_Active_proxies ); !_Chain_Is_tail( &_Thread_MP_Active_proxies, proxy_node ) ; ) { the_thread = (Thread_Control *) _Addresses_Subtract_offset( proxy_node, _Thread_MP_Proxy_Active_offset ); if ( _Objects_Are_ids_equal( the_thread->Object.id, the_id ) ) { _ISR_Enable( level ); return the_thread; } _ISR_Flash( level ); proxy_node = _Chain_Next( proxy_node ); /* * A proxy which is only dormant is not in a blocking state. * Therefore, we are looking at proxy which has been moved from * active to inactive chain (by an ISR) and need to restart * the search. */ if ( _States_Is_only_dormant( the_thread->current_state ) ) { _ISR_Enable( level ); goto restart; } } _ISR_Enable( level ); return NULL; }
void _User_extensions_Thread_begin ( Thread_Control *executing ) { Chain_Node *the_node; User_extensions_Control *the_extension; for ( the_node = _Chain_First( &_User_extensions_List ); !_Chain_Is_tail( &_User_extensions_List, the_node ) ; the_node = the_node->next ) { the_extension = (User_extensions_Control *) the_node; if ( the_extension->Callouts.thread_begin != NULL ) (*the_extension->Callouts.thread_begin)( executing ); } }
void _User_extensions_Thread_switch ( Thread_Control *executing, Thread_Control *heir ) { Chain_Node *the_node; User_extensions_Switch_control *the_extension_switch; for ( the_node = _Chain_First( &_User_extensions_Switches_list ); !_Chain_Is_tail( &_User_extensions_Switches_list, the_node ) ; the_node = the_node->next ) { the_extension_switch = (User_extensions_Switch_control *) the_node; (*the_extension_switch->thread_switch)( executing, heir ); } }
void _Scheduler_simple_smp_Extract( Thread_Control *thread ) { Scheduler_simple_smp_Control *self = _Scheduler_simple_smp_Instance(); _Chain_Extract_unprotected( &thread->Object.Node ); if ( thread->is_scheduled ) { Thread_Control *highest_ready = (Thread_Control *) _Chain_First( &self->ready ); _Scheduler_simple_smp_Allocate_processor( highest_ready, thread ); _Scheduler_simple_smp_Move_from_ready_to_scheduled( &self->scheduled, highest_ready ); } }
rtems_task Low_task( rtems_task_argument argument ) { Scheduler_priority_Context *scheduler_context = _Scheduler_priority_Get_context( _Scheduler_Get( _Thread_Get_executing() ) ); Thread_Control *executing; context_switch_no_fp_time = benchmark_timer_read(); executing = _Thread_Get_executing(); Low_tcb = executing; benchmark_timer_initialize(); _Context_Switch( &executing->Registers, &executing->Registers ); context_switch_self_time = benchmark_timer_read(); _Context_Switch(&executing->Registers, &Middle_tcb->Registers); context_switch_another_task_time = benchmark_timer_read(); set_thread_executing( (Thread_Control *) _Chain_First(&scheduler_context->Ready[FP1_PRIORITY]) ); /* do not force context switch */ set_thread_dispatch_necessary( false ); thread_disable_dispatch(); benchmark_timer_initialize(); #if (CPU_HARDWARE_FP == 1) || (CPU_SOFTWARE_FP == 1) _Context_Restore_fp( &_Thread_Get_executing()->fp_context ); #endif _Context_Switch( &executing->Registers, &_Thread_Get_executing()->Registers ); }
static Thread_Control *_Thread_queue_Priority_first( Thread_queue_Heads *heads ) { Thread_queue_Priority_queue *priority_queue; RBTree_Node *first; #if defined(RTEMS_SMP) _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) ); priority_queue = (Thread_queue_Priority_queue *) _Chain_First( &heads->Heads.Fifo ); #else priority_queue = &heads->Heads.Priority; #endif _Assert( !_RBTree_Is_empty( &priority_queue->Queue ) ); first = _RBTree_Minimum( &priority_queue->Queue ); return THREAD_RBTREE_NODE_TO_THREAD( first ); }