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 { \
76109 ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
77110 } \
78111 } \
79- ( void ) xTaskResumeAll(); \
112+ sbUNLOCK( pxStreamBuffer ); \
80113 } while( 0 )
81114 #endif /* sbRECEIVE_COMPLETED */
82115
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 { \
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
145178 */
146179 #ifndef sbSEND_COMPLETED
147180 #define sbSEND_COMPLETED ( pxStreamBuffer ) \
148- vTaskSuspendAll(); \
181+ sbLOCK( pxStreamBuffer ); \
149182 { \
150183 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
151184 { \
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
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 { \
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