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 ) taskDATA_GROUP_ENTER_CRITICAL( pxStreamBuffer )
67
+ #define sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer ) taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR( pxStreamBuffer )
68
+ #define sbEXIT_CRITICAL ( pxStreamBuffer ) taskDATA_GROUP_EXIT_CRITICAL( pxStreamBuffer )
69
+ #define sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer ) taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxStreamBuffer )
70
+ #else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
71
+ #define sbENTER_CRITICAL ( pxEventBits ) taskENTER_CRITICAL();
72
+ #define sbENTER_CRITICAL_FROM_ISR ( pxEventBits ) taskENTER_CRITICAL_FROM_ISR();
73
+ #define sbEXIT_CRITICAL ( pxEventBits ) 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 ) 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,32 @@ 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
+ /* Keep holding xTaskSpinlock after unlocking the data group to prevent tasks
393
+ * on other cores from accessing the stream buffer while it is suspended. */
394
+ portGET_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
395
+ }
396
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
397
+ /*-----------------------------------------------------------*/
398
+
399
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
400
+ static void prvUnlockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer )
401
+ {
402
+ /* Release the previously held task spinlock */
403
+ portRELEASE_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
404
+
405
+ /* Re-enable preemption */
406
+ vTaskPreemptionEnable ( NULL );
407
+ }
408
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
409
+ /*-----------------------------------------------------------*/
410
+
330
411
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
331
412
StreamBufferHandle_t xStreamBufferGenericCreate ( size_t xBufferSizeBytes ,
332
413
size_t xTriggerLevelBytes ,
@@ -405,6 +486,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
405
486
pxSendCompletedCallback ,
406
487
pxReceiveCompletedCallback );
407
488
489
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
490
+ {
491
+ portINIT_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xTaskSpinlock ) );
492
+ portINIT_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xISRSpinlock ) );
493
+ }
494
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
495
+
408
496
traceSTREAM_BUFFER_CREATE ( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xStreamBufferType );
409
497
}
410
498
else
@@ -499,6 +587,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
499
587
* again. */
500
588
pxStreamBuffer -> ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED ;
501
589
590
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
591
+ {
592
+ portINIT_SPINLOCK ( & ( pxStreamBuffer -> xTaskSpinlock ) );
593
+ portINIT_SPINLOCK ( & ( pxStreamBuffer -> xISRSpinlock ) );
594
+ }
595
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
596
+
502
597
traceSTREAM_BUFFER_CREATE ( pxStreamBuffer , xStreamBufferType );
503
598
504
599
/* MISRA Ref 11.3.1 [Misaligned access] */
@@ -614,7 +709,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
614
709
#endif
615
710
616
711
/* Can only reset a message buffer if there are no tasks blocked on it. */
617
- taskENTER_CRITICAL ( );
712
+ sbENTER_CRITICAL ( pxStreamBuffer );
618
713
{
619
714
if ( ( pxStreamBuffer -> xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer -> xTaskWaitingToSend == NULL ) )
620
715
{
@@ -644,7 +739,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
644
739
xReturn = pdPASS ;
645
740
}
646
741
}
647
- taskEXIT_CRITICAL ( );
742
+ sbEXIT_CRITICAL ( pxStreamBuffer );
648
743
649
744
traceRETURN_xStreamBufferReset ( xReturn );
650
745
@@ -872,7 +967,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
872
967
{
873
968
/* Wait until the required number of bytes are free in the message
874
969
* buffer. */
875
- taskENTER_CRITICAL ( );
970
+ sbENTER_CRITICAL ( pxStreamBuffer );
876
971
{
877
972
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer );
878
973
@@ -887,11 +982,11 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
887
982
}
888
983
else
889
984
{
890
- taskEXIT_CRITICAL ( );
985
+ sbEXIT_CRITICAL ( pxStreamBuffer );
891
986
break ;
892
987
}
893
988
}
894
- taskEXIT_CRITICAL ( );
989
+ sbEXIT_CRITICAL ( pxStreamBuffer );
895
990
896
991
traceBLOCKING_ON_STREAM_BUFFER_SEND ( xStreamBuffer );
897
992
( void ) xTaskNotifyWaitIndexed ( pxStreamBuffer -> uxNotificationIndex , ( uint32_t ) 0 , ( uint32_t ) 0 , NULL , xTicksToWait );
@@ -1087,7 +1182,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1087
1182
{
1088
1183
/* Checking if there is data and clearing the notification state must be
1089
1184
* performed atomically. */
1090
- taskENTER_CRITICAL ( );
1185
+ sbENTER_CRITICAL ( pxStreamBuffer );
1091
1186
{
1092
1187
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer );
1093
1188
@@ -1112,7 +1207,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1112
1207
mtCOVERAGE_TEST_MARKER ();
1113
1208
}
1114
1209
}
1115
- taskEXIT_CRITICAL ( );
1210
+ sbEXIT_CRITICAL ( pxStreamBuffer );
1116
1211
1117
1212
if ( xBytesAvailable <= xBytesToStoreMessageLength )
1118
1213
{
@@ -1409,7 +1504,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1409
1504
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1410
1505
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1411
1506
/* coverity[misra_c_2012_directive_4_7_violation] */
1412
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1507
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1413
1508
{
1414
1509
if ( ( pxStreamBuffer )-> xTaskWaitingToReceive != NULL )
1415
1510
{
@@ -1426,7 +1521,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1426
1521
xReturn = pdFALSE ;
1427
1522
}
1428
1523
}
1429
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1524
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1430
1525
1431
1526
traceRETURN_xStreamBufferSendCompletedFromISR ( xReturn );
1432
1527
@@ -1448,7 +1543,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1448
1543
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1449
1544
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1450
1545
/* coverity[misra_c_2012_directive_4_7_violation] */
1451
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1546
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1452
1547
{
1453
1548
if ( ( pxStreamBuffer )-> xTaskWaitingToSend != NULL )
1454
1549
{
@@ -1465,7 +1560,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1465
1560
xReturn = pdFALSE ;
1466
1561
}
1467
1562
}
1468
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1563
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1469
1564
1470
1565
traceRETURN_xStreamBufferReceiveCompletedFromISR ( xReturn );
1471
1566
0 commit comments