mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-20 10:08:33 -04:00
CI-CD Updates (#768)
* Use new version of CI-CD Actions * Use cSpell spell check, and use ubuntu-20.04 for formatting check * Format and spell check all files in the portable directory * Remove the https:// from #errors and #warnings as uncrustify attempts to change it to /* * Use checkout@v3 instead of checkout@v2 on all jobs ---------
This commit is contained in:
parent
d6bccb1f4c
commit
5fb9b50da8
485 changed files with 108790 additions and 107581 deletions
|
@ -39,14 +39,14 @@
|
|||
#pragma comment(lib, "winmm.lib")
|
||||
#endif
|
||||
|
||||
#define portMAX_INTERRUPTS ( ( uint32_t ) sizeof( uint32_t ) * 8UL ) /* The number of bits in an uint32_t. */
|
||||
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
|
||||
#define portMAX_INTERRUPTS ( ( uint32_t ) sizeof( uint32_t ) * 8UL ) /* The number of bits in an uint32_t. */
|
||||
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
|
||||
|
||||
/* The priorities at which the various components of the simulation execute. */
|
||||
#define portDELETE_SELF_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL /* Must be highest. */
|
||||
#define portSIMULATED_INTERRUPTS_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
|
||||
#define portSIMULATED_TIMER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
|
||||
#define portTASK_THREAD_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
|
||||
#define portDELETE_SELF_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL /* Must be highest. */
|
||||
#define portSIMULATED_INTERRUPTS_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
|
||||
#define portSIMULATED_TIMER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
|
||||
#define portTASK_THREAD_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
|
||||
|
||||
/*
|
||||
* Created as a high priority thread, this function uses a timer to simulate
|
||||
|
@ -87,47 +87,47 @@ static BOOL WINAPI prvEndProcess( DWORD dwCtrlType );
|
|||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The WIN32 simulator runs each task in a thread. The context switching is
|
||||
managed by the threads, so the task stack does not have to be managed directly,
|
||||
although the task stack is still used to hold an xThreadState structure this is
|
||||
the only thing it will ever hold. The structure indirectly maps the task handle
|
||||
to a thread handle. */
|
||||
* managed by the threads, so the task stack does not have to be managed directly,
|
||||
* although the task stack is still used to hold an xThreadState structure this is
|
||||
* the only thing it will ever hold. The structure indirectly maps the task handle
|
||||
* to a thread handle. */
|
||||
typedef struct
|
||||
{
|
||||
/* Handle of the thread that executes the task. */
|
||||
void *pvThread;
|
||||
void * pvThread;
|
||||
|
||||
/* Event used to make sure the thread does not execute past a yield point
|
||||
between the call to SuspendThread() to suspend the thread and the
|
||||
asynchronous SuspendThread() operation actually being performed. */
|
||||
void *pvYieldEvent;
|
||||
* between the call to SuspendThread() to suspend the thread and the
|
||||
* asynchronous SuspendThread() operation actually being performed. */
|
||||
void * pvYieldEvent;
|
||||
} ThreadState_t;
|
||||
|
||||
/* Simulated interrupts waiting to be processed. This is a bit mask where each
|
||||
bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
|
||||
* bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
|
||||
static volatile uint32_t ulPendingInterrupts = 0UL;
|
||||
|
||||
/* An event used to inform the simulated interrupt processing thread (a high
|
||||
priority thread that simulated interrupt processing) that an interrupt is
|
||||
pending. */
|
||||
static void *pvInterruptEvent = NULL;
|
||||
* priority thread that simulated interrupt processing) that an interrupt is
|
||||
* pending. */
|
||||
static void * pvInterruptEvent = NULL;
|
||||
|
||||
/* Mutex used to protect all the simulated interrupt variables that are accessed
|
||||
by multiple threads. */
|
||||
static void *pvInterruptEventMutex = NULL;
|
||||
* by multiple threads. */
|
||||
static void * pvInterruptEventMutex = NULL;
|
||||
|
||||
/* The critical nesting count for the currently executing task. This is
|
||||
initialised to a non-zero value so interrupts do not become enabled during
|
||||
the initialisation phase. As each task has its own critical nesting value
|
||||
ulCriticalNesting will get set to zero when the first task runs. This
|
||||
initialisation is probably not critical in this simulated environment as the
|
||||
simulated interrupt handlers do not get created until the FreeRTOS scheduler is
|
||||
started anyway. */
|
||||
* initialised to a non-zero value so interrupts do not become enabled during
|
||||
* the initialisation phase. As each task has its own critical nesting value
|
||||
* ulCriticalNesting will get set to zero when the first task runs. This
|
||||
* initialisation is probably not critical in this simulated environment as the
|
||||
* simulated interrupt handlers do not get created until the FreeRTOS scheduler is
|
||||
* started anyway. */
|
||||
static volatile uint32_t ulCriticalNesting = 9999UL;
|
||||
|
||||
/* Handlers for all the simulated software interrupts. The first two positions
|
||||
are used for the Yield and Tick interrupts so are handled slightly differently,
|
||||
all the other interrupts can be user defined. */
|
||||
static uint32_t (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
|
||||
* are used for the Yield and Tick interrupts so are handled slightly differently,
|
||||
* all the other interrupts can be user defined. */
|
||||
static uint32_t (* ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
|
||||
|
||||
/* Pointer to the TCB of the currently executing task. */
|
||||
extern void * volatile pxCurrentTCB;
|
||||
|
@ -139,8 +139,8 @@ static BaseType_t xPortRunning = pdFALSE;
|
|||
|
||||
static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
|
||||
{
|
||||
TickType_t xMinimumWindowsBlockTime;
|
||||
TIMECAPS xTimeCaps;
|
||||
TickType_t xMinimumWindowsBlockTime;
|
||||
TIMECAPS xTimeCaps;
|
||||
|
||||
/* Set the timer resolution to the maximum possible. */
|
||||
if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
|
||||
|
@ -149,7 +149,7 @@ TIMECAPS xTimeCaps;
|
|||
timeBeginPeriod( xTimeCaps.wPeriodMin );
|
||||
|
||||
/* Register an exit handler so the timeBeginPeriod() function can be
|
||||
matched with a timeEndPeriod() when the application exits. */
|
||||
* matched with a timeEndPeriod() when the application exits. */
|
||||
SetConsoleCtrlHandler( prvEndProcess, TRUE );
|
||||
}
|
||||
else
|
||||
|
@ -163,11 +163,11 @@ TIMECAPS xTimeCaps;
|
|||
while( xPortRunning == pdTRUE )
|
||||
{
|
||||
/* Wait until the timer expires and we can access the simulated interrupt
|
||||
variables. *NOTE* this is not a 'real time' way of generating tick
|
||||
events as the next wake time should be relative to the previous wake
|
||||
time, not the time that Sleep() is called. It is done this way to
|
||||
prevent overruns in this very non real time simulated/emulated
|
||||
environment. */
|
||||
* variables. *NOTE* this is not a 'real time' way of generating tick
|
||||
* events as the next wake time should be relative to the previous wake
|
||||
* time, not the time that Sleep() is called. It is done this way to
|
||||
* prevent overruns in this very non real time simulated/emulated
|
||||
* environment. */
|
||||
if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )
|
||||
{
|
||||
Sleep( xMinimumWindowsBlockTime );
|
||||
|
@ -182,40 +182,39 @@ TIMECAPS xTimeCaps;
|
|||
configASSERT( xPortRunning );
|
||||
|
||||
/* Can't proceed if in a critical section as pvInterruptEventMutex won't
|
||||
be available. */
|
||||
* be available. */
|
||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||
|
||||
/* The timer has expired, generate the simulated tick event. */
|
||||
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
|
||||
|
||||
/* The interrupt is now pending - notify the simulated interrupt
|
||||
handler thread. Must be outside of a critical section to get here so
|
||||
the handler thread can execute immediately pvInterruptEventMutex is
|
||||
released. */
|
||||
* handler thread. Must be outside of a critical section to get here so
|
||||
* the handler thread can execute immediately pvInterruptEventMutex is
|
||||
* released. */
|
||||
configASSERT( ulCriticalNesting == 0UL );
|
||||
SetEvent( pvInterruptEvent );
|
||||
|
||||
/* Give back the mutex so the simulated interrupt handler unblocks
|
||||
and can access the interrupt handler variables. */
|
||||
* and can access the interrupt handler variables. */
|
||||
ReleaseMutex( pvInterruptEventMutex );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BOOL WINAPI prvEndProcess( DWORD dwCtrlType )
|
||||
{
|
||||
TIMECAPS xTimeCaps;
|
||||
TIMECAPS xTimeCaps;
|
||||
|
||||
( void ) dwCtrlType;
|
||||
|
||||
if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
|
||||
{
|
||||
/* Match the call to timeBeginPeriod( xTimeCaps.wPeriodMin ) made when
|
||||
the process started with a timeEndPeriod() as the process exits. */
|
||||
* the process started with a timeEndPeriod() as the process exits. */
|
||||
timeEndPeriod( xTimeCaps.wPeriodMin );
|
||||
}
|
||||
|
||||
|
@ -223,27 +222,29 @@ TIMECAPS xTimeCaps;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
|
||||
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters )
|
||||
{
|
||||
ThreadState_t *pxThreadState = NULL;
|
||||
int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;
|
||||
const SIZE_T xStackSize = 1024; /* Set the size to a small number which will get rounded up to the minimum possible. */
|
||||
ThreadState_t * pxThreadState = NULL;
|
||||
int8_t * pcTopOfStack = ( int8_t * ) pxTopOfStack;
|
||||
const SIZE_T xStackSize = 1024; /* Set the size to a small number which will get rounded up to the minimum possible. */
|
||||
|
||||
/* In this simulated case a stack is not initialised, but instead a thread
|
||||
is created that will execute the task being created. The thread handles
|
||||
the context switching itself. The ThreadState_t object is placed onto
|
||||
the stack that was created for the task - so the stack buffer is still
|
||||
used, just not in the conventional way. It will not be used for anything
|
||||
other than holding this structure. */
|
||||
* is created that will execute the task being created. The thread handles
|
||||
* the context switching itself. The ThreadState_t object is placed onto
|
||||
* the stack that was created for the task - so the stack buffer is still
|
||||
* used, just not in the conventional way. It will not be used for anything
|
||||
* other than holding this structure. */
|
||||
pxThreadState = ( ThreadState_t * ) ( pcTopOfStack - sizeof( ThreadState_t ) );
|
||||
|
||||
/* Create the event used to prevent the thread from executing past its yield
|
||||
point if the SuspendThread() call that suspends the thread does not take
|
||||
effect immediately (it is an asynchronous call). */
|
||||
pxThreadState->pvYieldEvent = CreateEvent( NULL, /* Default security attributes. */
|
||||
FALSE, /* Auto reset. */
|
||||
FALSE, /* Start not signalled. */
|
||||
NULL );/* No name. */
|
||||
* point if the SuspendThread() call that suspends the thread does not take
|
||||
* effect immediately (it is an asynchronous call). */
|
||||
pxThreadState->pvYieldEvent = CreateEvent( NULL, /* Default security attributes. */
|
||||
FALSE, /* Auto reset. */
|
||||
FALSE, /* Start not signalled. */
|
||||
NULL ); /* No name. */
|
||||
|
||||
/* Create the thread itself. */
|
||||
pxThreadState->pvThread = CreateThread( NULL, xStackSize, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, NULL );
|
||||
|
@ -258,15 +259,16 @@ const SIZE_T xStackSize = 1024; /* Set the size to a small number which will get
|
|||
|
||||
BaseType_t xPortStartScheduler( void )
|
||||
{
|
||||
void *pvHandle = NULL;
|
||||
int32_t lSuccess;
|
||||
ThreadState_t *pxThreadState = NULL;
|
||||
SYSTEM_INFO xSystemInfo;
|
||||
void * pvHandle = NULL;
|
||||
int32_t lSuccess;
|
||||
ThreadState_t * pxThreadState = NULL;
|
||||
SYSTEM_INFO xSystemInfo;
|
||||
|
||||
/* This port runs windows threads with extremely high priority. All the
|
||||
threads execute on the same core - to prevent locking up the host only start
|
||||
if the host has multiple cores. */
|
||||
* threads execute on the same core - to prevent locking up the host only start
|
||||
* if the host has multiple cores. */
|
||||
GetSystemInfo( &xSystemInfo );
|
||||
|
||||
if( xSystemInfo.dwNumberOfProcessors <= 1 )
|
||||
{
|
||||
printf( "This version of the FreeRTOS Windows port can only be used on multi-core hosts.\r\n" );
|
||||
|
@ -277,7 +279,7 @@ SYSTEM_INFO xSystemInfo;
|
|||
lSuccess = pdPASS;
|
||||
|
||||
/* The highest priority class is used to [try to] prevent other Windows
|
||||
activity interfering with FreeRTOS timing too much. */
|
||||
* activity interfering with FreeRTOS timing too much. */
|
||||
if( SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) == 0 )
|
||||
{
|
||||
printf( "SetPriorityClass() failed\r\n" );
|
||||
|
@ -288,7 +290,7 @@ SYSTEM_INFO xSystemInfo;
|
|||
vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );
|
||||
|
||||
/* Create the events and mutexes that are used to synchronise all the
|
||||
threads. */
|
||||
* threads. */
|
||||
pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
|
||||
pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
|
||||
|
@ -298,9 +300,10 @@ SYSTEM_INFO xSystemInfo;
|
|||
}
|
||||
|
||||
/* Set the priority of this thread such that it is above the priority of
|
||||
the threads that run tasks. This higher priority is required to ensure
|
||||
simulated interrupts take priority over tasks. */
|
||||
* the threads that run tasks. This higher priority is required to ensure
|
||||
* simulated interrupts take priority over tasks. */
|
||||
pvHandle = GetCurrentThread();
|
||||
|
||||
if( pvHandle == NULL )
|
||||
{
|
||||
lSuccess = pdFAIL;
|
||||
|
@ -313,6 +316,7 @@ SYSTEM_INFO xSystemInfo;
|
|||
{
|
||||
lSuccess = pdFAIL;
|
||||
}
|
||||
|
||||
SetThreadPriorityBoost( pvHandle, TRUE );
|
||||
SetThreadAffinityMask( pvHandle, 0x01 );
|
||||
}
|
||||
|
@ -320,10 +324,11 @@ SYSTEM_INFO xSystemInfo;
|
|||
if( lSuccess == pdPASS )
|
||||
{
|
||||
/* Start the thread that simulates the timer peripheral to generate
|
||||
tick interrupts. The priority is set below that of the simulated
|
||||
interrupt handler so the interrupt event mutex is used for the
|
||||
handshake / overrun protection. */
|
||||
* tick interrupts. The priority is set below that of the simulated
|
||||
* interrupt handler so the interrupt event mutex is used for the
|
||||
* handshake / overrun protection. */
|
||||
pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, CREATE_SUSPENDED, NULL );
|
||||
|
||||
if( pvHandle != NULL )
|
||||
{
|
||||
SetThreadPriority( pvHandle, portSIMULATED_TIMER_THREAD_PRIORITY );
|
||||
|
@ -333,7 +338,7 @@ SYSTEM_INFO xSystemInfo;
|
|||
}
|
||||
|
||||
/* Start the highest priority task by obtaining its associated thread
|
||||
state structure, in which is stored the thread handle. */
|
||||
* state structure, in which is stored the thread handle. */
|
||||
pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
|
||||
ulCriticalNesting = portNO_CRITICAL_NESTING;
|
||||
|
||||
|
@ -344,12 +349,12 @@ SYSTEM_INFO xSystemInfo;
|
|||
xPortRunning = pdTRUE;
|
||||
|
||||
/* Handle all simulated interrupts - including yield requests and
|
||||
simulated ticks. */
|
||||
* simulated ticks. */
|
||||
prvProcessSimulatedInterrupts();
|
||||
}
|
||||
|
||||
/* Would not expect to return from prvProcessSimulatedInterrupts(), so should
|
||||
not get here. */
|
||||
* not get here. */
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
@ -363,7 +368,7 @@ static uint32_t prvProcessYieldInterrupt( void )
|
|||
|
||||
static uint32_t prvProcessTickInterrupt( void )
|
||||
{
|
||||
uint32_t ulSwitchRequired;
|
||||
uint32_t ulSwitchRequired;
|
||||
|
||||
/* Process the tick itself. */
|
||||
configASSERT( xPortRunning );
|
||||
|
@ -375,21 +380,21 @@ uint32_t ulSwitchRequired;
|
|||
|
||||
static void prvProcessSimulatedInterrupts( void )
|
||||
{
|
||||
uint32_t ulSwitchRequired, i;
|
||||
ThreadState_t *pxThreadState;
|
||||
void *pvObjectList[ 2 ];
|
||||
CONTEXT xContext;
|
||||
DWORD xWinApiResult;
|
||||
const DWORD xTimeoutMilliseconds = 1000;
|
||||
uint32_t ulSwitchRequired, i;
|
||||
ThreadState_t * pxThreadState;
|
||||
void * pvObjectList[ 2 ];
|
||||
CONTEXT xContext;
|
||||
DWORD xWinApiResult;
|
||||
const DWORD xTimeoutMilliseconds = 1000;
|
||||
|
||||
/* Going to block on the mutex that ensured exclusive access to the simulated
|
||||
interrupt objects, and the event that signals that a simulated interrupt
|
||||
should be processed. */
|
||||
* interrupt objects, and the event that signals that a simulated interrupt
|
||||
* should be processed. */
|
||||
pvObjectList[ 0 ] = pvInterruptEventMutex;
|
||||
pvObjectList[ 1 ] = pvInterruptEvent;
|
||||
|
||||
/* Create a pending tick to ensure the first task is started as soon as
|
||||
this thread pends. */
|
||||
* this thread pends. */
|
||||
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
|
||||
SetEvent( pvInterruptEvent );
|
||||
|
||||
|
@ -404,18 +409,18 @@ const DWORD xTimeoutMilliseconds = 1000;
|
|||
if( xWinApiResult != WAIT_TIMEOUT )
|
||||
{
|
||||
/* Cannot be in a critical section to get here. Tasks that exit a
|
||||
critical section will block on a yield mutex to wait for an interrupt to
|
||||
process if an interrupt was set pending while the task was inside the
|
||||
critical section. xInsideInterrupt prevents interrupts that contain
|
||||
critical sections from doing the same. */
|
||||
* critical section will block on a yield mutex to wait for an interrupt to
|
||||
* process if an interrupt was set pending while the task was inside the
|
||||
* critical section. xInsideInterrupt prevents interrupts that contain
|
||||
* critical sections from doing the same. */
|
||||
xInsideInterrupt = pdTRUE;
|
||||
|
||||
/* Used to indicate whether the simulated interrupt processing has
|
||||
necessitated a context switch to another task/thread. */
|
||||
* necessitated a context switch to another task/thread. */
|
||||
ulSwitchRequired = pdFALSE;
|
||||
|
||||
/* For each interrupt we are interested in processing, each of which is
|
||||
represented by a bit in the 32bit ulPendingInterrupts variable. */
|
||||
* represented by a bit in the 32bit ulPendingInterrupts variable. */
|
||||
for( i = 0; i < portMAX_INTERRUPTS; i++ )
|
||||
{
|
||||
/* Is the simulated interrupt pending? */
|
||||
|
@ -425,7 +430,7 @@ const DWORD xTimeoutMilliseconds = 1000;
|
|||
if( ulIsrHandler[ i ] != NULL )
|
||||
{
|
||||
/* Run the actual handler. Handlers return pdTRUE if they
|
||||
necessitate a context switch. */
|
||||
* necessitate a context switch. */
|
||||
if( ulIsrHandler[ i ]() != pdFALSE )
|
||||
{
|
||||
/* A bit mask is used purely to help debugging. */
|
||||
|
@ -440,7 +445,7 @@ const DWORD xTimeoutMilliseconds = 1000;
|
|||
|
||||
if( ulSwitchRequired != pdFALSE )
|
||||
{
|
||||
void *pvOldCurrentTCB;
|
||||
void * pvOldCurrentTCB;
|
||||
|
||||
pvOldCurrentTCB = pxCurrentTCB;
|
||||
|
||||
|
@ -448,51 +453,51 @@ const DWORD xTimeoutMilliseconds = 1000;
|
|||
vTaskSwitchContext();
|
||||
|
||||
/* If the task selected to enter the running state is not the task
|
||||
that is already in the running state. */
|
||||
* that is already in the running state. */
|
||||
if( pvOldCurrentTCB != pxCurrentTCB )
|
||||
{
|
||||
/* Suspend the old thread. In the cases where the (simulated)
|
||||
interrupt is asynchronous (tick event swapping a task out rather
|
||||
than a task blocking or yielding) it doesn't matter if the
|
||||
'suspend' operation doesn't take effect immediately - if it
|
||||
doesn't it would just be like the interrupt occurring slightly
|
||||
later. In cases where the yield was caused by a task blocking
|
||||
or yielding then the task will block on a yield event after the
|
||||
yield operation in case the 'suspend' operation doesn't take
|
||||
effect immediately. */
|
||||
pxThreadState = ( ThreadState_t *) *( ( size_t * ) pvOldCurrentTCB );
|
||||
* interrupt is asynchronous (tick event swapping a task out rather
|
||||
* than a task blocking or yielding) it doesn't matter if the
|
||||
* 'suspend' operation doesn't take effect immediately - if it
|
||||
* doesn't it would just be like the interrupt occurring slightly
|
||||
* later. In cases where the yield was caused by a task blocking
|
||||
* or yielding then the task will block on a yield event after the
|
||||
* yield operation in case the 'suspend' operation doesn't take
|
||||
* effect immediately. */
|
||||
pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pvOldCurrentTCB );
|
||||
SuspendThread( pxThreadState->pvThread );
|
||||
|
||||
/* Ensure the thread is actually suspended by performing a
|
||||
synchronous operation that can only complete when the thread is
|
||||
actually suspended. The below code asks for dummy register
|
||||
data. Experimentation shows that these two lines don't appear
|
||||
to do anything now, but according to
|
||||
https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
|
||||
they do - so as they do not harm (slight run-time hit). */
|
||||
* synchronous operation that can only complete when the thread is
|
||||
* actually suspended. The below code asks for dummy register
|
||||
* data. Experimentation shows that these two lines don't appear
|
||||
* to do anything now, but according to
|
||||
* https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
|
||||
* they do - so as they do not harm (slight run-time hit). */
|
||||
xContext.ContextFlags = CONTEXT_INTEGER;
|
||||
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
|
||||
|
||||
/* Obtain the state of the task now selected to enter the
|
||||
Running state. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
|
||||
* Running state. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pxCurrentTCB );
|
||||
|
||||
/* pxThreadState->pvThread can be NULL if the task deleted
|
||||
itself - but a deleted task should never be resumed here. */
|
||||
* itself - but a deleted task should never be resumed here. */
|
||||
configASSERT( pxThreadState->pvThread != NULL );
|
||||
ResumeThread( pxThreadState->pvThread );
|
||||
}
|
||||
}
|
||||
|
||||
/* If the thread that is about to be resumed stopped running
|
||||
because it yielded then it will wait on an event when it resumed
|
||||
(to ensure it does not continue running after the call to
|
||||
SuspendThread() above as SuspendThread() is asynchronous).
|
||||
Signal the event to ensure the thread can proceed now it is
|
||||
valid for it to do so. Signaling the event is benign in the case that
|
||||
the task was switched out asynchronously by an interrupt as the event
|
||||
is reset before the task blocks on it. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
|
||||
* because it yielded then it will wait on an event when it resumed
|
||||
* (to ensure it does not continue running after the call to
|
||||
* SuspendThread() above as SuspendThread() is asynchronous).
|
||||
* Signal the event to ensure the thread can proceed now it is
|
||||
* valid for it to do so. Signaling the event is benign in the case that
|
||||
* the task was switched out asynchronously by an interrupt as the event
|
||||
* is reset before the task blocks on it. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pxCurrentTCB );
|
||||
SetEvent( pxThreadState->pvYieldEvent );
|
||||
ReleaseMutex( pvInterruptEventMutex );
|
||||
}
|
||||
|
@ -500,29 +505,29 @@ const DWORD xTimeoutMilliseconds = 1000;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortDeleteThread( void *pvTaskToDelete )
|
||||
void vPortDeleteThread( void * pvTaskToDelete )
|
||||
{
|
||||
ThreadState_t *pxThreadState;
|
||||
uint32_t ulErrorCode;
|
||||
ThreadState_t * pxThreadState;
|
||||
uint32_t ulErrorCode;
|
||||
|
||||
/* Remove compiler warnings if configASSERT() is not defined. */
|
||||
( void ) ulErrorCode;
|
||||
|
||||
/* Find the handle of the thread being deleted. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pvTaskToDelete );
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pvTaskToDelete );
|
||||
|
||||
/* Check that the thread is still valid, it might have been closed by
|
||||
vPortCloseRunningThread() - which will be the case if the task associated
|
||||
with the thread originally deleted itself rather than being deleted by a
|
||||
different task. */
|
||||
* vPortCloseRunningThread() - which will be the case if the task associated
|
||||
* with the thread originally deleted itself rather than being deleted by a
|
||||
* different task. */
|
||||
if( pxThreadState->pvThread != NULL )
|
||||
{
|
||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||
|
||||
/* !!! This is not a nice way to terminate a thread, and will eventually
|
||||
result in resources being depleted if tasks frequently delete other
|
||||
tasks (rather than deleting themselves) as the task stacks will not be
|
||||
freed. */
|
||||
* result in resources being depleted if tasks frequently delete other
|
||||
* tasks (rather than deleting themselves) as the task stacks will not be
|
||||
* freed. */
|
||||
ulErrorCode = TerminateThread( pxThreadState->pvThread, 0 );
|
||||
configASSERT( ulErrorCode );
|
||||
|
||||
|
@ -534,31 +539,32 @@ uint32_t ulErrorCode;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortCloseRunningThread( void *pvTaskToDelete, volatile BaseType_t *pxPendYield )
|
||||
void vPortCloseRunningThread( void * pvTaskToDelete,
|
||||
volatile BaseType_t * pxPendYield )
|
||||
{
|
||||
ThreadState_t *pxThreadState;
|
||||
void *pvThread;
|
||||
uint32_t ulErrorCode;
|
||||
ThreadState_t * pxThreadState;
|
||||
void * pvThread;
|
||||
uint32_t ulErrorCode;
|
||||
|
||||
/* Remove compiler warnings if configASSERT() is not defined. */
|
||||
( void ) ulErrorCode;
|
||||
|
||||
/* Find the handle of the thread being deleted. */
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pvTaskToDelete );
|
||||
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pvTaskToDelete );
|
||||
pvThread = pxThreadState->pvThread;
|
||||
|
||||
/* Raise the Windows priority of the thread to ensure the FreeRTOS scheduler
|
||||
does not run and swap it out before it is closed. If that were to happen
|
||||
the thread would never run again and effectively be a thread handle and
|
||||
memory leak. */
|
||||
* does not run and swap it out before it is closed. If that were to happen
|
||||
* the thread would never run again and effectively be a thread handle and
|
||||
* memory leak. */
|
||||
SetThreadPriority( pvThread, portDELETE_SELF_THREAD_PRIORITY );
|
||||
|
||||
/* This function will not return, therefore a yield is set as pending to
|
||||
ensure a context switch occurs away from this thread on the next tick. */
|
||||
* ensure a context switch occurs away from this thread on the next tick. */
|
||||
*pxPendYield = pdTRUE;
|
||||
|
||||
/* Mark the thread associated with this task as invalid so
|
||||
vPortDeleteThread() does not try to terminate it. */
|
||||
* vPortDeleteThread() does not try to terminate it. */
|
||||
pxThreadState->pvThread = NULL;
|
||||
|
||||
/* Close the thread. */
|
||||
|
@ -566,7 +572,7 @@ uint32_t ulErrorCode;
|
|||
configASSERT( ulErrorCode );
|
||||
|
||||
/* This is called from a critical section, which must be exited before the
|
||||
thread stops. */
|
||||
* thread stops. */
|
||||
taskEXIT_CRITICAL();
|
||||
CloseHandle( pxThreadState->pvYieldEvent );
|
||||
ExitThread( 0 );
|
||||
|
@ -581,7 +587,7 @@ void vPortEndScheduler( void )
|
|||
|
||||
void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )
|
||||
{
|
||||
ThreadState_t *pxThreadState = ( ThreadState_t *) *( ( size_t * ) pxCurrentTCB );
|
||||
ThreadState_t * pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
|
||||
|
||||
configASSERT( xPortRunning );
|
||||
|
||||
|
@ -591,34 +597,36 @@ ThreadState_t *pxThreadState = ( ThreadState_t *) *( ( size_t * ) pxCurrentTCB )
|
|||
ulPendingInterrupts |= ( 1 << ulInterruptNumber );
|
||||
|
||||
/* The simulated interrupt is now held pending, but don't actually
|
||||
process it yet if this call is within a critical section. It is
|
||||
possible for this to be in a critical section as calls to wait for
|
||||
mutexes are accumulative. If in a critical section then the event
|
||||
will get set when the critical section nesting count is wound back
|
||||
down to zero. */
|
||||
* process it yet if this call is within a critical section. It is
|
||||
* possible for this to be in a critical section as calls to wait for
|
||||
* mutexes are accumulative. If in a critical section then the event
|
||||
* will get set when the critical section nesting count is wound back
|
||||
* down to zero. */
|
||||
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
|
||||
{
|
||||
SetEvent( pvInterruptEvent );
|
||||
|
||||
/* Going to wait for an event - make sure the event is not already
|
||||
signaled. */
|
||||
* signaled. */
|
||||
ResetEvent( pxThreadState->pvYieldEvent );
|
||||
}
|
||||
|
||||
ReleaseMutex( pvInterruptEventMutex );
|
||||
|
||||
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
|
||||
{
|
||||
/* An interrupt was pended so ensure to block to allow it to
|
||||
execute. In most cases the (simulated) interrupt will have
|
||||
executed before the next line is reached - so this is just to make
|
||||
sure. */
|
||||
* execute. In most cases the (simulated) interrupt will have
|
||||
* executed before the next line is reached - so this is just to make
|
||||
* sure. */
|
||||
WaitForSingleObject( pxThreadState->pvYieldEvent, INFINITE );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortSetInterruptHandler( uint32_t ulInterruptNumber, uint32_t (*pvHandler)( void ) )
|
||||
void vPortSetInterruptHandler( uint32_t ulInterruptNumber,
|
||||
uint32_t ( * pvHandler )( void ) )
|
||||
{
|
||||
if( ulInterruptNumber < portMAX_INTERRUPTS )
|
||||
{
|
||||
|
@ -641,7 +649,7 @@ void vPortEnterCritical( void )
|
|||
if( xPortRunning == pdTRUE )
|
||||
{
|
||||
/* The interrupt event mutex is held for the entire critical section,
|
||||
effectively disabling (simulated) interrupts. */
|
||||
* effectively disabling (simulated) interrupts. */
|
||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||
}
|
||||
|
||||
|
@ -651,10 +659,10 @@ void vPortEnterCritical( void )
|
|||
|
||||
void vPortExitCritical( void )
|
||||
{
|
||||
int32_t lMutexNeedsReleasing;
|
||||
int32_t lMutexNeedsReleasing;
|
||||
|
||||
/* The interrupt event mutex should already be held by this thread as it was
|
||||
obtained on entry to the critical section. */
|
||||
* obtained on entry to the critical section. */
|
||||
lMutexNeedsReleasing = pdTRUE;
|
||||
|
||||
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
|
||||
|
@ -662,33 +670,34 @@ int32_t lMutexNeedsReleasing;
|
|||
ulCriticalNesting--;
|
||||
|
||||
/* Don't need to wait for any pending interrupts to execute if the
|
||||
critical section was exited from inside an interrupt. */
|
||||
* critical section was exited from inside an interrupt. */
|
||||
if( ( ulCriticalNesting == portNO_CRITICAL_NESTING ) && ( xInsideInterrupt == pdFALSE ) )
|
||||
{
|
||||
/* Were any interrupts set to pending while interrupts were
|
||||
(simulated) disabled? */
|
||||
* (simulated) disabled? */
|
||||
if( ulPendingInterrupts != 0UL )
|
||||
{
|
||||
ThreadState_t *pxThreadState = ( ThreadState_t *) *( ( size_t * ) pxCurrentTCB );
|
||||
ThreadState_t * pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
|
||||
|
||||
configASSERT( xPortRunning );
|
||||
|
||||
/* The interrupt won't actually executed until
|
||||
pvInterruptEventMutex is released as it waits on both
|
||||
pvInterruptEventMutex and pvInterruptEvent.
|
||||
pvInterruptEvent is only set when the simulated
|
||||
interrupt is pended if the interrupt is pended
|
||||
from outside a critical section - hence it is set
|
||||
here. */
|
||||
* pvInterruptEventMutex is released as it waits on both
|
||||
* pvInterruptEventMutex and pvInterruptEvent.
|
||||
* pvInterruptEvent is only set when the simulated
|
||||
* interrupt is pended if the interrupt is pended
|
||||
* from outside a critical section - hence it is set
|
||||
* here. */
|
||||
SetEvent( pvInterruptEvent );
|
||||
|
||||
/* The calling task is going to wait for an event to ensure the
|
||||
interrupt that is pending executes immediately after the
|
||||
critical section is exited - so make sure the event is not
|
||||
already signaled. */
|
||||
* interrupt that is pending executes immediately after the
|
||||
* critical section is exited - so make sure the event is not
|
||||
* already signaled. */
|
||||
ResetEvent( pxThreadState->pvYieldEvent );
|
||||
|
||||
/* Mutex will be released now so the (simulated) interrupt can
|
||||
execute, so does not require releasing on function exit. */
|
||||
* execute, so does not require releasing on function exit. */
|
||||
lMutexNeedsReleasing = pdFALSE;
|
||||
ReleaseMutex( pvInterruptEventMutex );
|
||||
WaitForSingleObject( pxThreadState->pvYieldEvent, INFINITE );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue