mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Work on Win32 port layer - removing the need to store the critical section nesting count as part of the Win32 thread context.
This commit is contained in:
parent
8133188eee
commit
ab2eb016c1
|
@ -91,9 +91,6 @@ typedef struct
|
||||||
section while pseudo interrupts were pending. */
|
section while pseudo interrupts were pending. */
|
||||||
long lWaitingInterruptAck;
|
long lWaitingInterruptAck;
|
||||||
|
|
||||||
/* Critical nesting count of the task - each task has its own. */
|
|
||||||
portSTACK_TYPE ulCriticalNesting;
|
|
||||||
|
|
||||||
/* Handle of the thread that executes the task. */
|
/* Handle of the thread that executes the task. */
|
||||||
void * pvThread;
|
void * pvThread;
|
||||||
} xThreadState;
|
} xThreadState;
|
||||||
|
@ -154,13 +151,20 @@ static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
|
||||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||||
vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" );
|
vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" );
|
||||||
|
|
||||||
|
/* A thread will hold the interrupt event mutex while in a critical
|
||||||
|
section, so ulCriticalSection should be zero for this tick event to be
|
||||||
|
possible. */
|
||||||
|
if( ulCriticalNesting != 0 )
|
||||||
|
{
|
||||||
|
/* For a break point only. */
|
||||||
|
__asm{ NOP };
|
||||||
|
}
|
||||||
|
|
||||||
/* The timer has expired, generate the simulated tick event. */
|
/* The timer has expired, generate the simulated tick event. */
|
||||||
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
|
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
|
||||||
|
|
||||||
/* The interrupt is now pending - but should only be processed if
|
/* The interrupt is now pending - notify the simulated interrupt
|
||||||
interrupts are actually enabled. */
|
handler thread. */
|
||||||
if( ulCriticalNesting == 0UL )
|
|
||||||
{
|
|
||||||
vPortTrace( "prvSimulatedPeripheralTimer: Setting interrupt event to signal tick\r\n" );
|
vPortTrace( "prvSimulatedPeripheralTimer: Setting interrupt event to signal tick\r\n" );
|
||||||
SetEvent( pvInterruptEvent );
|
SetEvent( pvInterruptEvent );
|
||||||
|
|
||||||
|
@ -171,11 +175,6 @@ static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
|
||||||
vPortTrace( "prvSimulatedPeripheralTimer: Releasing interrupt event mutex so tick can be processed\r\n" );
|
vPortTrace( "prvSimulatedPeripheralTimer: Releasing interrupt event mutex so tick can be processed\r\n" );
|
||||||
SignalObjectAndWait( pvInterruptEventMutex, pvTickAcknowledgeEvent, INFINITE, FALSE );
|
SignalObjectAndWait( pvInterruptEventMutex, pvTickAcknowledgeEvent, INFINITE, FALSE );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ReleaseMutex( pvInterruptEventMutex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -194,7 +193,6 @@ xThreadState *pxThreadState = NULL;
|
||||||
/* Create the thread itself. */
|
/* Create the thread itself. */
|
||||||
pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
|
pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
|
||||||
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
|
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
|
||||||
pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING;
|
|
||||||
pxThreadState->lWaitingInterruptAck = pdFALSE;
|
pxThreadState->lWaitingInterruptAck = pdFALSE;
|
||||||
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
|
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
|
||||||
|
|
||||||
|
@ -296,6 +294,15 @@ unsigned long i;
|
||||||
WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
|
WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Got interrupt event and mutex\r\n" );
|
vPortTrace( "prvProcessPseudoInterrupts: Got interrupt event and mutex\r\n" );
|
||||||
|
|
||||||
|
/* A thread will hold the interrupt event mutex while in a critical
|
||||||
|
section, so this pseudo interrupt handler should only run when
|
||||||
|
critical nesting is zero. */
|
||||||
|
if( ulCriticalNesting != 0 )
|
||||||
|
{
|
||||||
|
/* For a break point only. */
|
||||||
|
__asm{ NOP };
|
||||||
|
}
|
||||||
|
|
||||||
/* Used to indicate whether the pseudo interrupt processing has
|
/* Used to indicate whether the pseudo interrupt processing has
|
||||||
necessitated a context switch to another task/thread. */
|
necessitated a context switch to another task/thread. */
|
||||||
lSwitchRequired = pdFALSE;
|
lSwitchRequired = pdFALSE;
|
||||||
|
@ -331,8 +338,6 @@ unsigned long i;
|
||||||
set up to process yields while within a critical
|
set up to process yields while within a critical
|
||||||
section. */
|
section. */
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Processing tick event\r\n" );
|
vPortTrace( "prvProcessPseudoInterrupts: Processing tick event\r\n" );
|
||||||
if( ulCriticalNesting == 0UL )
|
|
||||||
{
|
|
||||||
/* Process the tick itself. */
|
/* Process the tick itself. */
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Incrementing tick\r\n" );
|
vPortTrace( "prvProcessPseudoInterrupts: Incrementing tick\r\n" );
|
||||||
vTaskIncrementTick();
|
vTaskIncrementTick();
|
||||||
|
@ -350,19 +355,10 @@ unsigned long i;
|
||||||
|
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Acking tick\r\n" );
|
vPortTrace( "prvProcessPseudoInterrupts: Acking tick\r\n" );
|
||||||
SetEvent( pvTickAcknowledgeEvent );
|
SetEvent( pvTickAcknowledgeEvent );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* The tick is held pending in ulCriticalNesting
|
|
||||||
until such time that pseudo interrupts are enabled
|
|
||||||
again. */
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
if( ulCriticalNesting == 0UL )
|
|
||||||
{
|
|
||||||
/* Is a handler installed? */
|
/* Is a handler installed? */
|
||||||
if( vIsrHandler[ i ] != NULL )
|
if( vIsrHandler[ i ] != NULL )
|
||||||
{
|
{
|
||||||
|
@ -378,7 +374,6 @@ unsigned long i;
|
||||||
event here for non-tick and none yield
|
event here for non-tick and none yield
|
||||||
interrupts. */
|
interrupts. */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,10 +385,6 @@ unsigned long i;
|
||||||
|
|
||||||
pvOldCurrentTCB = pxCurrentTCB;
|
pvOldCurrentTCB = pxCurrentTCB;
|
||||||
|
|
||||||
/* Save the state of the current thread before suspending it. */
|
|
||||||
pxThreadState = ( xThreadState *) *( ( unsigned long * ) pxCurrentTCB );
|
|
||||||
pxThreadState->ulCriticalNesting = ulCriticalNesting ;
|
|
||||||
|
|
||||||
/* Select the next task to run. */
|
/* Select the next task to run. */
|
||||||
vTaskSwitchContext();
|
vTaskSwitchContext();
|
||||||
|
|
||||||
|
@ -402,28 +393,40 @@ unsigned long i;
|
||||||
if( pvOldCurrentTCB != pxCurrentTCB )
|
if( pvOldCurrentTCB != pxCurrentTCB )
|
||||||
{
|
{
|
||||||
/* Suspend the old thread. */
|
/* Suspend the old thread. */
|
||||||
|
pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );
|
||||||
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
|
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
|
||||||
|
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
|
||||||
SuspendThread( pxThreadState->pvThread );
|
SuspendThread( pxThreadState->pvThread );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE! - Here lies a problem when the preemptive scheduler is
|
||||||
|
used. It would seem Win32 threads do not stop as soon as a
|
||||||
|
call to suspend them is made. The co-operative scheduler gets
|
||||||
|
around this by having the thread block on a semaphore
|
||||||
|
immediately after yielding so it cannot execute any more task
|
||||||
|
code until it is once again scheduled to run. This cannot be
|
||||||
|
done if the task is pre-empted though, and I have not found an
|
||||||
|
equivalent work around for the preemptive situation. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName );
|
//sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName );
|
||||||
//vPortTrace( cTraceBuffer );
|
//vPortTrace( cTraceBuffer );
|
||||||
|
|
||||||
/* Obtain the state of the task now selected to enter the Running state. */
|
/* Obtain the state of the task now selected to enter the
|
||||||
|
Running state. */
|
||||||
pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
|
pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
|
||||||
ulCriticalNesting = pxThreadState->ulCriticalNesting;
|
|
||||||
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
|
|
||||||
ResumeThread( pxThreadState->pvThread );
|
|
||||||
|
|
||||||
if( pxThreadState->lWaitingInterruptAck == pdTRUE )
|
/* Boost the priority of the thread selected to run a little
|
||||||
{
|
in an attempt to get the Windows thread scheduler to act a
|
||||||
pxThreadState->lWaitingInterruptAck = pdFALSE;
|
little more like an embedded engineer might expect. */
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt\r\n" );
|
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
|
||||||
SetEvent( pvInterruptAcknowledgeEvent );
|
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
|
||||||
|
ResumeThread( pxThreadState->pvThread );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* On exiting a critical section a task may have blocked on the
|
/* On exiting a critical section a task may have blocked on the
|
||||||
interrupt event when only a tick needed processing, in which case
|
interrupt event when only a tick needed processing, in which case
|
||||||
it will not have been released from waiting on the event yet. */
|
it will not have been released from waiting on the event yet. */
|
||||||
|
@ -434,7 +437,6 @@ unsigned long i;
|
||||||
vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt even though a yield has not been performed.\r\n" );
|
vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt even though a yield has not been performed.\r\n" );
|
||||||
SetEvent( pvInterruptAcknowledgeEvent );
|
SetEvent( pvInterruptAcknowledgeEvent );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseMutex( pvInterruptEventMutex );
|
ReleaseMutex( pvInterruptEventMutex );
|
||||||
}
|
}
|
||||||
|
@ -456,7 +458,10 @@ xThreadState *pxThreadState;
|
||||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||||
ulPendingInterrupts |= ( 1 << ulInterruptNumber );
|
ulPendingInterrupts |= ( 1 << ulInterruptNumber );
|
||||||
|
|
||||||
if( ulCriticalNesting == 0 ) //|| ( ulInterruptNumber == portINTERRUPT_YIELD ) )
|
/* The pseudo 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( ulCriticalNesting == 0 )
|
||||||
{
|
{
|
||||||
/* The event handler needs to know to signal the interrupt acknowledge event
|
/* The event handler needs to know to signal the interrupt acknowledge event
|
||||||
the next time this task runs. */
|
the next time this task runs. */
|
||||||
|
@ -475,12 +480,7 @@ xThreadState *pxThreadState;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
|
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
|
||||||
vPortTrace( "vPortGeneratePseudoInterrupt: About to release interrupt event mutex\r\n" );
|
|
||||||
// ReleaseMutex( pvInterruptEventMutex );
|
|
||||||
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for interrupt ack\r\n" );
|
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for interrupt ack\r\n" );
|
||||||
|
|
||||||
// WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
|
|
||||||
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt acknowledged, leaving vPortGeneratePseudoInterrupt()\r\n" );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -512,10 +512,10 @@ void vPortEnterCritical( void )
|
||||||
{
|
{
|
||||||
if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
|
if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
|
||||||
{
|
{
|
||||||
|
/* The interrupt event mutex is held for the entire critical section,
|
||||||
|
effectively disabling (pseudo) interrupts. */
|
||||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
||||||
// SuspendThread( pvSimulatedTimerThread );
|
|
||||||
ulCriticalNesting++;
|
ulCriticalNesting++;
|
||||||
ReleaseMutex( pvInterruptEventMutex );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -527,21 +527,17 @@ void vPortEnterCritical( void )
|
||||||
void vPortExitCritical( void )
|
void vPortExitCritical( void )
|
||||||
{
|
{
|
||||||
xThreadState *pxThreadState;
|
xThreadState *pxThreadState;
|
||||||
|
long lMutexNeedsReleasing;
|
||||||
|
|
||||||
|
/* The interrupt event mutex should already be held by this thread as it was
|
||||||
|
obtained on entry to the critical section. */
|
||||||
|
|
||||||
|
lMutexNeedsReleasing = pdTRUE;
|
||||||
|
|
||||||
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
|
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
|
||||||
{
|
{
|
||||||
if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
|
if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
|
||||||
{
|
{
|
||||||
/* Wait for the interrupt event mutex prior to manipulating or
|
|
||||||
testing the pseudo interrupt control variables. */
|
|
||||||
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
|
|
||||||
vPortTrace( "vPortExitCritical: Got interrupt event mutex\r\n" );
|
|
||||||
|
|
||||||
// ResumeThread( pvSimulatedTimerThread );
|
|
||||||
|
|
||||||
/* Now it is safe to decrement the critical nesting count as no
|
|
||||||
tick events will be processed until the interrupt event mutex is
|
|
||||||
given back. */
|
|
||||||
ulCriticalNesting--;
|
ulCriticalNesting--;
|
||||||
|
|
||||||
/* Were any interrupts set to pending while interrupts were
|
/* Were any interrupts set to pending while interrupts were
|
||||||
|
@ -550,33 +546,17 @@ xThreadState *pxThreadState;
|
||||||
{
|
{
|
||||||
SetEvent( pvInterruptEvent );
|
SetEvent( pvInterruptEvent );
|
||||||
|
|
||||||
/* The interrupt ack event should not be signaled yet - if it
|
|
||||||
is then there is an error in the logical simulation. */
|
|
||||||
if( WaitForSingleObject( pvInterruptAcknowledgeEvent, 0 ) != WAIT_TIMEOUT )
|
|
||||||
{
|
|
||||||
/* This line is for a break point only. */
|
|
||||||
__asm { NOP };
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The event handler needs to know to signal the interrupt
|
/* The event handler needs to know to signal the interrupt
|
||||||
acknowledge event the next time this task runs. */
|
acknowledge event the next time this task runs. */
|
||||||
pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
|
pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
|
||||||
pxThreadState->lWaitingInterruptAck = pdTRUE;
|
pxThreadState->lWaitingInterruptAck = pdTRUE;
|
||||||
|
|
||||||
|
/* Mutex will be released now, so does not require releasing
|
||||||
|
on function exit. */
|
||||||
|
lMutexNeedsReleasing = pdFALSE;
|
||||||
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
|
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
|
||||||
/* Give back the interrupt event mutex so the event can be processed. */
|
|
||||||
// ReleaseMutex( pvInterruptEventMutex );
|
|
||||||
|
|
||||||
// vPortTrace( "vPortExitCritical: Waiting interrupt ack\r\n" );
|
|
||||||
// WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
|
|
||||||
vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" );
|
vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Can't leave here without giving back the interrupt event
|
|
||||||
mutex. */
|
|
||||||
ReleaseMutex( pvInterruptEventMutex );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -585,4 +565,9 @@ xThreadState *pxThreadState;
|
||||||
ulCriticalNesting--;
|
ulCriticalNesting--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( lMutexNeedsReleasing == pdTRUE )
|
||||||
|
{
|
||||||
|
ReleaseMutex( pvInterruptEventMutex );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue