void _Thread_queue_Extract_with_return_code( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, uint32_t return_code ) { ISR_lock_Context lock_context; _Thread_queue_Acquire( &lock_context ); if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) { _Thread_queue_Release( &lock_context ); return; } if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { _Chain_Extract_unprotected( &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ _RBTree_Extract( &the_thread->Wait.queue->Queues.Priority, &the_thread->RBNode ); _Thread_Priority_restore_default_change_handler( the_thread ); _Thread_Lock_restore_default( the_thread ); } the_thread->Wait.return_code = return_code; /* * We found a thread to unblock. * * NOTE: This is invoked with interrupts still disabled. */ _Thread_blocking_operation_Finalize( the_thread, &lock_context ); }
bool _Thread_queue_Extract_with_proxy( Thread_Control *the_thread ) { States_Control state; state = the_thread->current_state; if ( _States_Is_waiting_on_thread_queue( state ) ) { #if defined(RTEMS_MULTIPROCESSING) if ( _States_Is_waiting_for_rpc_reply( state ) && _States_Is_locally_blocked( state ) ) { Objects_Information *the_information; Objects_Thread_queue_Extract_callout proxy_extract_callout; the_information = _Objects_Get_information_id( the_thread->Wait.id ); proxy_extract_callout = (Objects_Thread_queue_Extract_callout) the_information->extract; if ( proxy_extract_callout ) (*proxy_extract_callout)( the_thread ); } #endif _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); return true; } return false; }
void _Thread_queue_Requeue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread ) { /* * Just in case the thread really wasn't blocked on a thread queue * when we get here. */ if ( !the_thread_queue ) return; /* * If queueing by FIFO, there is nothing to do. This only applies to * priority blocking discipline. */ if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { Thread_queue_Control *tq = the_thread_queue; ISR_Level level; ISR_Level level_ignored; _ISR_Disable( level ); if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) { _Thread_queue_Enter_critical_section( tq ); _Thread_queue_Extract_priority_helper( tq, the_thread, true ); (void) _Thread_queue_Enqueue_priority( tq, the_thread, &level_ignored ); } _ISR_Enable( level ); } }
void _Thread_queue_Requeue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread ) { /* * Just in case the thread really wasn't blocked on a thread queue * when we get here. */ if ( !the_thread_queue ) return; /* * If queueing by FIFO, there is nothing to do. This only applies to * priority blocking discipline. */ if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { Thread_queue_Control *tq = the_thread_queue; ISR_Level level; _ISR_Disable( level ); if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) { _Thread_queue_Enter_critical_section( tq ); /* extract the thread */ _RBTree_Extract( &the_thread->Wait.queue->Queues.Priority, &the_thread->RBNode ); /* enqueue the thread at the new priority */ _RBTree_Insert( &the_thread_queue->Queues.Priority, &the_thread->RBNode, _Thread_queue_Compare_priority, false ); } _ISR_Enable( level ); } }
void _Thread_Change_priority( Thread_Control *the_thread, Priority_Control new_priority, bool prepend_it ) { ISR_Level level; States_Control state, original_state; /* * Save original state */ original_state = the_thread->current_state; /* * Set a transient state for the thread so it is pulled off the Ready chains. * This will prevent it from being scheduled no matter what happens in an * ISR. */ _Thread_Set_transient( the_thread ); /* * Do not bother recomputing all the priority related information if * we are not REALLY changing priority. */ if ( the_thread->current_priority != new_priority ) _Thread_Set_priority( the_thread, new_priority ); _ISR_Disable( level ); /* * If the thread has more than STATES_TRANSIENT set, then it is blocked, * If it is blocked on a thread queue, then we need to requeue it. */ state = the_thread->current_state; if ( state != STATES_TRANSIENT ) { /* Only clear the transient state if it wasn't set already */ if ( ! _States_Is_transient( original_state ) ) the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); _ISR_Enable( level ); if ( _States_Is_waiting_on_thread_queue( state ) ) { _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); } return; } /* Only clear the transient state if it wasn't set already */ if ( ! _States_Is_transient( original_state ) ) { /* * Interrupts are STILL disabled. * We now know the thread will be in the READY state when we remove * the TRANSIENT state. So we have to place it on the appropriate * Ready Queue with interrupts off. */ the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); if ( prepend_it ) _Scheduler_Enqueue_first( the_thread ); else _Scheduler_Enqueue( the_thread ); } _ISR_Flash( level ); /* * We altered the set of thread priorities. So let's figure out * who is the heir and if we need to switch to them. */ _Scheduler_Schedule(); if ( !_Thread_Is_executing_also_the_heir() && _Thread_Executing->is_preemptible ) _Thread_Dispatch_necessary = true; _ISR_Enable( level ); }
/* XXX this routine could probably be cleaned up */ bool _POSIX_signals_Unblock_thread( Thread_Control *the_thread, int signo, siginfo_t *info ) { POSIX_API_Control *api; sigset_t mask; siginfo_t *the_info = NULL; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; mask = signo_to_mask( signo ); /* * Is the thread is specifically waiting for a signal? */ if ( _States_Is_interruptible_signal( the_thread->current_state ) ) { if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) { the_thread->Wait.return_code = EINTR; the_info = (siginfo_t *) the_thread->Wait.return_argument; if ( !info ) { the_info->si_signo = signo; the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; } else { *the_info = *info; } _Thread_queue_Extract_with_proxy( the_thread ); return true; } /* * This should only be reached via pthread_kill(). */ return false; } /* * Thread is not waiting due to a sigwait. */ if ( ~api->signals_blocked & mask ) { /* * The thread is interested in this signal. We are going * to post it. We have a few broad cases: * + If it is blocked on an interruptible signal, THEN * we unblock the thread. * + If it is in the ready state AND * we are sending from an ISR AND * it is the interrupted thread AND * it is not blocked, THEN * we need to dispatch at the end of this ISR. * + Any other combination, do nothing. */ the_thread->do_post_task_switch_extension = true; if ( _States_Is_interruptible_by_signal( the_thread->current_state ) ) { the_thread->Wait.return_code = EINTR; /* * In pthread_cond_wait, a thread will be blocking on a thread * queue, but is also interruptible by a POSIX signal. */ if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) _Thread_queue_Extract_with_proxy( the_thread ); else if ( _States_Is_delaying(the_thread->current_state) ){ (void) _Watchdog_Remove( &the_thread->Timer ); _Thread_Unblock( the_thread ); } } else if ( the_thread->current_state == STATES_READY ) { if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) ) _ISR_Signals_to_thread_executing = true; } } return false; }
void _Thread_Change_priority( Thread_Control *the_thread, Priority_Control new_priority, bool prepend_it ) { ISR_Level level; States_Control state, original_state; /* * If this is a case where prepending the task to its priority is * potentially desired, then we need to consider whether to do it. * This usually occurs when a task lowers its priority implcitly as * the result of losing inherited priority. Normal explicit priority * change calls (e.g. rtems_task_set_priority) should always do an * append not a prepend. */ /* if ( prepend_it && _Thread_Is_executing( the_thread ) && new_priority >= the_thread->current_priority ) prepend_it = true; */ /* * Save original state */ original_state = the_thread->current_state; /* * Set a transient state for the thread so it is pulled off the Ready chains. * This will prevent it from being scheduled no matter what happens in an * ISR. */ _Thread_Set_transient( the_thread ); /* * Do not bother recomputing all the priority related information if * we are not REALLY changing priority. */ if ( the_thread->current_priority != new_priority ) _Thread_Set_priority( the_thread, new_priority ); _ISR_Disable( level ); /* * If the thread has more than STATES_TRANSIENT set, then it is blocked, * If it is blocked on a thread queue, then we need to requeue it. */ state = the_thread->current_state; if ( state != STATES_TRANSIENT ) { /* Only clear the transient state if it wasn't set already */ if ( ! _States_Is_transient( original_state ) ) the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); _ISR_Enable( level ); if ( _States_Is_waiting_on_thread_queue( state ) ) { _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); } return; } /* Only clear the transient state if it wasn't set already */ if ( ! _States_Is_transient( original_state ) ) { /* * Interrupts are STILL disabled. * We now know the thread will be in the READY state when we remove * the TRANSIENT state. So we have to place it on the appropriate * Ready Queue with interrupts off. */ the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); _Priority_Add_to_bit_map( &the_thread->Priority_map ); if ( prepend_it ) _Chain_Prepend_unprotected( the_thread->ready, &the_thread->Object.Node ); else _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node ); } _ISR_Flash( level ); /* * We altered the set of thread priorities. So let's figure out * who is the heir and if we need to switch to them. */ _Thread_Calculate_heir(); if ( !_Thread_Is_executing_also_the_heir() && _Thread_Executing->is_preemptible ) _Context_Switch_necessary = true; _ISR_Enable( level ); }
/* XXX this routine could probably be cleaned up */ boolean _POSIX_signals_Unblock_thread( Thread_Control *the_thread, int signo, siginfo_t *info ) { POSIX_API_Control *api; sigset_t mask; siginfo_t *the_info = NULL; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; mask = signo_to_mask( signo ); /* * Is the thread is specifically waiting for a signal? */ if ( _States_Is_interruptible_signal( the_thread->current_state ) ) { if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) { the_thread->Wait.return_code = EINTR; the_info = (siginfo_t *) the_thread->Wait.return_argument; if ( !info ) { the_info->si_signo = signo; the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; } else { *the_info = *info; } _Thread_queue_Extract_with_proxy( the_thread ); return TRUE; } /* * This should only be reached via pthread_kill(). */ return FALSE; } if ( ~api->signals_blocked & mask ) { the_thread->do_post_task_switch_extension = TRUE; if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { the_thread->Wait.return_code = EINTR; if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) _Thread_queue_Extract_with_proxy( the_thread ); else if ( _States_Is_delaying(the_thread->current_state)){ if ( _Watchdog_Is_active( &the_thread->Timer ) ) (void) _Watchdog_Remove( &the_thread->Timer ); _Thread_Unblock( the_thread ); } } } return FALSE; }