Skip to content

Commit 7d3c250

Browse files
change(freertos/smp): Update stream_buffer.c locking
Updated stream_buffer.c to use granular locking - Added xTaskSpinlock and xISRSpinlock - Replaced critical section macros with data group critical section macros such as taskENTER/EXIT_CRITICAL/_FROM_ISR() with sbENTER/EXIT_CRITICAL_FROM_ISR(). - Added vStreambuffersEnterCritical/FromISR() and vStreambuffersExitCritical/FromISR() to map to the data group critical section macros. - Added prvLockStreamBufferForTasks() and prvUnlockStreamBufferForTasks() to suspend the stream buffer when executing non-deterministic code. Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
1 parent e5e51d4 commit 7d3c250

1 file changed

Lines changed: 93 additions & 21 deletions

File tree

stream_buffer.c

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,47 @@
5858
#error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c
5959
#endif
6060

61+
62+
/*
63+
* Macros to mark the start and end of a critical code region.
64+
*/
65+
#if ( portUSING_GRANULAR_LOCKS == 1 )
66+
#define sbENTER_CRITICAL( pxStreamBuffer ) taskDATA_GROUP_ENTER_CRITICAL( &( ( pxStreamBuffer )->xTaskSpinlock ), &( ( pxStreamBuffer )->xISRSpinlock ) )
67+
#define sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, puxSavedInterruptStatus ) taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR( &( ( pxStreamBuffer )->xISRSpinlock ), puxSavedInterruptStatus )
68+
#define sbEXIT_CRITICAL( pxStreamBuffer ) taskDATA_GROUP_EXIT_CRITICAL( &( ( pxStreamBuffer )->xTaskSpinlock ), &( ( pxStreamBuffer )->xISRSpinlock ) )
69+
#define sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer ) taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, &( ( pxStreamBuffer )->xISRSpinlock ) )
70+
#else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
71+
#define sbENTER_CRITICAL( pxStreamBuffer ) taskENTER_CRITICAL()
72+
#define sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, puxSavedInterruptStatus ) do { *( puxSavedInterruptStatus ) = taskENTER_CRITICAL_FROM_ISR(); } while( 0 )
73+
#define sbEXIT_CRITICAL( pxStreamBuffer ) taskEXIT_CRITICAL()
74+
#define sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer ) taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus )
75+
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
76+
77+
/*
78+
* Macro used to lock and unlock a stream buffer. When a task locks a stream
79+
* buffer, the task will have thread safe non-deterministic access to the stream
80+
* buffer.
81+
* - Concurrent access from other tasks will be blocked by the xTaskSpinlock
82+
* - Concurrent access from ISRs will be pended
83+
*
84+
* When the task unlocks the stream buffer, all pended access attempts are handled.
85+
*/
86+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
87+
#define sbLOCK( pxStreamBuffer ) taskDATA_GROUP_LOCK( &( ( pxStreamBuffer )->xTaskSpinlock ) )
88+
#define sbUNLOCK( pxStreamBuffer ) taskDATA_GROUP_UNLOCK( &( ( pxStreamBuffer )->xTaskSpinlock ) )
89+
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
90+
#define sbLOCK( pxStreamBuffer ) vTaskSuspendAll()
91+
#define sbUNLOCK( pxStreamBuffer ) ( void ) xTaskResumeAll()
92+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
93+
6194
/* If the user has not provided application specific Rx notification macros,
6295
* or #defined the notification macros away, then provide default implementations
6396
* that uses task notifications. */
6497
#ifndef sbRECEIVE_COMPLETED
6598
#define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
6699
do \
67100
{ \
68-
vTaskSuspendAll(); \
101+
sbLOCK( pxStreamBuffer ); \
69102
{ \
70103
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
71104
{ \
@@ -76,7 +109,7 @@
76109
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
77110
} \
78111
} \
79-
( void ) xTaskResumeAll(); \
112+
sbUNLOCK( pxStreamBuffer ); \
80113
} while( 0 )
81114
#endif /* sbRECEIVE_COMPLETED */
82115

@@ -105,7 +138,7 @@
105138
do { \
106139
UBaseType_t uxSavedInterruptStatus; \
107140
\
108-
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
141+
sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, &uxSavedInterruptStatus ); \
109142
{ \
110143
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
111144
{ \
@@ -117,7 +150,7 @@
117150
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
118151
} \
119152
} \
120-
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); \
153+
sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer ); \
121154
} while( 0 )
122155
#endif /* sbRECEIVE_COMPLETED_FROM_ISR */
123156

@@ -145,7 +178,7 @@
145178
*/
146179
#ifndef sbSEND_COMPLETED
147180
#define sbSEND_COMPLETED( pxStreamBuffer ) \
148-
vTaskSuspendAll(); \
181+
sbLOCK( pxStreamBuffer ); \
149182
{ \
150183
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
151184
{ \
@@ -156,7 +189,7 @@
156189
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
157190
} \
158191
} \
159-
( void ) xTaskResumeAll()
192+
sbUNLOCK( pxStreamBuffer )
160193
#endif /* sbSEND_COMPLETED */
161194

162195
/* If user has provided a per-instance send completed callback, then
@@ -184,7 +217,7 @@
184217
do { \
185218
UBaseType_t uxSavedInterruptStatus; \
186219
\
187-
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
220+
sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, &uxSavedInterruptStatus ); \
188221
{ \
189222
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
190223
{ \
@@ -196,7 +229,7 @@
196229
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
197230
} \
198231
} \
199-
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); \
232+
sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer ); \
200233
} while( 0 )
201234
#endif /* sbSEND_COMPLETE_FROM_ISR */
202235

@@ -249,6 +282,10 @@ typedef struct StreamBufferDef_t
249282
StreamBufferCallbackFunction_t pxReceiveCompletedCallback; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */
250283
#endif
251284
UBaseType_t uxNotificationIndex; /* The index we are using for notification, by default tskDEFAULT_INDEX_TO_NOTIFY. */
285+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
286+
portSPINLOCK_TYPE xTaskSpinlock;
287+
portSPINLOCK_TYPE xISRSpinlock;
288+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
252289
} StreamBuffer_t;
253290

254291
/*
@@ -336,6 +373,7 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
336373
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION;
337374

338375
/*-----------------------------------------------------------*/
376+
339377
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
340378
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
341379
size_t xTriggerLevelBytes,
@@ -414,6 +452,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
414452
pxSendCompletedCallback,
415453
pxReceiveCompletedCallback );
416454

455+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
456+
{
457+
portINIT_SPINLOCK( &( ( ( StreamBuffer_t * ) pvAllocatedMemory )->xTaskSpinlock ) );
458+
portINIT_SPINLOCK( &( ( ( StreamBuffer_t * ) pvAllocatedMemory )->xISRSpinlock ) );
459+
}
460+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
461+
417462
traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xStreamBufferType );
418463
}
419464
else
@@ -508,6 +553,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
508553
* again. */
509554
pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
510555

556+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
557+
{
558+
portINIT_SPINLOCK( &( pxStreamBuffer->xTaskSpinlock ) );
559+
portINIT_SPINLOCK( &( pxStreamBuffer->xISRSpinlock ) );
560+
}
561+
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
562+
511563
traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xStreamBufferType );
512564

513565
/* MISRA Ref 11.3.1 [Misaligned access] */
@@ -623,7 +675,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
623675
#endif
624676

625677
/* Can only reset a message buffer if there are no tasks blocked on it. */
626-
taskENTER_CRITICAL();
678+
sbENTER_CRITICAL( pxStreamBuffer );
627679
{
628680
if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
629681
{
@@ -653,7 +705,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
653705
xReturn = pdPASS;
654706
}
655707
}
656-
taskEXIT_CRITICAL();
708+
sbEXIT_CRITICAL( pxStreamBuffer );
657709

658710
traceRETURN_xStreamBufferReset( xReturn );
659711

@@ -881,7 +933,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
881933
{
882934
/* Wait until the required number of bytes are free in the message
883935
* buffer. */
884-
taskENTER_CRITICAL();
936+
sbENTER_CRITICAL( pxStreamBuffer );
885937
{
886938
xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
887939

@@ -896,15 +948,19 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
896948
}
897949
else
898950
{
899-
taskEXIT_CRITICAL();
951+
sbEXIT_CRITICAL( pxStreamBuffer );
900952
break;
901953
}
902954
}
903-
taskEXIT_CRITICAL();
955+
sbEXIT_CRITICAL( pxStreamBuffer );
904956

905957
traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
906958
( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
907-
pxStreamBuffer->xTaskWaitingToSend = NULL;
959+
sbENTER_CRITICAL( pxStreamBuffer );
960+
{
961+
pxStreamBuffer->xTaskWaitingToSend = NULL;
962+
}
963+
sbEXIT_CRITICAL( pxStreamBuffer );
908964
} while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
909965
}
910966
else
@@ -1099,7 +1155,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
10991155
{
11001156
/* Checking if there is data and clearing the notification state must be
11011157
* performed atomically. */
1102-
taskENTER_CRITICAL();
1158+
sbENTER_CRITICAL( pxStreamBuffer );
11031159
{
11041160
xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
11051161

@@ -1124,14 +1180,18 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
11241180
mtCOVERAGE_TEST_MARKER();
11251181
}
11261182
}
1127-
taskEXIT_CRITICAL();
1183+
sbEXIT_CRITICAL( pxStreamBuffer );
11281184

11291185
if( xBytesAvailable <= xBytesToStoreMessageLength )
11301186
{
11311187
/* Wait for data to be available. */
11321188
traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
11331189
( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
1134-
pxStreamBuffer->xTaskWaitingToReceive = NULL;
1190+
sbENTER_CRITICAL( pxStreamBuffer );
1191+
{
1192+
pxStreamBuffer->xTaskWaitingToReceive = NULL;
1193+
}
1194+
sbEXIT_CRITICAL( pxStreamBuffer );
11351195

11361196
/* Recheck the data available after blocking. */
11371197
xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
@@ -1421,7 +1481,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
14211481
/* MISRA Ref 4.7.1 [Return value shall be checked] */
14221482
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
14231483
/* coverity[misra_c_2012_directive_4_7_violation] */
1424-
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1484+
sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, &uxSavedInterruptStatus );
14251485
{
14261486
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
14271487
{
@@ -1438,7 +1498,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
14381498
xReturn = pdFALSE;
14391499
}
14401500
}
1441-
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1501+
sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer );
14421502

14431503
traceRETURN_xStreamBufferSendCompletedFromISR( xReturn );
14441504

@@ -1460,7 +1520,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
14601520
/* MISRA Ref 4.7.1 [Return value shall be checked] */
14611521
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
14621522
/* coverity[misra_c_2012_directive_4_7_violation] */
1463-
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1523+
sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer, &uxSavedInterruptStatus );
14641524
{
14651525
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
14661526
{
@@ -1477,7 +1537,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
14771537
xReturn = pdFALSE;
14781538
}
14791539
}
1480-
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1540+
sbEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer );
14811541

14821542
traceRETURN_xStreamBufferReceiveCompletedFromISR( xReturn );
14831543

@@ -1633,6 +1693,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
16331693
StreamBufferCallbackFunction_t pxSendCompletedCallback,
16341694
StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
16351695
{
1696+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
1697+
/* Preserve the embedded spinlocks across the memset; the reset
1698+
* path runs with xTaskSpinlock held by the caller. */
1699+
portSPINLOCK_TYPE xTaskSpinlock = pxStreamBuffer->xTaskSpinlock;
1700+
portSPINLOCK_TYPE xISRSpinlock = pxStreamBuffer->xISRSpinlock;
1701+
#endif
1702+
16361703
/* Assert here is deliberately writing to the entire buffer to ensure it can
16371704
* be written to without generating exceptions, and is setting the buffer to a
16381705
* known value to assist in development/debugging. */
@@ -1652,6 +1719,11 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
16521719
pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
16531720
pxStreamBuffer->ucFlags = ucFlags;
16541721
pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY;
1722+
1723+
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
1724+
pxStreamBuffer->xTaskSpinlock = xTaskSpinlock;
1725+
pxStreamBuffer->xISRSpinlock = xISRSpinlock;
1726+
#endif
16551727
#if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
16561728
{
16571729
pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;

0 commit comments

Comments
 (0)