Hello Catalin,

On 29/03/2019 10:56, Catalin Demergian wrote:
Hi,
We had some time ago (sept/oct 2018) a long discussion where I was suspecting a scheduler issue (subject "rtems_message_queue_receive/rtems_event_receive issues")

We got to the point where I realized that _Chain_Append_unprotected might fail to add an element in the queue, with the effect of having a task in a funny state where state=READY, but the task will not be in the ready chain, so the task will never get CPU time anymore since a task
needs to be blocked in order to be unblocked when new data arrives.

We were using USB then, but this issue re-became hot because we just got the same issue
over serial :)
I believe there is a possible chain of events that can make _Chain_Append_unprotected to fail,
explanations follow.

/*

** @note It does NOT disable interrupts to ensure the atomicity of the*

**       append operation.*

*/

RTEMS_INLINE_ROUTINE void _Chain_Append_unprotected(

  Chain_Control *the_chain,

  Chain_Node    *the_node

)

{

  Chain_Node *tail = _Chain_Tail( the_chain );

  Chain_Node *old_last = tail->previous;

  the_node->next = tail;

*  tail->previous = the_node;*

*  old_last->next = the_node;*

  the_node->previous = old_last;

}

The

*  tail->previous = the_node;*

*  old_last->next = the_node;*

lines are the ones that actually add the element

to the ready chain.

If a thread executes those lines, but just before executing

the_node->previous = old_last;

another thread comes to add another node in this chain, it will set another node in

tail->previous and old_last->next, and as a result, when the interrupted

thread will continue to execute the last line, it will be for nothing, because the initial node will not be added to the ready chain.


If this chain of events occur (*and after a while they will*), we get starvation for that task.

I'm reproducing this issue in a long duration test, the duration before this happens varies from run to run, but it always happens.


*What I'm proposing is the following*: call _Chain_Append instead of _Chain_Append_unprotected in schedulerpriorityimpl.h, _Scheduler_priority_Ready_queue_enqueue function.


void _Chain_Append(

  Chain_Control *the_chain,

  Chain_Node    *node

)

{

  ISR_Level level;

  _ISR_Disable( level );

    _Chain_Append_unprotected( the_chain, node );

_ISR_Enable( level );

}


This way the add-element-to-chain operation becomes atomic.

I was able to run a long duration test (8 hrs) in my setup with this fix successfully.


What do you think ?


The _Scheduler_priority_Ready_queue_enqueue() should only be called with interrupts disabled. So, disabling interrupts again should have no effect. Could you please try out the attached patch and build the BSP with --enable-rtems-debug?

--
Sebastian Huber, embedded brains GmbH

Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone   : +49 89 189 47 41-16
Fax     : +49 89 189 47 41-09
E-Mail  : sebastian.hu...@embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.

>From cc9ddd9ddcba5b925704f2ea66e312074b19dd2c Mon Sep 17 00:00:00 2001
From: Sebastian Huber <sebastian.hu...@embedded-brains.de>
Date: Fri, 29 Mar 2019 11:02:40 +0100
Subject: [PATCH] score: Add asserts

---
 cpukit/include/rtems/score/schedulerpriorityimpl.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/cpukit/include/rtems/score/schedulerpriorityimpl.h b/cpukit/include/rtems/score/schedulerpriorityimpl.h
index 354065fac4..05cc2eaf12 100644
--- a/cpukit/include/rtems/score/schedulerpriorityimpl.h
+++ b/cpukit/include/rtems/score/schedulerpriorityimpl.h
@@ -89,6 +89,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_priority_Ready_queue_enqueue(
 {
   Chain_Control *ready_chain = ready_queue->ready_chain;
 
+  _Assert(_ISR_Get_level() != 0);
   _Chain_Append_unprotected( ready_chain, node );
   _Priority_bit_map_Add( bit_map, &ready_queue->Priority_map );
 }
@@ -110,6 +111,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_priority_Ready_queue_enqueue_first(
 {
   Chain_Control *ready_chain = ready_queue->ready_chain;
 
+  _Assert(_ISR_Get_level() != 0);
   _Chain_Prepend_unprotected( ready_chain, node );
   _Priority_bit_map_Add( bit_map, &ready_queue->Priority_map );
 }
@@ -129,6 +131,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_priority_Ready_queue_extract(
 {
   Chain_Control *ready_chain = ready_queue->ready_chain;
 
+  _Assert(_ISR_Get_level() != 0);
   if ( _Chain_Has_only_one_node( ready_chain ) ) {
     _Chain_Initialize_empty( ready_chain );
     _Chain_Initialize_node( node );
-- 
2.16.4

_______________________________________________
users mailing list
users@rtems.org
http://lists.rtems.org/mailman/listinfo/users

Reply via email to