/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSImplClassicSignal * * @brief This source file contains the implementation of * rtems_signal_send(). */ /* * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include static void _Signal_Action_handler( Thread_Control *executing, Thread_Action *action, ISR_lock_Context *lock_context ) { RTEMS_API_Control *api; ASR_Information *asr; rtems_signal_set signal_set; bool normal_is_preemptible; Thread_CPU_budget_control normal_cpu_budget; uint32_t normal_isr_level; uint32_t before_call_isr_level; bool after_call_is_preemptible; bool after_call_asr_is_enabled; (void) action; /* * For the variable names the following notation is used. The prefix * "normal" specifies the mode associated with the normal task execution. * The prefix "before_call" specifies the mode set up right before the ASR * handler is called. The prefix "after_call" specifies the mode after the * ASR handler call returned. This mode may differ from the "before_call" * mode since an ASR handler is free to change the task mode. */ api = executing->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; /* Get and clear the pending signals */ signal_set = asr->signals_pending; _Assert( signal_set != 0 ); asr->signals_pending = 0; /* Save normal mode */ _Assert( asr->is_enabled ); normal_is_preemptible = executing->is_preemptible; normal_cpu_budget = executing->CPU_budget; /* Set mode for ASR processing */ executing->is_preemptible = _Modes_Is_preempt( asr->mode_set ); asr->is_enabled = !_Modes_Is_asr_disabled( asr->mode_set ); _Modes_Apply_timeslice_to_thread( asr->mode_set, executing ); before_call_isr_level = _Modes_Get_interrupt_level( asr->mode_set ); if ( executing->is_preemptible && !normal_is_preemptible ) { Per_CPU_Control *cpu_self; cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Scheduler_Schedule( executing ); _Thread_State_release( executing, lock_context ); _Thread_Dispatch_direct( cpu_self ); } else { _Thread_State_release( executing, lock_context ); } normal_isr_level = _ISR_Get_level(); _ISR_Set_level( before_call_isr_level ); /* Call the ASR handler in the ASR processing mode */ ( *asr->handler )( signal_set ); /* Restore normal mode */ _ISR_Set_level( normal_isr_level ); _Thread_State_acquire( executing, lock_context ); executing->CPU_budget = normal_cpu_budget; after_call_is_preemptible = executing->is_preemptible; executing->is_preemptible = normal_is_preemptible; /* * We do the best to avoid recursion in the ASR processing. A well behaved * application will disable ASR processing during ASR processing. In this * case, ASR processing is currently disabled. We do now the thread dispatch * necessary due to a re-enabled preemption mode. This helps to avoid doing * the next round of ASR processing recursively in _Thread_Dispatch_direct(). */ if ( normal_is_preemptible && !after_call_is_preemptible ) { Per_CPU_Control *cpu_self; cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Scheduler_Schedule( executing ); _Thread_State_release( executing, lock_context ); _Thread_Dispatch_direct( cpu_self ); _Thread_State_acquire( executing, lock_context ); } /* * Restore the normal ASR processing mode. If we enable ASR processing and * there are pending signals, then add us as a post-switch action. The loop * in _Thread_Run_post_switch_actions() will continue after our return and * call us again. This avoids a recursion. */ after_call_asr_is_enabled = asr->is_enabled; asr->is_enabled = true; if ( !after_call_asr_is_enabled && asr->signals_pending != 0 ) { _Thread_Append_post_switch_action( executing, action ); } } rtems_status_code rtems_signal_send( rtems_id id, rtems_signal_set signal_set ) { Thread_Control *the_thread; ISR_lock_Context lock_context; RTEMS_API_Control *api; ASR_Information *asr; if ( signal_set == 0 ) { return RTEMS_INVALID_NUMBER; } the_thread = _Thread_Get( id, &lock_context ); if ( the_thread == NULL ) { #if defined(RTEMS_MULTIPROCESSING) return _Signal_MP_Send( id, signal_set ); #else return RTEMS_INVALID_ID; #endif } api = the_thread->API_Extensions[ THREAD_API_RTEMS ]; asr = &api->Signal; _Thread_State_acquire_critical( the_thread, &lock_context ); if ( asr->handler == NULL ) { _Thread_State_release( the_thread, &lock_context ); return RTEMS_NOT_DEFINED; } /* Make the signals of the set pending */ asr->signals_pending |= signal_set; if ( asr->is_enabled ) { Per_CPU_Control *cpu_self; _Thread_Add_post_switch_action( the_thread, &api->Signal_action, _Signal_Action_handler ); cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); _Thread_State_release( the_thread, &lock_context ); _Thread_Dispatch_enable( cpu_self ); } else { _Thread_State_release( the_thread, &lock_context ); } return RTEMS_SUCCESSFUL; } #if defined(RTEMS_MULTIPROCESSING) static void _Signal_MP_Initialize( void ) { _MPCI_Register_packet_processor( MP_PACKET_SIGNAL, _Signal_MP_Process_packet ); } RTEMS_SYSINIT_ITEM( _Signal_MP_Initialize, RTEMS_SYSINIT_CLASSIC_SIGNAL_MP, RTEMS_SYSINIT_ORDER_MIDDLE ); #endif