summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/signalsend.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/rtems/src/signalsend.c')
-rw-r--r--cpukit/rtems/src/signalsend.c98
1 files changed, 91 insertions, 7 deletions
diff --git a/cpukit/rtems/src/signalsend.c b/cpukit/rtems/src/signalsend.c
index 606ddfcb53..8c4ce10788 100644
--- a/cpukit/rtems/src/signalsend.c
+++ b/cpukit/rtems/src/signalsend.c
@@ -21,7 +21,9 @@
#endif
#include <rtems/rtems/signalimpl.h>
+#include <rtems/rtems/modesimpl.h>
#include <rtems/rtems/tasksdata.h>
+#include <rtems/score/schedulerimpl.h>
#include <rtems/score/threaddispatch.h>
#include <rtems/score/threadimpl.h>
@@ -33,13 +35,29 @@ static void _Signal_Action_handler(
ISR_lock_Context *lock_context
)
{
- RTEMS_API_Control *api;
- ASR_Information *asr;
- rtems_signal_set signal_set;
- rtems_mode prev_mode;
+ RTEMS_API_Control *api;
+ ASR_Information *asr;
+ rtems_signal_set signal_set;
+ bool normal_is_preemptible;
+ uint32_t normal_cpu_time_budget;
+ Thread_CPU_budget_algorithms normal_budget_algorithm;
+ bool normal_asr_is_enabled;
+ 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;
@@ -48,16 +66,82 @@ static void _Signal_Action_handler(
_Assert( signal_set != 0 );
asr->signals_pending = 0;
- _Thread_State_release( executing, lock_context );
+ /* Save normal mode */
+
+ normal_is_preemptible = executing->is_preemptible;
+ normal_asr_is_enabled = asr->is_enabled;
+ normal_cpu_time_budget = executing->cpu_time_budget;
+ normal_budget_algorithm = executing->budget_algorithm;
+
+ /* 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 );
+ }
- rtems_task_mode( asr->mode_set, RTEMS_ALL_MODE_MASKS, &prev_mode );
+ 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 );
- rtems_task_mode( prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode );
+ /* Restore normal mode */
+
+ _ISR_Set_level( normal_isr_level );
_Thread_State_acquire( executing, lock_context );
+
+ executing->cpu_time_budget = normal_cpu_time_budget ;
+ executing->budget_algorithm = normal_budget_algorithm ;
+ 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 = normal_asr_is_enabled;
+
+ if (
+ normal_asr_is_enabled &&
+ !after_call_asr_is_enabled &&
+ asr->signals_pending != 0
+ ) {
+ _Thread_Append_post_switch_action( executing, action );
+ }
}
rtems_status_code rtems_signal_send(