58
58
#error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c
59
59
#endif
60
60
61
+
62
+ /*
63
+ * Macro to mark the start of a critical code region.
64
+ */
65
+ #if ( portUSING_GRANULAR_LOCKS == 1 )
66
+ #define sbENTER_CRITICAL ( pxStreamBuffer ) portLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xTaskSpinlock ), &( pxStreamBuffer->xISRSpinlock ) )
67
+ #define sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer ) portLOCK_DATA_GROUP_FROM_ISR( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xISRSpinlock ) )
68
+ #else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
69
+ #define sbENTER_CRITICAL ( pxEventBits ) do { ( void ) pxStreamBuffer; taskENTER_CRITICAL(); } while( 0 )
70
+ #define sbENTER_CRITICAL_FROM_ISR ( pxEventBits ) do { ( void ) pxStreamBuffer; taskENTER_CRITICAL_FROM_ISR(); } while( 0 )
71
+ #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
72
+
73
+ /*
74
+ * Macro to mark the end of a critical code region.
75
+ */
76
+ #if ( portUSING_GRANULAR_LOCKS == 1 )
77
+ #define sbEXIT_CRITICAL ( pxEventBits ) portUNLOCK_DATA_GROUP( ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xTaskSpinlock ), &( pxStreamBuffer->xISRSpinlock ) )
78
+ #define sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxEventBits ) portUNLOCK_DATA_GROUP_FROM_ISR( uxSavedInterruptStatus, ( portSPINLOCK_TYPE * ) &( pxStreamBuffer->xISRSpinlock ) )
79
+ #else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
80
+ #define egEXIT_CRITICAL ( pxEventBits ) do { ( void ) pxEventBits; taskEXIT_CRITICAL(); } while( 0 )
81
+ #define egEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer ) do { ( void ) pxStreamBuffer; taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); } while( 0 )
82
+ #endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
83
+
84
+ /*
85
+ * Macro used to lock and unlock a stream buffer. When a task locks a stream
86
+ * buffer, the task will have thread safe non-deterministic access to the stream
87
+ * buffer.
88
+ * - Concurrent access from other tasks will be blocked by the xTaskSpinlock
89
+ * - Concurrent access from ISRs will be pended
90
+ *
91
+ * When the task unlocks the stream buffer, all pended access attempts are handled.
92
+ */
93
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
94
+ #define sbLOCK ( pxStreamBuffer ) prvLockStreamBufferForTasks( pxStreamBuffer )
95
+ #define sbUNLOCK ( pxStreamBuffer ) prvUnlockStreamBufferForTasks( pxStreamBuffer )
96
+ #else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
97
+ #define sbLOCK ( pxStreamBuffer ) vTaskSuspendAll()
98
+ #define sbUNLOCK ( pxStreamBuffer ) ( void ) xTaskResumeAll()
99
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
100
+
61
101
/* If the user has not provided application specific Rx notification macros,
62
102
* or #defined the notification macros away, then provide default implementations
63
103
* that uses task notifications. */
64
104
#ifndef sbRECEIVE_COMPLETED
65
105
#define sbRECEIVE_COMPLETED ( pxStreamBuffer ) \
66
106
do \
67
107
{ \
68
- vTaskSuspendAll(); \
108
+ sbLOCK( pxStreamBuffer ); \
69
109
{ \
70
110
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
71
111
{ \
76
116
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
77
117
} \
78
118
} \
79
- ( void ) xTaskResumeAll(); \
119
+ ( void ) sbUNLOCK( pxStreamBuffer ); \
80
120
} while( 0 )
81
121
#endif /* sbRECEIVE_COMPLETED */
82
122
105
145
do { \
106
146
UBaseType_t uxSavedInterruptStatus; \
107
147
\
108
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
148
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer ); \
109
149
{ \
110
150
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
111
151
{ \
117
157
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
118
158
} \
119
159
} \
120
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus ); \
160
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus, pxStreamBuffer ); \
121
161
} while( 0 )
122
162
#endif /* sbRECEIVE_COMPLETED_FROM_ISR */
123
163
145
185
*/
146
186
#ifndef sbSEND_COMPLETED
147
187
#define sbSEND_COMPLETED ( pxStreamBuffer ) \
148
- vTaskSuspendAll(); \
188
+ sbLOCK( pxStreamBuffer ); \
149
189
{ \
150
190
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
151
191
{ \
156
196
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
157
197
} \
158
198
} \
159
- ( void ) xTaskResumeAll( )
199
+ ( void ) sbUNLOCK( pxStreamBuffer )
160
200
#endif /* sbSEND_COMPLETED */
161
201
162
202
/* If user has provided a per-instance send completed callback, then
184
224
do { \
185
225
UBaseType_t uxSavedInterruptStatus; \
186
226
\
187
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
227
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR( pxStreamBuffer ); \
188
228
{ \
189
229
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
190
230
{ \
196
236
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
197
237
} \
198
238
} \
199
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus ); \
239
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus, pxStreamBuffer ); \
200
240
} while( 0 )
201
241
#endif /* sbSEND_COMPLETE_FROM_ISR */
202
242
@@ -249,8 +289,30 @@ typedef struct StreamBufferDef_t
249
289
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */
250
290
#endif
251
291
UBaseType_t uxNotificationIndex ; /* The index we are using for notification, by default tskDEFAULT_INDEX_TO_NOTIFY. */
292
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
293
+ portSPINLOCK_TYPE xTaskSpinlock ;
294
+ portSPINLOCK_TYPE xISRSpinlock ;
295
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
252
296
} StreamBuffer_t ;
253
297
298
+ /*
299
+ * Locks a stream buffer for tasks. Prevents other tasks from accessing the stream buffer
300
+ * but allows ISRs to pend access to the stream buffer. Caller cannot be preempted
301
+ * by other tasks after locking the stream buffer, thus allowing the caller to
302
+ * execute non-deterministic operations.
303
+ */
304
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
305
+ static void prvLockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION ;
306
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
307
+
308
+ /*
309
+ * Unlocks a stream buffer for tasks. Handles all pended access from ISRs, then reenables preemption
310
+ * for the caller.
311
+ */
312
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
313
+ static void prvUnlockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION ;
314
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
315
+
254
316
/*
255
317
* The number of bytes available to be read from the buffer.
256
318
*/
@@ -327,6 +389,42 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
327
389
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION ;
328
390
329
391
/*-----------------------------------------------------------*/
392
+
393
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
394
+ static void prvLockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer )
395
+ {
396
+ /* Disable preempt so that current task cannot be preempted by another task */
397
+ vTaskPreemptionDisable ( NULL );
398
+
399
+ /* Lock the stream buffer data group so that we can suspend the stream buffer atomically */
400
+ sbENTER_CRITICAL ( pxStreamBuffer );
401
+
402
+ /* Keep holding xTaskSpinlock after unlocking the data group to prevent tasks
403
+ * on other cores from accessing the stream buffer while it is suspended. */
404
+ portGET_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
405
+
406
+ sbEXIT_CRITICAL ( pxStreamBuffer );
407
+ }
408
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
409
+ /*-----------------------------------------------------------*/
410
+
411
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
412
+ static void prvUnlockStreamBufferForTasks ( StreamBuffer_t * const pxStreamBuffer )
413
+ {
414
+ /* Lock the stream buffer data group so that we can handle any pended accesses atomically */
415
+ sbENTER_CRITICAL ( pxStreamBuffer );
416
+
417
+ /* Release the previously held task spinlock */
418
+ portRELEASE_SPINLOCK ( portGET_CORE_ID (), & ( pxStreamBuffer -> xTaskSpinlock ) );
419
+
420
+ sbEXIT_CRITICAL ( pxStreamBuffer );
421
+
422
+ /* Re-enable preemption so that current task cannot be preempted by other tasks */
423
+ vTaskPreemptionEnable ( NULL );
424
+ }
425
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
426
+ /*-----------------------------------------------------------*/
427
+
330
428
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
331
429
StreamBufferHandle_t xStreamBufferGenericCreate ( size_t xBufferSizeBytes ,
332
430
size_t xTriggerLevelBytes ,
@@ -405,6 +503,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
405
503
pxSendCompletedCallback ,
406
504
pxReceiveCompletedCallback );
407
505
506
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
507
+ {
508
+ portINIT_STREAM_BUFFER_TASK_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xTaskSpinlock ) );
509
+ portINIT_STREAM_BUFFER_ISR_SPINLOCK ( & ( ( ( StreamBuffer_t * ) pvAllocatedMemory )-> xISRSpinlock ) );
510
+ }
511
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
512
+
408
513
traceSTREAM_BUFFER_CREATE ( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xStreamBufferType );
409
514
}
410
515
else
@@ -499,6 +604,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
499
604
* again. */
500
605
pxStreamBuffer -> ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED ;
501
606
607
+ #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
608
+ {
609
+ portINIT_STREAM_BUFFER_TASK_SPINLOCK ( & ( pxStreamBuffer -> xTaskSpinlock ) );
610
+ portINIT_STREAM_BUFFER_ISR_SPINLOCK ( & ( pxStreamBuffer -> xISRSpinlock ) );
611
+ }
612
+ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
613
+
502
614
traceSTREAM_BUFFER_CREATE ( pxStreamBuffer , xStreamBufferType );
503
615
504
616
/* MISRA Ref 11.3.1 [Misaligned access] */
@@ -614,7 +726,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
614
726
#endif
615
727
616
728
/* Can only reset a message buffer if there are no tasks blocked on it. */
617
- taskENTER_CRITICAL ( );
729
+ sbENTER_CRITICAL ( pxStreamBuffer );
618
730
{
619
731
if ( ( pxStreamBuffer -> xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer -> xTaskWaitingToSend == NULL ) )
620
732
{
@@ -644,7 +756,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
644
756
xReturn = pdPASS ;
645
757
}
646
758
}
647
- taskEXIT_CRITICAL ( );
759
+ sbEXIT_CRITICAL ( pxStreamBuffer );
648
760
649
761
traceRETURN_xStreamBufferReset ( xReturn );
650
762
@@ -872,7 +984,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
872
984
{
873
985
/* Wait until the required number of bytes are free in the message
874
986
* buffer. */
875
- taskENTER_CRITICAL ( );
987
+ sbENTER_CRITICAL ( pxStreamBuffer );
876
988
{
877
989
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer );
878
990
@@ -887,11 +999,11 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
887
999
}
888
1000
else
889
1001
{
890
- taskEXIT_CRITICAL ( );
1002
+ sbEXIT_CRITICAL ( pxStreamBuffer );
891
1003
break ;
892
1004
}
893
1005
}
894
- taskEXIT_CRITICAL ( );
1006
+ sbEXIT_CRITICAL ( pxStreamBuffer );
895
1007
896
1008
traceBLOCKING_ON_STREAM_BUFFER_SEND ( xStreamBuffer );
897
1009
( void ) xTaskNotifyWaitIndexed ( pxStreamBuffer -> uxNotificationIndex , ( uint32_t ) 0 , ( uint32_t ) 0 , NULL , xTicksToWait );
@@ -1087,7 +1199,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1087
1199
{
1088
1200
/* Checking if there is data and clearing the notification state must be
1089
1201
* performed atomically. */
1090
- taskENTER_CRITICAL ( );
1202
+ sbENTER_CRITICAL ( pxStreamBuffer );
1091
1203
{
1092
1204
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer );
1093
1205
@@ -1112,7 +1224,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1112
1224
mtCOVERAGE_TEST_MARKER ();
1113
1225
}
1114
1226
}
1115
- taskEXIT_CRITICAL ( );
1227
+ sbEXIT_CRITICAL ( pxStreamBuffer );
1116
1228
1117
1229
if ( xBytesAvailable <= xBytesToStoreMessageLength )
1118
1230
{
@@ -1409,7 +1521,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1409
1521
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1410
1522
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1411
1523
/* coverity[misra_c_2012_directive_4_7_violation] */
1412
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1524
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1413
1525
{
1414
1526
if ( ( pxStreamBuffer )-> xTaskWaitingToReceive != NULL )
1415
1527
{
@@ -1426,7 +1538,7 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer
1426
1538
xReturn = pdFALSE ;
1427
1539
}
1428
1540
}
1429
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1541
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1430
1542
1431
1543
traceRETURN_xStreamBufferSendCompletedFromISR ( xReturn );
1432
1544
@@ -1448,7 +1560,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1448
1560
/* MISRA Ref 4.7.1 [Return value shall be checked] */
1449
1561
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1450
1562
/* coverity[misra_c_2012_directive_4_7_violation] */
1451
- uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR ( );
1563
+ uxSavedInterruptStatus = sbENTER_CRITICAL_FROM_ISR ( pxStreamBuffer );
1452
1564
{
1453
1565
if ( ( pxStreamBuffer )-> xTaskWaitingToSend != NULL )
1454
1566
{
@@ -1465,7 +1577,7 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf
1465
1577
xReturn = pdFALSE ;
1466
1578
}
1467
1579
}
1468
- taskEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus );
1580
+ sbEXIT_CRITICAL_FROM_ISR ( uxSavedInterruptStatus , pxStreamBuffer );
1469
1581
1470
1582
traceRETURN_xStreamBufferReceiveCompletedFromISR ( xReturn );
1471
1583
0 commit comments