summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/signalsend.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-02-16 12:58:36 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-02-20 15:21:34 +0100
commita7e180b95dcc3c2f0bab82ec8eaa211cb0a4956a (patch)
tree762a9f2bece889f6683fcb9f65613168cf1ca298 /cpukit/rtems/src/signalsend.c
parentrtems: Add _Modes_Apply_timeslice_to_thread() (diff)
downloadrtems-a7e180b95dcc3c2f0bab82ec8eaa211cb0a4956a.tar.bz2
rtems: Avoid potential recursion in ASR handling
Do the mode changes necessary for the ASR processing directly under protection of the thread state lock to avoid the recursive calls to thread dispatching done in rtems_task_mode(). Close #4244.
Diffstat (limited to '')
-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(