xelus wrote on Saturday, February 09, 2019:
Thanks for your help.
I presume you mean FreeRTOS V9.0.0. Why use an old version?
Yes, I’m using 9.0.0 version, and I’m using this old version because this is old code, which is only bugfixed. I’m not sure what happens, when I will change to the newest Free RTOS version…
Is that the latest compiler version?
Yes, I have used in test the newest version
…but where is listGET_OWNER_OF_HEAD_ENTRY() being called in that
function before the while loop? I presume you mean it is being called
INSIDE the while loop (line 2043).
This macro is called inside loop, but in assembler code value is evaluated into microcontroller register before loop begins. Without any volatiles it looks like:
2041 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
(1) 019e9c: 9382 3980 TST.W &xPendingReadyList
(2) 019ea0: 2486 JEQ (0x9fae)
(3) 019ea2: 0028 398A MOVA &0x0398a,R8
2043 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
(4) 019ea6: 0839 000C MOVA 0x000c(R8),R9
(5) (.....)
2052 xYieldPending = pdTRUE;
(6) 019f74: 4392 3AEA MOV.W #1,&xYieldPending
2041 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
(7) 019f78: 9382 3980 TST.W &xPendingReadyList
(8) 019f7c: 2394 JNE (0x9ea6)
2060 if( pxTCB != NULL )
(1) - check if list isn’t empty
(2) - exit when list is empty
(3) - put into R8 register ( pxList )->xListEnd ))->pxNext (pointer value)
(4) - dereferencing ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner
(7) - check if list isn’t empty (and it is not)
(8) - jump to line (4) if there is another task left in the list. In the meantime ( pxList )->xListEnd ))->pxNext was changed, but do not recalculate R8 register value
If there is only one task, then in line (8) it out of the loop and everything work fine.
Can you please show how you updated the code to make the list volatile
as my suggestion just made the members of the list volatile.
I added to FreeRTOSConfig.h line:
#define configLIST_VOLATILE volatile
I added your test function to the code and anduring execution it enters into infinite loop - just like in my case. listGET_OWNER_OF_HEAD_ENTRY always return X1 task.
(type * volatile ptr) means the thing at the pointer address is volatile
(volatile type * ptr) means the pointer itself is volatile
Isn’t it inversly?
(type * volatile ptr) means the pointer itself is volatile
(volatile type * ptr) means the thing at the pointer address is volatile
The compiler is correctly asssuming the pointer doesn’t change (…)
pxIndex is changed directly one line up, so I think, that compiler shouldn’t assuming that it isn’t changed, even if it isn’t set as volatile
I have temporarily added a configLIST_VOLATILE macro and changed the definitions:
/*
* Definition of the only type of object that a list can contain.
*/
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
struct xLIST_ITEM volatile * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
struct xLIST_ITEM volatile * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef volatile struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM volatile * configLIST_VOLATILE pxNext;
struct xLIST_ITEM volatile * configLIST_VOLATILE pxPrevious;
};
typedef volatile struct xMINI_LIST_ITEM MiniListItem_t;
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} volatile List_t;
And now it’s work ok in both situations - during switiching task and during handling two tasks in xPendingReadyList list. Assembler look like:
2041 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
(1) 019e70: 9382 3980 TST.W &xPendingReadyList
(2) 019e74: 2488 JEQ (0x9f86)
2043 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
(3) 019e76: 002F 398A MOVA &0x0398a,R15
(4) 019e7a: 0F39 000C MOVA 0x000c(R15),R9
(5) (...)
2052 xYieldPending = pdTRUE;
019f4c: 4392 3AEA MOV.W #1,&xYieldPending
(6) 2041 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
$C$L38:
(7) 019f50: 9382 3980 TST.W &xPendingReadyList
(8) 019f54: 2390 JNE (0x9e76)
Now in line (8) it jumps to line (3), where pointer value is evaluated ( pxList )->xListEnd ))->pxNext