58
58
#error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c
59
59
#endif
60
60
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 ) portENTER_CRITICAL_DATA_GROUP( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xTaskSpinlock ), &( pxStreamBuffer->xISRSpinlock ) )
67
+ #define sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer ) portENTER_CRITICAL_DATA_GROUP_FROM_ISR( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xISRSpinlock ) )
68
+ #define sbEXIT_CRITICAL ( pxEventBits ) portEXIT_CRITICAL_DATA_GROUP( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xTaskSpinlock ), &( pxStreamBuffer->xISRSpinlock ) )
69
+ #define sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxEventBits ) portEXIT_CRITICAL_DATA_GROUP_FROM_ISR( uxSavedInterruptStatus, ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xISRSpinlock ) )
70
+ #else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
71
+ #define sbENTER_CRITICAL ( pxEventBits ) do { ( void ) pxStreamBuffer; taskENTER_CRITICAL(); } while( 0 )
72
+ #define sbENTER_CRITICAL_FROM_ISR ( pxEventBits ) do { ( void ) pxStreamBuffer; taskENTER_CRITICAL_FROM_ISR(); } while( 0 )
73
+ #define sbEXIT_CRITICAL ( pxEventBits ) do { ( void ) pxStreamBuffer; taskEXIT_CRITICAL(); } while( 0 )
74
+ #define sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer ) do { ( void ) pxStreamBuffer; taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); } while( 0 )
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 ) prvLockStreamBufferForTasks( pxStreamBuffer )
88
+ #define sbUNLOCK ( pxStreamBuffer ) prvUnlockStreamBufferForTasks( pxStreamBuffer )
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
+
61
94
/* If the user has not provided application specific Rx notification macros,
62
95
* or #defined the notification macros away, then provide default implementations
63
96
* that uses task notifications. */
64
97
#ifndef sbRECEIVE_COMPLETED
65
98
#define sbRECEIVE_COMPLETED ( pxStreamBuffer ) \
66
99
do \
67
100
{ \
68
- vTaskSuspendAll(); \
101
+ sbLOCK( pxStreamBuffer ); \
69
102
{ \
70
103
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
71
104
{ \
76
109
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
77
110
} \
78
111
} \
79
- ( void ) xTaskResumeAll(); \
112
+ ( void ) sbUNLOCK( pxStreamBuffer ); \
80
113
} while( 0 )
81
114
#endif /* sbRECEIVE_COMPLETED */
82
115
105
138
do { \
106
139
UBaseType_t uxSavedInterruptStatus; \
107
140
\
108
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
141
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer ); \
109
142
{ \
110
143
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
111
144
{ \
117
150
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
118
151
} \
119
152
} \
120
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus ); \
153
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus, pxStreamBuffer ); \
121
154
} while( 0 )
122
155
#endif /* sbRECEIVE_COMPLETED_FROM_ISR */
123
156
145
178
*/
146
179
#ifndef sbSEND_COMPLETED
147
180
#define sbSEND_COMPLETED ( pxStreamBuffer ) \
148
- vTaskSuspendAll(); \
181
+ sbLOCK( pxStreamBuffer ); \
149
182
{ \
150
183
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
151
184
{ \
156
189
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
157
190
} \
158
191
} \
159
- ( void ) xTaskResumeAll( )
192
+ ( void ) sbUNLOCK( pxStreamBuffer )
160
193
#endif /* sbSEND_COMPLETED */
161
194
162
195
/* If user has provided a per-instance send completed callback, then
184
217
do { \
185
218
UBaseType_t uxSavedInterruptStatus; \
186
219
\
187
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
220
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer ); \
188
221
{ \
189
222
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
190
223
{ \
196
229
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
197
230
} \
198
231
} \
199
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus ); \
232
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus, pxStreamBuffer ); \
200
233
} while( 0 )
201
234
#endif /* sbSEND_COMPLETE_FROM_ISR */
202
235
@@ -249,8 +282,30 @@ typedef struct StreamBufferDef_t
249
282
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */
250
283
#endif
251
284
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 ) ) */
252
289
} StreamBuffer_t ;
253
290
291
+ /*
292
+ * Locks a stream buffer for tasks. Prevents other tasks from accessing the stream buffer
293
+ * but allows ISRs to pend access to the stream buffer. Caller cannot be preempted
294
+ * by other tasks after locking the stream buffer, thus allowing the caller to
295
+ * execute non-deterministic operations.
296
+ */
297
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
298
+ static void prvLockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION ;
299
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
300
+
301
+ /*
302
+ * Unlocks a stream buffer for tasks. Handles all pended access from ISRs, then reenables preemption
303
+ * for the caller.
304
+ */
305
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
306
+ static void prvUnlockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION ;
307
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
308
+
254
309
/*
255
310
* The number of bytes available to be read from the buffer.
256
311
*/
@@ -327,6 +382,42 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
327
382
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION ;
328
383
329
384
/*-----------------------------------------------------------*/
385
+
386
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
387
+ static void prvLockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer )
388
+ {
389
+ /* Disable preemption so that the current task cannot be preempted by another task */
390
+ vTaskPreemptionDisable ( NULL );
391
+
392
+ /* Lock the stream buffer data group so that we can suspend the stream buffer atomically */
393
+ sbENTER_CRITICAL ( pxStreamBuffer );
394
+
395
+ /* Keep holding xTaskSpinlock after unlocking the data group to prevent tasks
396
+ * on other cores from accessing the stream buffer while it is suspended. */
397
+ portGET_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
398
+
399
+ sbEXIT_CRITICAL ( pxStreamBuffer );
400
+ }
401
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
402
+ /*-----------------------------------------------------------*/
403
+
404
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
405
+ static void prvUnlockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer )
406
+ {
407
+ /* Lock the stream buffer data group so that we can handle any pended accesses atomically */
408
+ sbENTER_CRITICAL ( pxStreamBuffer );
409
+
410
+ /* Release the previously held task spinlock */
411
+ portRELEASE_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
412
+
413
+ sbEXIT_CRITICAL ( pxStreamBuffer );
414
+
415
+ /* Re-enable preemption */
416
+ vTaskPreemptionEnable ( NULL );
417
+ }
418
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
419
+ /*-----------------------------------------------------------*/
420
+
330
421
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
331
422
StreamBufferHandle_t xStreamBufferGenericCreate ( size_t xBufferSizeBytes ,
332
423
size_t xTriggerLevelBytes ,
@@ -405,6 +496,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
405
496
pxSendCompletedCallback ,
406
497
pxReceiveCompletedCallback );
407
498
499
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
500
+ {
501
+ portINIT_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xTaskSpinlock ) );
502
+ portINIT_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xISRSpinlock ) );
503
+ }
504
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
505
+
408
506
traceSTREAM_BUFFER_CREATE ( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xStreamBufferType );
409
507
}
410
508
else
@@ -499,6 +597,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
499
597
* again. */
500
598
pxStreamBuffer -> ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED ;
501
599
600
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
601
+ {
602
+ portINIT_SPINLOCK ( & ( pxStreamBuffer -> xTaskSpinlock ) );
603
+ portINIT_SPINLOCK ( & ( pxStreamBuffer -> xISRSpinlock ) );
604
+ }
605
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
606
+
502
607
traceSTREAM_BUFFER_CREATE ( pxStreamBuffer , xStreamBufferType );
503
608
504
609
/* MISRA Ref 11.3.1 [Misaligned access] */
@@ -614,7 +719,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
614
719
#endif
615
720
616
721
/* Can only reset a message buffer if there are no tasks blocked on it. */
617
- taskENTER_CRITICAL ( );
722
+ sbENTER_CRITICAL ( pxStreamBuffer );
618
723
{
619
724
if ( ( pxStreamBuffer -> xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer -> xTaskWaitingToSend == NULL ) )
620
725
{
@@ -644,7 +749,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
644
749
xReturn = pdPASS ;
645
750
}
646
751
}
647
- taskEXIT_CRITICAL ( );
752
+ sbEXIT_CRITICAL ( pxStreamBuffer );
648
753
649
754
traceRETURN_xStreamBufferReset ( xReturn );
650
755
@@ -872,7 +977,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
872
977
{
873
978
/* Wait until the required number of bytes are free in the message
874
979
* buffer. */
875
- taskENTER_CRITICAL ( );
980
+ sbENTER_CRITICAL ( pxStreamBuffer );
876
981
{
877
982
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer );
878
983
@@ -887,11 +992,11 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
887
992
}
888
993
else
889
994
{
890
- taskEXIT_CRITICAL ( );
995
+ sbEXIT_CRITICAL ( pxStreamBuffer );
891
996
break ;
892
997
}
893
998
}
894
- taskEXIT_CRITICAL ( );
999
+ sbEXIT_CRITICAL ( pxStreamBuffer );
895
1000
896
1001
traceBLOCKING_ON_STREAM_BUFFER_SEND ( xStreamBuffer );
897
1002
( void ) xTaskNotifyWaitIndexed ( pxStreamBuffer -> uxNotificationIndex , ( uint32_t ) 0 , ( uint32_t ) 0 , NULL , xTicksToWait );
@@ -1087,7 +1192,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1087
1192
{
1088
1193
/* Checking if there is data and clearing the notification state must be
1089
1194
* performed atomically. */
1090
- taskENTER_CRITICAL ( );
1195
+ sbENTER_CRITICAL ( pxStreamBuffer );
1091
1196
{
1092
1197
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer );
1093
1198
@@ -1112,7 +1217,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1112
1217
mtCOVERAGE_TEST_MARKER ();
1113
1218
}
1114
1219
}
1115
- taskEXIT_CRITICAL ( );
1220
+ sbEXIT_CRITICAL ( pxStreamBuffer );
1116
1221
1117
1222
if ( xBytesAvailable <= xBytesToStoreMessageLength )
1118
1223
{
@@ -1409,7 +1514,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1409
1514
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1410
1515
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1411
1516
/* coverity[misra_c_2012_directive_4_7_violation] */
1412
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1517
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1413
1518
{
1414
1519
if ( ( pxStreamBuffer )-> xTaskWaitingToReceive != NULL )
1415
1520
{
@@ -1426,7 +1531,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1426
1531
xReturn = pdFALSE ;
1427
1532
}
1428
1533
}
1429
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1534
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1430
1535
1431
1536
traceRETURN_xStreamBufferSendCompletedFromISR ( xReturn );
1432
1537
@@ -1448,7 +1553,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1448
1553
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1449
1554
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1450
1555
/* coverity[misra_c_2012_directive_4_7_violation] */
1451
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1556
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1452
1557
{
1453
1558
if ( ( pxStreamBuffer )-> xTaskWaitingToSend != NULL )
1454
1559
{
@@ -1465,7 +1570,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1465
1570
xReturn = pdFALSE ;
1466
1571
}
1467
1572
}
1468
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1573
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1469
1574
1470
1575
traceRETURN_xStreamBufferReceiveCompletedFromISR ( xReturn );
1471
1576
0 commit comments