2 FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
70 /* Standard includes. */
\r
73 /* Scheduler includes. */
\r
74 #include "FreeRTOS.h"
\r
78 #include "mmsystem.h"
\r
80 #pragma comment(lib, "winmm.lib")
\r
83 #define portMAX_INTERRUPTS ( ( uint32_t ) sizeof( uint32_t ) * 8UL ) /* The number of bits in an uint32_t. */
\r
84 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
\r
86 /* The priorities at which the various components of the simulation execute. */
\r
87 #define portDELETE_SELF_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL /* Must be highest. */
\r
88 #define portSIMULATED_INTERRUPTS_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
\r
89 #define portSIMULATED_TIMER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
\r
90 #define portTASK_THREAD_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
\r
93 * Created as a high priority thread, this function uses a timer to simulate
\r
94 * a tick interrupt being generated on an embedded target. In this Windows
\r
95 * environment the timer does not achieve anything approaching real time
\r
96 * performance though.
\r
98 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
\r
101 * Process all the simulated interrupts - each represented by a bit in
\r
102 * ulPendingInterrupts variable.
\r
104 static void prvProcessSimulatedInterrupts( void );
\r
107 * Interrupt handlers used by the kernel itself. These are executed from the
\r
108 * simulated interrupt handler thread.
\r
110 static uint32_t prvProcessYieldInterrupt( void );
\r
111 static uint32_t prvProcessTickInterrupt( void );
\r
114 * Called when the process exits to let Windows know the high timer resolution
\r
115 * is no longer required.
\r
117 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType );
\r
119 /*-----------------------------------------------------------*/
\r
121 /* The WIN32 simulator runs each task in a thread. The context switching is
\r
122 managed by the threads, so the task stack does not have to be managed directly,
\r
123 although the task stack is still used to hold an xThreadState structure this is
\r
124 the only thing it will ever hold. The structure indirectly maps the task handle
\r
125 to a thread handle. */
\r
128 /* Handle of the thread that executes the task. */
\r
133 /* Simulated interrupts waiting to be processed. This is a bit mask where each
\r
134 bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
\r
135 static volatile uint32_t ulPendingInterrupts = 0UL;
\r
137 /* An event used to inform the simulated interrupt processing thread (a high
\r
138 priority thread that simulated interrupt processing) that an interrupt is
\r
140 static void *pvInterruptEvent = NULL;
\r
142 /* Mutex used to protect all the simulated interrupt variables that are accessed
\r
143 by multiple threads. */
\r
144 static void *pvInterruptEventMutex = NULL;
\r
146 /* The critical nesting count for the currently executing task. This is
\r
147 initialised to a non-zero value so interrupts do not become enabled during
\r
148 the initialisation phase. As each task has its own critical nesting value
\r
149 ulCriticalNesting will get set to zero when the first task runs. This
\r
150 initialisation is probably not critical in this simulated environment as the
\r
151 simulated interrupt handlers do not get created until the FreeRTOS scheduler is
\r
153 static uint32_t ulCriticalNesting = 9999UL;
\r
155 /* Handlers for all the simulated software interrupts. The first two positions
\r
156 are used for the Yield and Tick interrupts so are handled slightly differently,
\r
157 all the other interrupts can be user defined. */
\r
158 static uint32_t (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
\r
160 /* Pointer to the TCB of the currently executing task. */
\r
161 extern void *pxCurrentTCB;
\r
163 /* Used to ensure nothing is processed during the startup sequence. */
\r
164 static BaseType_t xPortRunning = pdFALSE;
\r
166 /*-----------------------------------------------------------*/
\r
168 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
\r
170 TickType_t xMinimumWindowsBlockTime;
\r
171 TIMECAPS xTimeCaps;
\r
173 /* Set the timer resolution to the maximum possible. */
\r
174 if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
\r
176 xMinimumWindowsBlockTime = ( TickType_t ) xTimeCaps.wPeriodMin;
\r
177 timeBeginPeriod( xTimeCaps.wPeriodMin );
\r
179 /* Register an exit handler so the timeBeginPeriod() function can be
\r
180 matched with a timeEndPeriod() when the application exits. */
\r
181 SetConsoleCtrlHandler( prvEndProcess, TRUE );
\r
185 xMinimumWindowsBlockTime = ( TickType_t ) 20;
\r
188 /* Just to prevent compiler warnings. */
\r
189 ( void ) lpParameter;
\r
193 /* Wait until the timer expires and we can access the simulated interrupt
\r
194 variables. *NOTE* this is not a 'real time' way of generating tick
\r
195 events as the next wake time should be relative to the previous wake
\r
196 time, not the time that Sleep() is called. It is done this way to
\r
197 prevent overruns in this very non real time simulated/emulated
\r
199 if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )
\r
201 Sleep( xMinimumWindowsBlockTime );
\r
205 Sleep( portTICK_PERIOD_MS );
\r
208 configASSERT( xPortRunning );
\r
210 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
212 /* The timer has expired, generate the simulated tick event. */
\r
213 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
215 /* The interrupt is now pending - notify the simulated interrupt
\r
217 if( ulCriticalNesting == 0 )
\r
219 SetEvent( pvInterruptEvent );
\r
222 /* Give back the mutex so the simulated interrupt handler unblocks
\r
223 and can access the interrupt handler variables. */
\r
224 ReleaseMutex( pvInterruptEventMutex );
\r
228 /* Should never reach here - MingW complains if you leave this line out,
\r
229 MSVC complains if you put it in. */
\r
233 /*-----------------------------------------------------------*/
\r
235 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType )
\r
237 TIMECAPS xTimeCaps;
\r
239 ( void ) dwCtrlType;
\r
241 if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
\r
243 /* Match the call to timeBeginPeriod( xTimeCaps.wPeriodMin ) made when
\r
244 the process started with a timeEndPeriod() as the process exits. */
\r
245 timeEndPeriod( xTimeCaps.wPeriodMin );
\r
250 /*-----------------------------------------------------------*/
\r
252 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
\r
254 xThreadState *pxThreadState = NULL;
\r
255 int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;
\r
256 const SIZE_T xStackSize = 1024; /* Set the size to a small number which will get rounded up to the minimum possible. */
\r
258 /* In this simulated case a stack is not initialised, but instead a thread
\r
259 is created that will execute the task being created. The thread handles
\r
260 the context switching itself. The xThreadState object is placed onto
\r
261 the stack that was created for the task - so the stack buffer is still
\r
262 used, just not in the conventional way. It will not be used for anything
\r
263 other than holding this structure. */
\r
264 pxThreadState = ( xThreadState * ) ( pcTopOfStack - sizeof( xThreadState ) );
\r
266 /* Create the thread itself. */
\r
267 pxThreadState->pvThread = CreateThread( NULL, xStackSize, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, NULL );
\r
268 configASSERT( pxThreadState->pvThread ); /* See comment where TerminateThread() is called. */
\r
269 SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );
\r
270 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
271 SetThreadPriority( pxThreadState->pvThread, portTASK_THREAD_PRIORITY );
\r
273 return ( StackType_t * ) pxThreadState;
\r
275 /*-----------------------------------------------------------*/
\r
277 BaseType_t xPortStartScheduler( void )
\r
279 void *pvHandle = NULL;
\r
281 xThreadState *pxThreadState = NULL;
\r
282 SYSTEM_INFO xSystemInfo;
\r
284 /* This port runs windows threads with extremely high priority. All the
\r
285 threads execute on the same core - to prevent locking up the host only start
\r
286 if the host has multiple cores. */
\r
287 GetSystemInfo( &xSystemInfo );
\r
288 if( xSystemInfo.dwNumberOfProcessors <= 1 )
\r
290 printf( "This version of the FreeRTOS Windows port can only be used on multi-core hosts.\r\n" );
\r
297 /* The highest priority class is used to [try to] prevent other Windows
\r
298 activity interfering with FreeRTOS timing too much. */
\r
299 if( SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) == 0 )
\r
301 printf( "SetPriorityClass() failed\r\n" );
\r
304 /* Install the interrupt handlers used by the scheduler itself. */
\r
305 vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );
\r
306 vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );
\r
308 /* Create the events and mutexes that are used to synchronise all the
\r
310 pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
\r
311 pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
313 if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )
\r
318 /* Set the priority of this thread such that it is above the priority of
\r
319 the threads that run tasks. This higher priority is required to ensure
\r
320 simulated interrupts take priority over tasks. */
\r
321 pvHandle = GetCurrentThread();
\r
322 if( pvHandle == NULL )
\r
328 if( lSuccess == pdPASS )
\r
330 if( SetThreadPriority( pvHandle, portSIMULATED_INTERRUPTS_THREAD_PRIORITY ) == 0 )
\r
334 SetThreadPriorityBoost( pvHandle, TRUE );
\r
335 SetThreadAffinityMask( pvHandle, 0x01 );
\r
338 if( lSuccess == pdPASS )
\r
340 /* Start the thread that simulates the timer peripheral to generate
\r
341 tick interrupts. The priority is set below that of the simulated
\r
342 interrupt handler so the interrupt event mutex is used for the
\r
343 handshake / overrun protection. */
\r
344 pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, CREATE_SUSPENDED, NULL );
\r
345 if( pvHandle != NULL )
\r
347 SetThreadPriority( pvHandle, portSIMULATED_TIMER_THREAD_PRIORITY );
\r
348 SetThreadPriorityBoost( pvHandle, TRUE );
\r
349 SetThreadAffinityMask( pvHandle, 0x01 );
\r
350 ResumeThread( pvHandle );
\r
353 /* Start the highest priority task by obtaining its associated thread
\r
354 state structure, in which is stored the thread handle. */
\r
355 pxThreadState = ( xThreadState * ) *( ( size_t * ) pxCurrentTCB );
\r
356 ulCriticalNesting = portNO_CRITICAL_NESTING;
\r
358 /* Bump up the priority of the thread that is going to run, in the
\r
359 hope that this will assist in getting the Windows thread scheduler to
\r
360 behave as an embedded engineer might expect. */
\r
361 ResumeThread( pxThreadState->pvThread );
\r
363 /* Handle all simulated interrupts - including yield requests and
\r
364 simulated ticks. */
\r
365 prvProcessSimulatedInterrupts();
\r
368 /* Would not expect to return from prvProcessSimulatedInterrupts(), so should
\r
372 /*-----------------------------------------------------------*/
\r
374 static uint32_t prvProcessYieldInterrupt( void )
\r
378 /*-----------------------------------------------------------*/
\r
380 static uint32_t prvProcessTickInterrupt( void )
\r
382 uint32_t ulSwitchRequired;
\r
384 /* Process the tick itself. */
\r
385 configASSERT( xPortRunning );
\r
386 ulSwitchRequired = ( uint32_t ) xTaskIncrementTick();
\r
388 return ulSwitchRequired;
\r
390 /*-----------------------------------------------------------*/
\r
392 static void prvProcessSimulatedInterrupts( void )
\r
394 uint32_t ulSwitchRequired, i;
\r
395 xThreadState *pxThreadState;
\r
396 void *pvObjectList[ 2 ];
\r
399 /* Going to block on the mutex that ensured exclusive access to the simulated
\r
400 interrupt objects, and the event that signals that a simulated interrupt
\r
401 should be processed. */
\r
402 pvObjectList[ 0 ] = pvInterruptEventMutex;
\r
403 pvObjectList[ 1 ] = pvInterruptEvent;
\r
405 /* Create a pending tick to ensure the first task is started as soon as
\r
406 this thread pends. */
\r
407 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
408 SetEvent( pvInterruptEvent );
\r
410 xPortRunning = pdTRUE;
\r
414 WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
\r
416 /* Used to indicate whether the simulated interrupt processing has
\r
417 necessitated a context switch to another task/thread. */
\r
418 ulSwitchRequired = pdFALSE;
\r
420 /* For each interrupt we are interested in processing, each of which is
\r
421 represented by a bit in the 32bit ulPendingInterrupts variable. */
\r
422 for( i = 0; i < portMAX_INTERRUPTS; i++ )
\r
424 /* Is the simulated interrupt pending? */
\r
425 if( ulPendingInterrupts & ( 1UL << i ) )
\r
427 /* Is a handler installed? */
\r
428 if( ulIsrHandler[ i ] != NULL )
\r
430 /* Run the actual handler. */
\r
431 if( ulIsrHandler[ i ]() != pdFALSE )
\r
433 ulSwitchRequired |= ( 1 << i );
\r
437 /* Clear the interrupt pending bit. */
\r
438 ulPendingInterrupts &= ~( 1UL << i );
\r
442 if( ulSwitchRequired != pdFALSE )
\r
444 void *pvOldCurrentTCB;
\r
446 pvOldCurrentTCB = pxCurrentTCB;
\r
448 /* Select the next task to run. */
\r
449 vTaskSwitchContext();
\r
451 /* If the task selected to enter the running state is not the task
\r
452 that is already in the running state. */
\r
453 if( pvOldCurrentTCB != pxCurrentTCB )
\r
455 /* Suspend the old thread. */
\r
456 pxThreadState = ( xThreadState *) *( ( size_t * ) pvOldCurrentTCB );
\r
457 SuspendThread( pxThreadState->pvThread );
\r
459 /* Ensure the thread is actually suspended by performing a
\r
460 synchronous operation that can only complete when the thread is
\r
461 actually suspended. The below code asks for dummy register
\r
463 xContext.ContextFlags = CONTEXT_INTEGER;
\r
464 ( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
\r
466 /* Obtain the state of the task now selected to enter the
\r
468 pxThreadState = ( xThreadState * ) ( *( size_t *) pxCurrentTCB );
\r
469 ResumeThread( pxThreadState->pvThread );
\r
473 ReleaseMutex( pvInterruptEventMutex );
\r
476 /*-----------------------------------------------------------*/
\r
478 void vPortDeleteThread( void *pvTaskToDelete )
\r
480 xThreadState *pxThreadState;
\r
481 uint32_t ulErrorCode;
\r
483 /* Remove compiler warnings if configASSERT() is not defined. */
\r
484 ( void ) ulErrorCode;
\r
486 /* Find the handle of the thread being deleted. */
\r
487 pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );
\r
489 /* Check that the thread is still valid, it might have been closed by
\r
490 vPortCloseRunningThread() - which will be the case if the task associated
\r
491 with the thread originally deleted itself rather than being deleted by a
\r
493 if( pxThreadState->pvThread != NULL )
\r
495 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
497 /* !!! This is not a nice way to terminate a thread, and will eventually
\r
498 result in resources being depleted if tasks frequently delete other
\r
499 tasks (rather than deleting themselves) as the task stacks will not be
\r
501 ulErrorCode = TerminateThread( pxThreadState->pvThread, 0 );
\r
502 configASSERT( ulErrorCode );
\r
504 ulErrorCode = CloseHandle( pxThreadState->pvThread );
\r
505 configASSERT( ulErrorCode );
\r
507 ReleaseMutex( pvInterruptEventMutex );
\r
510 /*-----------------------------------------------------------*/
\r
512 void vPortCloseRunningThread( void *pvTaskToDelete, volatile BaseType_t *pxPendYield )
\r
514 xThreadState *pxThreadState;
\r
516 uint32_t ulErrorCode;
\r
518 /* Remove compiler warnings if configASSERT() is not defined. */
\r
519 ( void ) ulErrorCode;
\r
521 /* Find the handle of the thread being deleted. */
\r
522 pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );
\r
523 pvThread = pxThreadState->pvThread;
\r
525 /* Raise the Windows priority of the thread to ensure the FreeRTOS scheduler
\r
526 does not run and swap it out before it is closed. If that were to happen
\r
527 the thread would never run again and effectively be a thread handle and
\r
529 SetThreadPriority( pvThread, portDELETE_SELF_THREAD_PRIORITY );
\r
531 /* This function will not return, therefore a yield is set as pending to
\r
532 ensure a context switch occurs away from this thread on the next tick. */
\r
533 *pxPendYield = pdTRUE;
\r
535 /* Mark the thread associated with this task as invalid so
\r
536 vPortDeleteThread() does not try to terminate it. */
\r
537 pxThreadState->pvThread = NULL;
\r
539 /* Close the thread. */
\r
540 ulErrorCode = CloseHandle( pvThread );
\r
541 configASSERT( ulErrorCode );
\r
543 /* This is called from a critical section, which must be exited before the
\r
545 taskEXIT_CRITICAL();
\r
549 /*-----------------------------------------------------------*/
\r
551 void vPortEndScheduler( void )
\r
553 /* This function IS NOT TESTED! */
\r
554 TerminateProcess( GetCurrentProcess(), 0 );
\r
556 /*-----------------------------------------------------------*/
\r
558 void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )
\r
560 configASSERT( xPortRunning );
\r
562 if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
\r
564 /* Yield interrupts are processed even when critical nesting is
\r
566 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
567 ulPendingInterrupts |= ( 1 << ulInterruptNumber );
\r
569 /* The simulated interrupt is now held pending, but don't actually
\r
570 process it yet if this call is within a critical section. It is
\r
571 possible for this to be in a critical section as calls to wait for
\r
572 mutexes are accumulative. */
\r
573 if( ulCriticalNesting == 0 )
\r
575 SetEvent( pvInterruptEvent );
\r
578 ReleaseMutex( pvInterruptEventMutex );
\r
581 /*-----------------------------------------------------------*/
\r
583 void vPortSetInterruptHandler( uint32_t ulInterruptNumber, uint32_t (*pvHandler)( void ) )
\r
585 if( ulInterruptNumber < portMAX_INTERRUPTS )
\r
587 if( pvInterruptEventMutex != NULL )
\r
589 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
590 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
591 ReleaseMutex( pvInterruptEventMutex );
\r
595 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
599 /*-----------------------------------------------------------*/
\r
601 void vPortEnterCritical( void )
\r
603 if( xPortRunning == pdTRUE )
\r
605 /* The interrupt event mutex is held for the entire critical section,
\r
606 effectively disabling (simulated) interrupts. */
\r
607 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
608 ulCriticalNesting++;
\r
612 ulCriticalNesting++;
\r
615 /*-----------------------------------------------------------*/
\r
617 void vPortExitCritical( void )
\r
619 int32_t lMutexNeedsReleasing;
\r
621 /* The interrupt event mutex should already be held by this thread as it was
\r
622 obtained on entry to the critical section. */
\r
624 lMutexNeedsReleasing = pdTRUE;
\r
626 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
628 if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
\r
630 ulCriticalNesting--;
\r
632 /* Were any interrupts set to pending while interrupts were
\r
633 (simulated) disabled? */
\r
634 if( ulPendingInterrupts != 0UL )
\r
636 configASSERT( xPortRunning );
\r
637 SetEvent( pvInterruptEvent );
\r
639 /* Mutex will be released now, so does not require releasing
\r
640 on function exit. */
\r
641 lMutexNeedsReleasing = pdFALSE;
\r
642 ReleaseMutex( pvInterruptEventMutex );
\r
647 /* Tick interrupts will still not be processed as the critical
\r
648 nesting depth will not be zero. */
\r
649 ulCriticalNesting--;
\r
653 if( pvInterruptEventMutex != NULL )
\r
655 if( lMutexNeedsReleasing == pdTRUE )
\r
657 configASSERT( xPortRunning );
\r
658 ReleaseMutex( pvInterruptEventMutex );
\r
662 /*-----------------------------------------------------------*/
\r