[PATCH v2 4/4] rtems: Avoid potential recursion in ASR handling
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri Feb 19 09:40:38 UTC 2021
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().
Update #4244.
---
cpukit/rtems/src/signalsend.c | 98 ++++++++++++++++++++++++++++++++---
1 file changed, 91 insertions(+), 7 deletions(-)
diff --git a/cpukit/rtems/src/signalsend.c b/cpukit/rtems/src/signalsend.c
index 606ddfcb53..f6489b41b3 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 asr_isr_level;
+ bool previous_is_preemptible;
+ bool previous_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 "asr" specifies the mode set up before the ASR handler is
+ * called. The prefix "previous" specifies the mode right before it is
+ * restored to "normal". This mode may differ from the "asr" 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 );
+ asr_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( asr_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 ;
+ previous_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 && !previous_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.
+ */
+
+ previous_asr_is_enabled = asr->is_enabled;
+ asr->is_enabled = normal_asr_is_enabled;
+
+ if (
+ normal_asr_is_enabled &&
+ !previous_asr_is_enabled &&
+ asr->signals_pending != 0
+ ) {
+ _Thread_Append_post_switch_action( executing, action );
+ }
}
rtems_status_code rtems_signal_send(
--
2.26.2
More information about the devel
mailing list