|
|
@@ -541,6 +541,12 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
|
|
|
|
|
|
#endif
|
|
|
|
|
|
+//Function to call the Thread Local Storage Pointer Deletion Callbacks. Will be
|
|
|
+//called during task deletion before prvDeleteTCB is called.
|
|
|
+#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
+ static void prvDeleteTLS( TCB_t *pxTCB );
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* Used only by the idle task. This checks to see if anything has been placed
|
|
|
* in the list of tasks waiting to be deleted. If so the task is cleaned up
|
|
|
@@ -1201,19 +1207,25 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
#if ( INCLUDE_vTaskDelete == 1 )
|
|
|
+
|
|
|
void vTaskDelete( TaskHandle_t xTaskToDelete )
|
|
|
{
|
|
|
+ //The following vTaskDelete() is backported from FreeRTOS v9.0.0 and modified for SMP.
|
|
|
+ //v9.0.0 vTaskDelete() will immediately free task memory if the task being deleted is
|
|
|
+ //NOT currently running and not pinned to the other core. Otherwise, freeing of task memory
|
|
|
+ //will still be delegated to the Idle Task.
|
|
|
+
|
|
|
TCB_t *pxTCB;
|
|
|
+ int core = xPortGetCoreID(); //Current core
|
|
|
+ UBaseType_t free_now; //Flag to indicate if task memory can be freed immediately
|
|
|
+
|
|
|
taskENTER_CRITICAL(&xTaskQueueMutex);
|
|
|
{
|
|
|
/* If null is passed in here then it is the calling task that is
|
|
|
being deleted. */
|
|
|
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
|
|
|
|
|
|
- /* Remove task from the ready list and place in the termination list.
|
|
|
- This will stop the task from be scheduled. The idle task will check
|
|
|
- the termination list and free up any memory allocated by the
|
|
|
- scheduler for the TCB and stack. */
|
|
|
+ /* Remove task from the ready list. */
|
|
|
if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
|
|
|
{
|
|
|
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
|
|
@@ -1233,29 +1245,67 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
|
|
|
|
- vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
|
|
|
+ /* Increment the uxTaskNumber also so kernel aware debuggers can
|
|
|
+ detect that the task lists need re-generating. This is done before
|
|
|
+ portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
|
|
|
+ not return. */
|
|
|
+ uxTaskNumber++;
|
|
|
|
|
|
- /* Increment the ucTasksDeleted variable so the idle task knows
|
|
|
- there is a task that has been deleted and that it should therefore
|
|
|
- check the xTasksWaitingTermination list. */
|
|
|
- ++uxTasksDeleted;
|
|
|
+ //If task to be deleted is currently running on either core or is pinned to the other core. Let Idle free memory
|
|
|
+ if( pxTCB == pxCurrentTCB[ core ] ||
|
|
|
+ (portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !core ]) ||
|
|
|
+ (portNUM_PROCESSORS > 1 && pxTCB->xCoreID == (!core)) )
|
|
|
+ {
|
|
|
+ /* Deleting a currently running task. This cannot complete
|
|
|
+ within the task itself, as a context switch to another task is
|
|
|
+ required. Place the task in the termination list. The idle task
|
|
|
+ will check the termination list and free up any memory allocated
|
|
|
+ by the scheduler for the TCB and stack of the deleted task. */
|
|
|
+ vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
|
|
|
+
|
|
|
+ /* Increment the ucTasksDeleted variable so the idle task knows
|
|
|
+ there is a task that has been deleted and that it should therefore
|
|
|
+ check the xTasksWaitingTermination list. */
|
|
|
+ ++uxTasksDeleted;
|
|
|
|
|
|
- /* Increment the uxTaskNumberVariable also so kernel aware debuggers
|
|
|
- can detect that the task lists need re-generating. */
|
|
|
- uxTaskNumber++;
|
|
|
+ /* The pre-delete hook is primarily for the Windows simulator,
|
|
|
+ in which Windows specific clean up operations are performed,
|
|
|
+ after which it is not possible to yield away from this task -
|
|
|
+ hence xYieldPending is used to latch that a context switch is
|
|
|
+ required. */
|
|
|
+ portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
|
|
|
+
|
|
|
+ free_now = pdFALSE; //Let Idle Task free task memory
|
|
|
+ }
|
|
|
+ else //Task is not currently running and not pinned to the other core
|
|
|
+ {
|
|
|
+ --uxCurrentNumberOfTasks;
|
|
|
+
|
|
|
+ /* Reset the next expected unblock time in case it referred to
|
|
|
+ the task that has just been deleted. */
|
|
|
+ prvResetNextTaskUnblockTime();
|
|
|
+ free_now = pdTRUE; //Set flag to free task memory immediately
|
|
|
+ }
|
|
|
|
|
|
traceTASK_DELETE( pxTCB );
|
|
|
}
|
|
|
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
|
|
|
+ if(free_now == pdTRUE){ //Free task memory. Outside critical section due to deletion callbacks
|
|
|
+ #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
+ prvDeleteTLS( pxTCB ); //Run deletion callbacks before deleting TCB
|
|
|
+ #endif
|
|
|
+ prvDeleteTCB( pxTCB ); //Must only be called after del cb
|
|
|
+ }
|
|
|
+
|
|
|
/* Force a reschedule if it is the currently running task that has just
|
|
|
been deleted. */
|
|
|
if( xSchedulerRunning != pdFALSE )
|
|
|
{
|
|
|
//No mux; no harm done if this misfires. The deleted task won't get scheduled anyway.
|
|
|
- if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
|
|
|
+ if( pxTCB == pxCurrentTCB[ core ] ) //If task was currently running on this core
|
|
|
{
|
|
|
- configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 );
|
|
|
+ configASSERT( uxSchedulerSuspended[ core ] == 0 );
|
|
|
|
|
|
/* The pre-delete hook is primarily for the Windows simulator,
|
|
|
in which Windows specific clean up operations are performed,
|
|
|
@@ -1265,20 +1315,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
|
|
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[xPortGetCoreID()] );
|
|
|
portYIELD_WITHIN_API();
|
|
|
}
|
|
|
- else if ( portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !xPortGetCoreID() ] )
|
|
|
+ else if ( portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !core] ) //If task was currently running on the other core
|
|
|
{
|
|
|
/* if task is running on the other CPU, force a yield on that CPU to take it off */
|
|
|
- vPortYieldOtherCore( !xPortGetCoreID() );
|
|
|
+ vPortYieldOtherCore( !core );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- /* Reset the next expected unblock time in case it referred to
|
|
|
- the task that has just been deleted. */
|
|
|
- taskENTER_CRITICAL(&xTaskQueueMutex);
|
|
|
- {
|
|
|
- prvResetNextTaskUnblockTime();
|
|
|
- }
|
|
|
- taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
+ mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -3583,52 +3627,48 @@ static void prvCheckTasksWaitingTermination( void )
|
|
|
#if ( INCLUDE_vTaskDelete == 1 )
|
|
|
{
|
|
|
BaseType_t xListIsEmpty;
|
|
|
+ int core = xPortGetCoreID();
|
|
|
|
|
|
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
|
|
too often in the idle task. */
|
|
|
while(uxTasksDeleted > ( UBaseType_t ) 0U )
|
|
|
{
|
|
|
TCB_t *pxTCB = NULL;
|
|
|
+
|
|
|
taskENTER_CRITICAL(&xTaskQueueMutex);
|
|
|
{
|
|
|
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
|
|
|
- }
|
|
|
-
|
|
|
- if( xListIsEmpty == pdFALSE )
|
|
|
- {
|
|
|
+ if( xListIsEmpty == pdFALSE )
|
|
|
{
|
|
|
- pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
|
|
|
/* We only want to kill tasks that ran on this core because e.g. _xt_coproc_release needs to
|
|
|
- be called on the core the process is pinned on, if any */
|
|
|
- if( pxTCB->xCoreID == tskNO_AFFINITY || pxTCB->xCoreID == xPortGetCoreID()) {
|
|
|
- ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
|
|
|
+ be called on the core the process is pinned on, if any */
|
|
|
+ ListItem_t *target = listGET_HEAD_ENTRY(&xTasksWaitingTermination);
|
|
|
+ for( ; target != listGET_END_MARKER(&xTasksWaitingTermination); target = listGET_NEXT(target) ){
|
|
|
+ int coreid = (( TCB_t * )listGET_LIST_ITEM_OWNER(target))->xCoreID;
|
|
|
+ if(coreid == core || coreid == tskNO_AFFINITY){ //Find first item not pinned to other core
|
|
|
+ pxTCB = ( TCB_t * )listGET_LIST_ITEM_OWNER(target);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(pxTCB != NULL){
|
|
|
+ ( void ) uxListRemove( target ); //Remove list item from list
|
|
|
--uxCurrentNumberOfTasks;
|
|
|
--uxTasksDeleted;
|
|
|
- } else {
|
|
|
- /* Need to wait until the idle task on the other processor kills that task first. */
|
|
|
- taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
- break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
+ taskEXIT_CRITICAL(&xTaskQueueMutex); //Need to call deletion callbacks outside critical section
|
|
|
|
|
|
- if (pxTCB != NULL) {
|
|
|
- #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
- int x;
|
|
|
- for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
|
|
- {
|
|
|
- if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL)
|
|
|
- {
|
|
|
- pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]);
|
|
|
- }
|
|
|
- }
|
|
|
- #endif
|
|
|
- prvDeleteTCB( pxTCB );
|
|
|
+ if (pxTCB != NULL) { //Call deletion callbacks and free TCB memory
|
|
|
+ #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
+ prvDeleteTLS( pxTCB );
|
|
|
+ #endif
|
|
|
+ prvDeleteTCB( pxTCB );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
+ break; //No TCB found that could be freed by this core, break out of loop
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -3831,7 +3871,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
|
|
|
|
|
#if ( INCLUDE_vTaskDelete == 1 )
|
|
|
|
|
|
-
|
|
|
static void prvDeleteTCB( TCB_t *pxTCB )
|
|
|
{
|
|
|
/* Free up the memory allocated by the scheduler for the task. It is up
|
|
|
@@ -3886,6 +3925,23 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
|
|
#endif /* INCLUDE_vTaskDelete */
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
+#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
+
|
|
|
+ static void prvDeleteTLS( TCB_t *pxTCB )
|
|
|
+ {
|
|
|
+ configASSERT( pxTCB );
|
|
|
+ for( int x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
|
|
+ {
|
|
|
+ if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL) //If del cb is set
|
|
|
+ {
|
|
|
+ pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]); //Call del cb
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+#endif /* ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) */
|
|
|
+/*-----------------------------------------------------------*/
|
|
|
+
|
|
|
static void prvResetNextTaskUnblockTime( void )
|
|
|
{
|
|
|
TCB_t *pxTCB;
|