2 FreeRTOS V6.1.0 - Copyright (C) 2010 Real Time Engineers Ltd.
\r
4 ***************************************************************************
\r
8 * + New to FreeRTOS, *
\r
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
\r
10 * + Looking for basic training, *
\r
11 * + Wanting to improve your FreeRTOS skills and productivity *
\r
13 * then take a look at the FreeRTOS books - available as PDF or paperback *
\r
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
\r
16 * http://www.FreeRTOS.org/Documentation *
\r
18 * A pdf reference manual is also available. Both are usually delivered *
\r
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
\r
20 * and 8pm GMT (although please allow up to 24 hours in case of *
\r
21 * exceptional circumstances). Thank you for your support! *
\r
23 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
\r
31 a combined work that includes FreeRTOS without being obliged to provide the
\r
32 source code for proprietary components outside of the FreeRTOS kernel.
\r
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
54 /* Scheduler includes. */
\r
55 #include "FreeRTOS.h"
\r
59 #define portMAX_INTERRUPTS ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */
\r
60 #define portNO_CRITICAL_NESTING ( ( unsigned long ) 0 )
\r
63 * Created as a high priority thread, this function uses a timer to simulate
\r
64 * a tick interrupt being generated on an embedded target. In this Windows
\r
65 * environment the timer does not achieve anything approaching real time
\r
66 * performance though.
\r
68 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
\r
71 * Process all the simulated interrupts - each represented by a bit in
\r
72 * ulPendingInterrupts variable.
\r
74 static void prvProcessPseudoInterrupts( void );
\r
76 /*-----------------------------------------------------------*/
\r
78 /* The WIN32 simulator runs each task in a thread. The context switching is
\r
79 managed by the threads, so the task stack does not have to be managed directly,
\r
80 although the task stack is still used to hold an xThreadState structure this is
\r
81 the only thing it will ever hold. The structure indirectly maps the task handle
\r
82 to a thread handle. */
\r
85 /* Set to true if the task run by the thread yielded control to the pseudo
\r
86 interrupt handler manually - either by yielding or when exiting a critical
\r
87 section while pseudo interrupts were pending. */
\r
88 long lWaitingInterruptAck;
\r
90 /* Handle of the thread that executes the task. */
\r
93 /* Used to check that the thread that is supposed to be running in indeed
\r
94 the thread that is running. */
\r
95 unsigned long ulThreadId;
\r
99 /* Pseudo interrupts waiting to be processed. This is a bit mask where each
\r
100 bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
\r
101 static volatile unsigned long ulPendingInterrupts = 0UL;
\r
103 /* An event used to inform the pseudo interrupt processing thread (a high
\r
104 priority thread that simulated interrupt processing) that an interrupt is
\r
106 static void *pvInterruptEvent = NULL;
\r
108 /* Mutex used to protect all the pseudo interrupt variables that are accessed
\r
109 by multiple threads. */
\r
110 static void *pvInterruptEventMutex = NULL;
\r
112 /* Events used to manage sequencing. */
\r
113 static void *pvTickAcknowledgeEvent = NULL, *pvInterruptAcknowledgeEvent = NULL;
\r
115 /* The critical nesting count for the currently executing task. This is
\r
116 initialised to a non-zero value so interrupts do not become enabled during
\r
117 the initialisation phase. As each task has its own critical nesting value
\r
118 ulCriticalNesting will get set to zero when the first task runs. This
\r
119 initialisation is probably not critical in this simulated environment as the
\r
120 pseudo interrupt handlers do not get created until the FreeRTOS scheduler is
\r
122 static unsigned long ulCriticalNesting = 9999UL;
\r
124 /* Handlers for all the simulated software interrupts. The first two positions
\r
125 are used for the Yield and Tick interrupts so are handled slightly differently,
\r
126 all the other interrupts can be user defined. */
\r
127 static void (*vIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
\r
129 /* Pointer to the TCB of the currently executing task. */
\r
130 extern void *pxCurrentTCB;
\r
132 /*-----------------------------------------------------------*/
\r
134 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
\r
136 /* Just to prevent compiler warnings. */
\r
137 ( void ) lpParameter;
\r
141 /* Wait until the timer expires and we can access the pseudo interrupt
\r
142 variables. *NOTE* this is not a 'real time' way of generating tick
\r
143 events as the next wake time should be relative to the previous wake
\r
144 time, not the time that Sleep() is called. It is done this way to
\r
145 prevent overruns in this very non real time simulated/emulated
\r
147 Sleep( portTICK_RATE_MS );
\r
149 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
151 /* A thread will hold the interrupt event mutex while in a critical
\r
152 section, so ulCriticalSection should be zero for this tick event to be
\r
154 if( ulCriticalNesting != 0 )
\r
156 /* For a break point only. */
\r
160 /* The timer has expired, generate the simulated tick event. */
\r
161 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
\r
163 /* The interrupt is now pending - notify the simulated interrupt
\r
165 SetEvent( pvInterruptEvent );
\r
167 /* Give back the mutex so the pseudo interrupt handler unblocks
\r
168 and can access the interrupt handler variables. This high priority
\r
169 task will then loop back round after waiting for the lower priority
\r
170 pseudo interrupt handler thread to acknowledge the tick. */
\r
171 SignalObjectAndWait( pvInterruptEventMutex, pvTickAcknowledgeEvent, INFINITE, FALSE );
\r
174 /*-----------------------------------------------------------*/
\r
176 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
178 xThreadState *pxThreadState = NULL;
\r
180 /* In this simulated case a stack is not initialised, but instead a thread
\r
181 is created that will execute the task being created. The thread handles
\r
182 the context switching itself. The xThreadState object is placed onto
\r
183 the stack that was created for the task - so the stack buffer is still
\r
184 used, just not in the conventional way. It will not be used for anything
\r
185 other than holding this structure. */
\r
186 pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );
\r
188 /* Create the thread itself. */
\r
189 pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, &( pxThreadState->ulThreadId ) );
\r
190 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
191 pxThreadState->lWaitingInterruptAck = pdFALSE;
\r
192 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
\r
194 return ( portSTACK_TYPE * ) pxThreadState;
\r
196 /*-----------------------------------------------------------*/
\r
198 portBASE_TYPE xPortStartScheduler( void )
\r
201 long lSuccess = pdPASS;
\r
202 xThreadState *pxThreadState;
\r
204 /* Create the events and mutexes that are used to synchronise all the
\r
206 pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
\r
207 pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
208 pvTickAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
209 pvInterruptAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
211 if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) || ( pvTickAcknowledgeEvent == NULL ) || ( pvInterruptAcknowledgeEvent == NULL ) )
\r
216 /* Set the priority of this thread such that it is above the priority of
\r
217 the threads that run tasks. This higher priority is required to ensure
\r
218 pseudo interrupts take priority over tasks. */
\r
219 SetPriorityClass( GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS );
\r
220 pvHandle = GetCurrentThread();
\r
221 if( pvHandle == NULL )
\r
226 if( lSuccess == pdPASS )
\r
228 if( SetThreadPriority( pvHandle, THREAD_PRIORITY_HIGHEST ) == 0 )
\r
232 SetThreadPriorityBoost( pvHandle, TRUE );
\r
235 if( lSuccess == pdPASS )
\r
237 /* Start the thread that simulates the timer peripheral to generate
\r
238 tick interrupts. */
\r
239 pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );
\r
240 if( pvHandle != NULL )
\r
242 SetThreadPriority( pvHandle, THREAD_PRIORITY_HIGHEST );
\r
243 SetThreadPriorityBoost( pvHandle, TRUE );
\r
246 /* Start the highest priority task by obtaining its associated thread
\r
247 state structure, in which is stored the thread handle. */
\r
248 pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
\r
249 ulCriticalNesting = portNO_CRITICAL_NESTING;
\r
251 /* Bump up the priority of the thread that is going to run, in the
\r
252 hope that this will asist in getting the Windows thread scheduler to
\r
253 behave as an embedded engineer might expect. */
\r
254 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
\r
255 ResumeThread( pxThreadState->pvThread );
\r
257 /* Handle all pseudo interrupts - including yield requests and
\r
258 simulated ticks. */
\r
259 prvProcessPseudoInterrupts();
\r
262 /* Would not expect to return from prvProcessPseudoInterrupts(), so should
\r
266 /*-----------------------------------------------------------*/
\r
268 static void prvProcessPseudoInterrupts( void )
\r
270 long lSwitchRequired;
\r
271 xThreadState *pxThreadState;
\r
272 void *pvObjectList[ 2 ];
\r
275 /* Going to block on the mutex that ensured exclusive access to the pseudo
\r
276 interrupt objects, and the event that signals that a pseudo interrupt
\r
277 should be processed. */
\r
278 pvObjectList[ 0 ] = pvInterruptEventMutex;
\r
279 pvObjectList[ 1 ] = pvInterruptEvent;
\r
283 WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
\r
285 /* A thread will hold the interrupt event mutex while in a critical
\r
286 section, so this pseudo interrupt handler should only run when
\r
287 critical nesting is zero. */
\r
288 if( ulCriticalNesting != 0 )
\r
290 /* For a break point only. */
\r
294 /* Used to indicate whether the pseudo interrupt processing has
\r
295 necessitated a context switch to another task/thread. */
\r
296 lSwitchRequired = pdFALSE;
\r
298 /* For each interrupt we are interested in processing, each of which is
\r
299 represented by a bit in the 32bit ulPendingInterrupts variable. */
\r
300 for( i = 0; i < portMAX_INTERRUPTS; i++ )
\r
302 /* Is the pseudo interrupt pending? */
\r
303 if( ulPendingInterrupts & ( 1UL << i ) )
\r
307 case portINTERRUPT_YIELD:
\r
309 lSwitchRequired = pdTRUE;
\r
311 /* Clear the interrupt pending bit. */
\r
312 ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD );
\r
315 case portINTERRUPT_TICK:
\r
317 /* Process the tick itself. */
\r
318 vTaskIncrementTick();
\r
319 #if( configUSE_PREEMPTION != 0 )
\r
321 /* A context switch is only automatically
\r
322 performed from the tick interrupt if the
\r
323 pre-emptive scheduler is being used. */
\r
324 lSwitchRequired = pdTRUE;
\r
328 /* Clear the interrupt pending bit. */
\r
329 ulPendingInterrupts &= ~( 1UL << portINTERRUPT_TICK );
\r
330 SetEvent( pvTickAcknowledgeEvent );
\r
335 /* Is a handler installed? */
\r
336 if( vIsrHandler[ i ] != NULL )
\r
338 lSwitchRequired = pdTRUE;
\r
340 /* Run the actual handler. */
\r
341 vIsrHandler[ i ]();
\r
343 /* Clear the interrupt pending bit. */
\r
344 ulPendingInterrupts &= ~( 1UL << i );
\r
346 /* TODO: Need to have some sort of handshake
\r
347 event here for non-tick and none yield
\r
355 if( lSwitchRequired != pdFALSE )
\r
357 void *pvOldCurrentTCB;
\r
359 pvOldCurrentTCB = pxCurrentTCB;
\r
361 /* Select the next task to run. */
\r
362 vTaskSwitchContext();
\r
364 /* If the task selected to enter the running state is not the task
\r
365 that is already in the running state. */
\r
366 if( pvOldCurrentTCB != pxCurrentTCB )
\r
368 /* Suspend the old thread. */
\r
369 pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );
\r
370 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
\r
371 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
372 SuspendThread( pxThreadState->pvThread );
\r
376 /* NOTE! - Here lies a problem when the preemptive scheduler is
\r
377 used. It would seem Win32 threads do not stop as soon as a
\r
378 call to suspend them is made. The co-operative scheduler gets
\r
379 around this by having the thread block on a semaphore
\r
380 immediately after yielding so it cannot execute any more task
\r
381 code until it is once again scheduled to run. This cannot be
\r
382 done if the task is pre-empted though, and I have not found an
\r
383 equivalent work around for the preemptive situation. */
\r
387 /* Obtain the state of the task now selected to enter the
\r
389 pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
\r
391 /* Boost the priority of the thread selected to run a little
\r
392 in an attempt to get the Windows thread scheduler to act a
\r
393 little more like an embedded engineer might expect. */
\r
394 SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
\r
395 SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
\r
396 ResumeThread( pxThreadState->pvThread );
\r
400 /* On exiting a critical section a task may have blocked on the
\r
401 interrupt event when only a tick needed processing, in which case
\r
402 it will not have been released from waiting on the event yet. */
\r
403 pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
\r
404 if( pxThreadState->lWaitingInterruptAck == pdTRUE )
\r
406 pxThreadState->lWaitingInterruptAck = pdFALSE;
\r
407 SetEvent( pvInterruptAcknowledgeEvent );
\r
410 ReleaseMutex( pvInterruptEventMutex );
\r
413 /*-----------------------------------------------------------*/
\r
415 void vPortEndScheduler( void )
\r
418 /*-----------------------------------------------------------*/
\r
420 void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber )
\r
422 xThreadState *pxThreadState;
\r
424 if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
\r
426 /* Yield interrupts are processed even when critical nesting is non-zero. */
\r
427 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
428 ulPendingInterrupts |= ( 1 << ulInterruptNumber );
\r
430 /* The pseudo interrupt is now held pending, but don't actually process it
\r
431 yet if this call is within a critical section. It is possible for this to
\r
432 be in a critical section as calls to wait for mutexes are accumulative. */
\r
433 if( ulCriticalNesting == 0 )
\r
435 /* The event handler needs to know to signal the interrupt acknowledge event
\r
436 the next time this task runs. */
\r
437 pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
\r
438 pxThreadState->lWaitingInterruptAck = pdTRUE;
\r
440 SetEvent( pvInterruptEvent );
\r
442 /* The interrupt ack event should not be signaled yet - if it is then there
\r
443 is an error in the logical simulation. */
\r
444 if( WaitForSingleObject( pvInterruptAcknowledgeEvent, 0 ) != WAIT_TIMEOUT )
\r
446 /* This line is for a break point only. */
\r
450 SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
\r
454 ReleaseMutex( pvInterruptEventMutex );
\r
458 /*-----------------------------------------------------------*/
\r
460 void vPortSetInterruptHandler( unsigned long ulInterruptNumber, void (*pvHandler)( void ) )
\r
462 if( ulInterruptNumber < portMAX_INTERRUPTS )
\r
464 if( pvInterruptEventMutex != NULL )
\r
466 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
467 vIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
468 ReleaseMutex( pvInterruptEventMutex );
\r
472 vIsrHandler[ ulInterruptNumber ] = pvHandler;
\r
476 /*-----------------------------------------------------------*/
\r
478 void vPortEnterCritical( void )
\r
480 if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
\r
482 /* The interrupt event mutex is held for the entire critical section,
\r
483 effectively disabling (pseudo) interrupts. */
\r
484 WaitForSingleObject( pvInterruptEventMutex, INFINITE );
\r
485 ulCriticalNesting++;
\r
489 ulCriticalNesting++;
\r
492 /*-----------------------------------------------------------*/
\r
494 void vPortExitCritical( void )
\r
496 xThreadState *pxThreadState;
\r
497 long lMutexNeedsReleasing;
\r
499 /* The interrupt event mutex should already be held by this thread as it was
\r
500 obtained on entry to the critical section. */
\r
502 lMutexNeedsReleasing = pdTRUE;
\r
504 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
506 if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
\r
508 ulCriticalNesting--;
\r
510 /* Were any interrupts set to pending while interrupts were
\r
511 (pseudo) disabled? */
\r
512 if( ulPendingInterrupts != 0UL )
\r
514 SetEvent( pvInterruptEvent );
\r
516 /* The event handler needs to know to signal the interrupt
\r
517 acknowledge event the next time this task runs. */
\r
518 pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
\r
519 pxThreadState->lWaitingInterruptAck = pdTRUE;
\r
521 /* Mutex will be released now, so does not require releasing
\r
522 on function exit. */
\r
523 lMutexNeedsReleasing = pdFALSE;
\r
524 SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
\r
529 /* Tick interrupts will still not be processed as the critical
\r
530 nesting depth will not be zero. */
\r
531 ulCriticalNesting--;
\r
535 if( lMutexNeedsReleasing == pdTRUE )
\r
537 ReleaseMutex( pvInterruptEventMutex );
\r
540 /*-----------------------------------------------------------*/
\r
542 void vPortCheckCorrectThreadIsRunning( void )
\r
544 xThreadState *pxThreadState;
\r
546 /* When switching threads, Windows does not always seem to run the selected
\r
547 thread immediately. This function can be called to check if the thread
\r
548 that is currently running is the thread that is responsible for executing
\r
549 the task selected by the real time scheduler. */
\r
550 if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
\r
552 pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
\r
554 if( GetCurrentThreadId() != pxThreadState->ulThreadId )
\r