2 FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
28 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
29 >>! obliged to provide the source code for proprietary components !<<
\r
30 >>! outside of the FreeRTOS kernel. !<<
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
66 /* Standard includes. */
\r
69 /* Scheduler includes. */
\r
70 #include "FreeRTOS.h"
\r
74 #include "mmsystem.h"
\r
76 #pragma comment(lib, "winmm.lib")
\r
79 #define portMAX_INTERRUPTS ( ( uint32_t ) sizeof( uint32_t ) * 8UL ) /* The number of bits in an uint32_t. */
\r
80 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
\r
83 * Created as a high priority thread, this function uses a timer to simulate
\r
84 * a tick interrupt being generated on an embedded target. In this Windows
\r
85 * environment the timer does not achieve anything approaching real time
\r
86 * performance though.
\r
88 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
\r
91 * Process all the simulated interrupts - each represented by a bit in
\r
92 * ulPendingInterrupts variable.
\r
94 static void prvProcessSimulatedInterrupts( void );
\r
97 * Interrupt handlers used by the kernel itself. These are executed from the
\r
98 * simulated interrupt handler thread.
\r
100 static uint32_t prvProcessYieldInterrupt( void );
\r
101 static uint32_t prvProcessTickInterrupt( void );
\r
104 * Called when the process exits to let Windows know the high timer resolution
\r
105 * is no longer required.
\r
107 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType );
\r
109 /*-----------------------------------------------------------*/
\r
111 /* The WIN32 simulator runs each task in a thread. The context switching is
\r
112 managed by the threads, so the task stack does not have to be managed directly,
\r
113 although the task stack is still used to hold an xThreadState structure this is
\r
114 the only thing it will ever hold. The structure indirectly maps the task handle
\r
115 to a thread handle. */
\r
118 /* Handle of the thread that executes the task. */
\r
123 /* Simulated interrupts waiting to be processed. This is a bit mask where each
\r
124 bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
\r
125 static volatile uint32_t ulPendingInterrupts = 0UL;
\r
127 /* An event used to inform the simulated interrupt processing thread (a high
\r
128 priority thread that simulated interrupt processing) that an interrupt is
\r
130 static void *pvInterruptEvent = NULL;
\r
132 /* Mutex used to protect all the simulated interrupt variables that are accessed
\r
133 by multiple threads. */
\r
134 static void *pvInterruptEventMutex = NULL;
\r
136 /* The critical nesting count for the currently executing task. This is
\r
137 initialised to a non-zero value so interrupts do not become enabled during
\r
138 the initialisation phase. As each task has its own critical nesting value
\r
139 ulCriticalNesting will get set to zero when the first task runs. This
\r
140 initialisation is probably not critical in this simulated environment as the
\r
141 simulated interrupt handlers do not get created until the FreeRTOS scheduler is
\r
143 static uint32_t ulCriticalNesting = 9999UL;
\r
145 /* Handlers for all the simulated software interrupts. The first two positions
\r
146 are used for the Yield and Tick interrupts so are handled slightly differently,
\r
147 all the other interrupts can be user defined. */
\r
148 static uint32_t (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
\r
150 /* Pointer to the TCB of the currently executing task. */
\r
151 extern void *pxCurrentTCB;
\r
153 /* Used to ensure nothing is processed during the startup sequence. */
\r
154 static BaseType_t xPortRunning = pdFALSE;
\r
156 /*-----------------------------------------------------------*/
\r
158 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
\r
160 TickType_t xMinimumWindowsBlockTime;
\r
161 TIMECAPS xTimeCaps;
\r
163 /* Set the timer resolution to the maximum possible. */
\r
164 if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
\r
166 xMinimumWindowsBlockTime = ( TickType_t ) xTimeCaps.wPeriodMin;
\r
167 timeBeginPeriod( xTimeCaps.wPeriodMin );
\r
169 /* Register an exit handler so the timeBeginPeriod() function can be
\r
170 matched with a timeEndPeriod() when the application exits. */
\r
171 SetConsoleCtrlHandler( prvEndProcess, TRUE );
\r
175 xMinimumWindowsBlockTime = ( TickType_t ) 20;
\r
178 /* Just to prevent compiler warnings. */
\r
179 ( void ) lpParameter;
\r
183 /* Wait until the timer expires and we can access the simulated interrupt
\r
184 variables. *NOTE* this is not a 'real time' way of generating tick
\r
185 events as the next wake time should be relative to the previous wake
\r
186 time, not the time that Sleep() is called. It is done this way to
\r
187 prevent overruns in this very non real time simulated/emulated
\r
189 if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )
\r
191 Sleep( xMinimumWindowsBlockTime );
\r
195 Sleep( portTICK_PERIOD_MS );
\r
198 configASSERT( xPortRunning );
\r
200 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
202 /* The timer has expired, generate the simulated tick event. */
\r
203 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
205 /* The interrupt is now pending - notify the simulated interrupt
\r
207 if( ulCriticalNesting == 0 )
\r
209 SetEvent( pvInterruptEvent );
\r
212 /* Give back the mutex so the simulated interrupt handler unblocks
\r
213 and can access the interrupt handler variables. */
\r
214 ReleaseMutex( pvInterruptEventMutex );
\r
218 /* Should never reach here - MingW complains if you leave this line out,
\r
219 MSVC complains if you put it in. */
\r
223 /*-----------------------------------------------------------*/
\r
225 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType )
\r
227 TIMECAPS xTimeCaps;
\r
229 ( void ) dwCtrlType;
\r
231 if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
\r
233 /* Match the call to timeBeginPeriod( xTimeCaps.wPeriodMin ) made when
\r
234 the process started with a timeEndPeriod() as the process exits. */
\r
235 timeEndPeriod( xTimeCaps.wPeriodMin );
\r
240 /*-----------------------------------------------------------*/
\r
242 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
\r
244 xThreadState *pxThreadState = NULL;
\r
245 int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;
\r
247 /* In this simulated case a stack is not initialised, but instead a thread
\r
248 is created that will execute the task being created. The thread handles
\r
249 the context switching itself. The xThreadState object is placed onto
\r
250 the stack that was created for the task - so the stack buffer is still
\r
251 used, just not in the conventional way. It will not be used for anything
\r
252 other than holding this structure. */
\r
253 pxThreadState = ( xThreadState * ) ( pcTopOfStack - sizeof( xThreadState ) );
\r
255 /* Create the thread itself. */
\r
256 pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
\r
257 configASSERT( pxThreadState->pvThread );
\r
258 SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );
\r
259 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
260 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
\r
262 return ( StackType_t * ) pxThreadState;
\r
264 /*-----------------------------------------------------------*/
\r
266 BaseType_t xPortStartScheduler( void )
\r
269 int32_t lSuccess = pdPASS;
\r
270 xThreadState *pxThreadState;
\r
272 /* Install the interrupt handlers used by the scheduler itself. */
\r
273 vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );
\r
274 vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );
\r
276 /* Create the events and mutexes that are used to synchronise all the
\r
278 pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
\r
279 pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
281 if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )
\r
286 /* Set the priority of this thread such that it is above the priority of
\r
287 the threads that run tasks. This higher priority is required to ensure
\r
288 simulated interrupts take priority over tasks. */
\r
289 pvHandle = GetCurrentThread();
\r
290 if( pvHandle == NULL )
\r
295 if( lSuccess == pdPASS )
\r
297 if( SetThreadPriority( pvHandle, THREAD_PRIORITY_NORMAL ) == 0 )
\r
301 SetThreadPriorityBoost( pvHandle, TRUE );
\r
302 SetThreadAffinityMask( pvHandle, 0x01 );
\r
305 if( lSuccess == pdPASS )
\r
307 /* Start the thread that simulates the timer peripheral to generate
\r
308 tick interrupts. The priority is set below that of the simulated
\r
309 interrupt handler so the interrupt event mutex is used for the
\r
310 handshake / overrun protection. */
\r
311 pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );
\r
312 if( pvHandle != NULL )
\r
314 SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL );
\r
315 SetThreadPriorityBoost( pvHandle, TRUE );
\r
316 SetThreadAffinityMask( pvHandle, 0x01 );
\r
319 /* Start the highest priority task by obtaining its associated thread
\r
320 state structure, in which is stored the thread handle. */
\r
321 pxThreadState = ( xThreadState * ) *( ( uint32_t * ) pxCurrentTCB );
\r
322 ulCriticalNesting = portNO_CRITICAL_NESTING;
\r
324 /* Bump up the priority of the thread that is going to run, in the
\r
325 hope that this will assist in getting the Windows thread scheduler to
\r
326 behave as an embedded engineer might expect. */
\r
327 ResumeThread( pxThreadState->pvThread );
\r
329 /* Handle all simulated interrupts - including yield requests and
\r
330 simulated ticks. */
\r
331 prvProcessSimulatedInterrupts();
\r
334 /* Would not expect to return from prvProcessSimulatedInterrupts(), so should
\r
338 /*-----------------------------------------------------------*/
\r
340 static uint32_t prvProcessYieldInterrupt( void )
\r
344 /*-----------------------------------------------------------*/
\r
346 static uint32_t prvProcessTickInterrupt( void )
\r
348 uint32_t ulSwitchRequired;
\r
350 /* Process the tick itself. */
\r
351 configASSERT( xPortRunning );
\r
352 ulSwitchRequired = ( uint32_t ) xTaskIncrementTick();
\r
354 return ulSwitchRequired;
\r
356 /*-----------------------------------------------------------*/
\r
358 static void prvProcessSimulatedInterrupts( void )
\r
360 uint32_t ulSwitchRequired, i;
\r
361 xThreadState *pxThreadState;
\r
362 void *pvObjectList[ 2 ];
\r
364 /* Going to block on the mutex that ensured exclusive access to the simulated
\r
365 interrupt objects, and the event that signals that a simulated interrupt
\r
366 should be processed. */
\r
367 pvObjectList[ 0 ] = pvInterruptEventMutex;
\r
368 pvObjectList[ 1 ] = pvInterruptEvent;
\r
370 /* Create a pending tick to ensure the first task is started as soon as
\r
371 this thread pends. */
\r
372 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
373 SetEvent( pvInterruptEvent );
\r
375 xPortRunning = pdTRUE;
\r
379 WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
\r
381 /* Used to indicate whether the simulated interrupt processing has
\r
382 necessitated a context switch to another task/thread. */
\r
383 ulSwitchRequired = pdFALSE;
\r
385 /* For each interrupt we are interested in processing, each of which is
\r
386 represented by a bit in the 32bit ulPendingInterrupts variable. */
\r
387 for( i = 0; i < portMAX_INTERRUPTS; i++ )
\r
389 /* Is the simulated interrupt pending? */
\r
390 if( ulPendingInterrupts & ( 1UL << i ) )
\r
392 /* Is a handler installed? */
\r
393 if( ulIsrHandler[ i ] != NULL )
\r
395 /* Run the actual handler. */
\r
396 if( ulIsrHandler[ i ]() != pdFALSE )
\r
398 ulSwitchRequired |= ( 1 << i );
\r
402 /* Clear the interrupt pending bit. */
\r
403 ulPendingInterrupts &= ~( 1UL << i );
\r
407 if( ulSwitchRequired != pdFALSE )
\r
409 void *pvOldCurrentTCB;
\r
411 pvOldCurrentTCB = pxCurrentTCB;
\r
413 /* Select the next task to run. */
\r
414 vTaskSwitchContext();
\r
416 /* If the task selected to enter the running state is not the task
\r
417 that is already in the running state. */
\r
418 if( pvOldCurrentTCB != pxCurrentTCB )
\r
420 /* Suspend the old thread. */
\r
421 pxThreadState = ( xThreadState *) *( ( uint32_t * ) pvOldCurrentTCB );
\r
422 SuspendThread( pxThreadState->pvThread );
\r
424 /* Obtain the state of the task now selected to enter the
\r
426 pxThreadState = ( xThreadState * ) ( *( uint32_t *) pxCurrentTCB );
\r
427 ResumeThread( pxThreadState->pvThread );
\r
431 ReleaseMutex( pvInterruptEventMutex );
\r
434 /*-----------------------------------------------------------*/
\r
436 void vPortDeleteThread( void *pvTaskToDelete )
\r
438 xThreadState *pxThreadState;
\r
439 uint32_t ulErrorCode;
\r
441 /* Remove compiler warnings if configASSERT() is not defined. */
\r
442 ( void ) ulErrorCode;
\r
444 /* Find the handle of the thread being deleted. */
\r
445 pxThreadState = ( xThreadState * ) ( *( uint32_t *) pvTaskToDelete );
\r
447 /* Check that the thread is still valid, it might have been closed by
\r
448 vPortCloseRunningThread() - which will be the case if the task associated
\r
449 with the thread originally deleted itself rather than being deleted by a
\r
451 if( pxThreadState->pvThread != NULL )
\r
453 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
455 ulErrorCode = TerminateThread( pxThreadState->pvThread, 0 );
\r
456 configASSERT( ulErrorCode );
\r
458 ulErrorCode = CloseHandle( pxThreadState->pvThread );
\r
459 configASSERT( ulErrorCode );
\r
461 ReleaseMutex( pvInterruptEventMutex );
\r
464 /*-----------------------------------------------------------*/
\r
466 void vPortCloseRunningThread( void *pvTaskToDelete, volatile BaseType_t *pxPendYield )
\r
468 xThreadState *pxThreadState;
\r
470 uint32_t ulErrorCode;
\r
472 /* Remove compiler warnings if configASSERT() is not defined. */
\r
473 ( void ) ulErrorCode;
\r
475 /* Find the handle of the thread being deleted. */
\r
476 pxThreadState = ( xThreadState * ) ( *( uint32_t *) pvTaskToDelete );
\r
477 pvThread = pxThreadState->pvThread;
\r
479 /* Raise the Windows priority of the thread to ensure the FreeRTOS scheduler
\r
480 does not run and swap it out before it is closed. If that were to happen
\r
481 the thread would never run again and effectively be a thread handle and
\r
483 SetThreadPriority( pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
\r
485 /* This function will not return, therefore a yield is set as pending to
\r
486 ensure a context switch occurs away from this thread on the next tick. */
\r
487 *pxPendYield = pdTRUE;
\r
489 /* Mark the thread associated with this task as invalid so
\r
490 vPortDeleteThread() does not try to terminate it. */
\r
491 pxThreadState->pvThread = NULL;
\r
493 /* Close the thread. */
\r
494 ulErrorCode = CloseHandle( pvThread );
\r
495 configASSERT( ulErrorCode );
\r
499 /*-----------------------------------------------------------*/
\r
501 void vPortEndScheduler( void )
\r
503 /* This function IS NOT TESTED! */
\r
504 TerminateProcess( GetCurrentProcess(), 0 );
\r
506 /*-----------------------------------------------------------*/
\r
508 void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )
\r
510 configASSERT( xPortRunning );
\r
512 if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
\r
514 /* Yield interrupts are processed even when critical nesting is non-zero. */
\r
515 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
516 ulPendingInterrupts |= ( 1 << ulInterruptNumber );
\r
518 /* The simulated interrupt is now held pending, but don't actually process it
\r
519 yet if this call is within a critical section. It is possible for this to
\r
520 be in a critical section as calls to wait for mutexes are accumulative. */
\r
521 if( ulCriticalNesting == 0 )
\r
523 SetEvent( pvInterruptEvent );
\r
526 ReleaseMutex( pvInterruptEventMutex );
\r
529 /*-----------------------------------------------------------*/
\r
531 void vPortSetInterruptHandler( uint32_t ulInterruptNumber, uint32_t (*pvHandler)( void ) )
\r
533 if( ulInterruptNumber < portMAX_INTERRUPTS )
\r
535 if( pvInterruptEventMutex != NULL )
\r
537 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
538 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
539 ReleaseMutex( pvInterruptEventMutex );
\r
543 ulIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
547 /*-----------------------------------------------------------*/
\r
549 void vPortEnterCritical( void )
\r
551 if( xPortRunning == pdTRUE )
\r
553 /* The interrupt event mutex is held for the entire critical section,
\r
554 effectively disabling (simulated) interrupts. */
\r
555 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
556 ulCriticalNesting++;
\r
560 ulCriticalNesting++;
\r
563 /*-----------------------------------------------------------*/
\r
565 void vPortExitCritical( void )
\r
567 int32_t lMutexNeedsReleasing;
\r
569 /* The interrupt event mutex should already be held by this thread as it was
\r
570 obtained on entry to the critical section. */
\r
572 lMutexNeedsReleasing = pdTRUE;
\r
574 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
576 if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
\r
578 ulCriticalNesting--;
\r
580 /* Were any interrupts set to pending while interrupts were
\r
581 (simulated) disabled? */
\r
582 if( ulPendingInterrupts != 0UL )
\r
584 configASSERT( xPortRunning );
\r
585 SetEvent( pvInterruptEvent );
\r
587 /* Mutex will be released now, so does not require releasing
\r
588 on function exit. */
\r
589 lMutexNeedsReleasing = pdFALSE;
\r
590 ReleaseMutex( pvInterruptEventMutex );
\r
595 /* Tick interrupts will still not be processed as the critical
\r
596 nesting depth will not be zero. */
\r
597 ulCriticalNesting--;
\r
601 if( pvInterruptEventMutex != NULL )
\r
603 if( lMutexNeedsReleasing == pdTRUE )
\r
605 configASSERT( xPortRunning );
\r
606 ReleaseMutex( pvInterruptEventMutex );
\r
610 /*-----------------------------------------------------------*/
\r