]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/MSVC-MingW/port.c
Update version number in preparation for maintenance release.
[freertos] / FreeRTOS / Source / portable / MSVC-MingW / port.c
1 /*\r
2     FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \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
12 \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
19 \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
24 \r
25     ***************************************************************************\r
26      *                                                                       *\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
31      *                                                                       *\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
36      *                                                                       *\r
37     ***************************************************************************\r
38 \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
42 \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
46 \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
51 \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
55 \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
58 \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
62 \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
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /* Standard includes. */\r
71 #include <stdio.h>\r
72 \r
73 /* Scheduler includes. */\r
74 #include "FreeRTOS.h"\r
75 #include "task.h"\r
76 \r
77 #ifdef __GNUC__\r
78         #include "mmsystem.h"\r
79 #else\r
80         #pragma comment(lib, "winmm.lib")\r
81 #endif\r
82 \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
85 \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
91 \r
92 /*\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
97  */\r
98 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );\r
99 \r
100 /*\r
101  * Process all the simulated interrupts - each represented by a bit in\r
102  * ulPendingInterrupts variable.\r
103  */\r
104 static void prvProcessSimulatedInterrupts( void );\r
105 \r
106 /*\r
107  * Interrupt handlers used by the kernel itself.  These are executed from the\r
108  * simulated interrupt handler thread.\r
109  */\r
110 static uint32_t prvProcessYieldInterrupt( void );\r
111 static uint32_t prvProcessTickInterrupt( void );\r
112 \r
113 /*\r
114  * Called when the process exits to let Windows know the high timer resolution\r
115  * is no longer required.\r
116  */\r
117 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType );\r
118 \r
119 /*-----------------------------------------------------------*/\r
120 \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
126 typedef struct\r
127 {\r
128         /* Handle of the thread that executes the task. */\r
129         void *pvThread;\r
130 \r
131 } xThreadState;\r
132 \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
136 \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
139 pending. */\r
140 static void *pvInterruptEvent = NULL;\r
141 \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
145 \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
152 started anyway. */\r
153 static uint32_t ulCriticalNesting = 9999UL;\r
154 \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
159 \r
160 /* Pointer to the TCB of the currently executing task. */\r
161 extern void *pxCurrentTCB;\r
162 \r
163 /* Used to ensure nothing is processed during the startup sequence. */\r
164 static BaseType_t xPortRunning = pdFALSE;\r
165 \r
166 /*-----------------------------------------------------------*/\r
167 \r
168 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )\r
169 {\r
170 TickType_t xMinimumWindowsBlockTime;\r
171 TIMECAPS xTimeCaps;\r
172 \r
173         /* Set the timer resolution to the maximum possible. */\r
174         if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )\r
175         {\r
176                 xMinimumWindowsBlockTime = ( TickType_t ) xTimeCaps.wPeriodMin;\r
177                 timeBeginPeriod( xTimeCaps.wPeriodMin );\r
178 \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
182         }\r
183         else\r
184         {\r
185                 xMinimumWindowsBlockTime = ( TickType_t ) 20;\r
186         }\r
187 \r
188         /* Just to prevent compiler warnings. */\r
189         ( void ) lpParameter;\r
190 \r
191         for( ;; )\r
192         {\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
198                 environment. */\r
199                 if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )\r
200                 {\r
201                         Sleep( xMinimumWindowsBlockTime );\r
202                 }\r
203                 else\r
204                 {\r
205                         Sleep( portTICK_PERIOD_MS );\r
206                 }\r
207 \r
208                 configASSERT( xPortRunning );\r
209 \r
210                 WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
211 \r
212                 /* The timer has expired, generate the simulated tick event. */\r
213                 ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );\r
214 \r
215                 /* The interrupt is now pending - notify the simulated interrupt\r
216                 handler thread. */\r
217                 if( ulCriticalNesting == 0 )\r
218                 {\r
219                         SetEvent( pvInterruptEvent );\r
220                 }\r
221 \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
225         }\r
226 \r
227         #ifdef __GNUC__\r
228                 /* Should never reach here - MingW complains if you leave this line out,\r
229                 MSVC complains if you put it in. */\r
230                 return 0;\r
231         #endif\r
232 }\r
233 /*-----------------------------------------------------------*/\r
234 \r
235 static BOOL WINAPI prvEndProcess( DWORD dwCtrlType )\r
236 {\r
237 TIMECAPS xTimeCaps;\r
238 \r
239         ( void ) dwCtrlType;\r
240 \r
241         if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )\r
242         {\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
246         }\r
247 \r
248         return pdPASS;\r
249 }\r
250 /*-----------------------------------------------------------*/\r
251 \r
252 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )\r
253 {\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
257 \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
265 \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
272 \r
273         return ( StackType_t * ) pxThreadState;\r
274 }\r
275 /*-----------------------------------------------------------*/\r
276 \r
277 BaseType_t xPortStartScheduler( void )\r
278 {\r
279 void *pvHandle = NULL;\r
280 int32_t lSuccess;\r
281 xThreadState *pxThreadState = NULL;\r
282 SYSTEM_INFO xSystemInfo;\r
283 \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
289         {\r
290                 printf( "This version of the FreeRTOS Windows port can only be used on multi-core hosts.\r\n" );\r
291                 lSuccess = pdFAIL;\r
292         }\r
293         else\r
294         {\r
295                 lSuccess = pdPASS;\r
296 \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
300                 {\r
301                         printf( "SetPriorityClass() failed\r\n" );\r
302                 }\r
303 \r
304                 /* Install the interrupt handlers used by the scheduler itself. */\r
305                 vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );\r
306                 vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );\r
307 \r
308                 /* Create the events and mutexes that are used to synchronise all the\r
309                 threads. */\r
310                 pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );\r
311                 pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
312 \r
313                 if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )\r
314                 {\r
315                         lSuccess = pdFAIL;\r
316                 }\r
317 \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
323                 {\r
324                         lSuccess = pdFAIL;\r
325                 }\r
326         }\r
327 \r
328         if( lSuccess == pdPASS )\r
329         {\r
330                 if( SetThreadPriority( pvHandle, portSIMULATED_INTERRUPTS_THREAD_PRIORITY ) == 0 )\r
331                 {\r
332                         lSuccess = pdFAIL;\r
333                 }\r
334                 SetThreadPriorityBoost( pvHandle, TRUE );\r
335                 SetThreadAffinityMask( pvHandle, 0x01 );\r
336         }\r
337 \r
338         if( lSuccess == pdPASS )\r
339         {\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
346                 {\r
347                         SetThreadPriority( pvHandle, portSIMULATED_TIMER_THREAD_PRIORITY );\r
348                         SetThreadPriorityBoost( pvHandle, TRUE );\r
349                         SetThreadAffinityMask( pvHandle, 0x01 );\r
350                         ResumeThread( pvHandle );\r
351                 }\r
352 \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
357 \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
362 \r
363                 /* Handle all simulated interrupts - including yield requests and\r
364                 simulated ticks. */\r
365                 prvProcessSimulatedInterrupts();\r
366         }\r
367 \r
368         /* Would not expect to return from prvProcessSimulatedInterrupts(), so should\r
369         not get here. */\r
370         return 0;\r
371 }\r
372 /*-----------------------------------------------------------*/\r
373 \r
374 static uint32_t prvProcessYieldInterrupt( void )\r
375 {\r
376         return pdTRUE;\r
377 }\r
378 /*-----------------------------------------------------------*/\r
379 \r
380 static uint32_t prvProcessTickInterrupt( void )\r
381 {\r
382 uint32_t ulSwitchRequired;\r
383 \r
384         /* Process the tick itself. */\r
385         configASSERT( xPortRunning );\r
386         ulSwitchRequired = ( uint32_t ) xTaskIncrementTick();\r
387 \r
388         return ulSwitchRequired;\r
389 }\r
390 /*-----------------------------------------------------------*/\r
391 \r
392 static void prvProcessSimulatedInterrupts( void )\r
393 {\r
394 uint32_t ulSwitchRequired, i;\r
395 xThreadState *pxThreadState;\r
396 void *pvObjectList[ 2 ];\r
397 CONTEXT xContext;\r
398 \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
404 \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
409 \r
410         xPortRunning = pdTRUE;\r
411 \r
412         for(;;)\r
413         {\r
414                 WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );\r
415 \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
419 \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
423                 {\r
424                         /* Is the simulated interrupt pending? */\r
425                         if( ulPendingInterrupts & ( 1UL << i ) )\r
426                         {\r
427                                 /* Is a handler installed? */\r
428                                 if( ulIsrHandler[ i ] != NULL )\r
429                                 {\r
430                                         /* Run the actual handler. */\r
431                                         if( ulIsrHandler[ i ]() != pdFALSE )\r
432                                         {\r
433                                                 ulSwitchRequired |= ( 1 << i );\r
434                                         }\r
435                                 }\r
436 \r
437                                 /* Clear the interrupt pending bit. */\r
438                                 ulPendingInterrupts &= ~( 1UL << i );\r
439                         }\r
440                 }\r
441 \r
442                 if( ulSwitchRequired != pdFALSE )\r
443                 {\r
444                         void *pvOldCurrentTCB;\r
445 \r
446                         pvOldCurrentTCB = pxCurrentTCB;\r
447 \r
448                         /* Select the next task to run. */\r
449                         vTaskSwitchContext();\r
450 \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
454                         {\r
455                                 /* Suspend the old thread. */\r
456                                 pxThreadState = ( xThreadState *) *( ( size_t * ) pvOldCurrentTCB );\r
457                                 SuspendThread( pxThreadState->pvThread );\r
458 \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
462                                 data. */\r
463                                 xContext.ContextFlags = CONTEXT_INTEGER;\r
464                                 ( void ) GetThreadContext( pxThreadState->pvThread, &xContext );\r
465 \r
466                                 /* Obtain the state of the task now selected to enter the\r
467                                 Running state. */\r
468                                 pxThreadState = ( xThreadState * ) ( *( size_t *) pxCurrentTCB );\r
469                                 ResumeThread( pxThreadState->pvThread );\r
470                         }\r
471                 }\r
472 \r
473                 ReleaseMutex( pvInterruptEventMutex );\r
474         }\r
475 }\r
476 /*-----------------------------------------------------------*/\r
477 \r
478 void vPortDeleteThread( void *pvTaskToDelete )\r
479 {\r
480 xThreadState *pxThreadState;\r
481 uint32_t ulErrorCode;\r
482 \r
483         /* Remove compiler warnings if configASSERT() is not defined. */\r
484         ( void ) ulErrorCode;\r
485 \r
486         /* Find the handle of the thread being deleted. */\r
487         pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );\r
488 \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
492         different task. */\r
493         if( pxThreadState->pvThread != NULL )\r
494         {\r
495                 WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
496 \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
500                 freed. */\r
501                 ulErrorCode = TerminateThread( pxThreadState->pvThread, 0 );\r
502                 configASSERT( ulErrorCode );\r
503 \r
504                 ulErrorCode = CloseHandle( pxThreadState->pvThread );\r
505                 configASSERT( ulErrorCode );\r
506 \r
507                 ReleaseMutex( pvInterruptEventMutex );\r
508         }\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 void vPortCloseRunningThread( void *pvTaskToDelete, volatile BaseType_t *pxPendYield )\r
513 {\r
514 xThreadState *pxThreadState;\r
515 void *pvThread;\r
516 uint32_t ulErrorCode;\r
517 \r
518         /* Remove compiler warnings if configASSERT() is not defined. */\r
519         ( void ) ulErrorCode;\r
520 \r
521         /* Find the handle of the thread being deleted. */\r
522         pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );\r
523         pvThread = pxThreadState->pvThread;\r
524 \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
528         memory leak. */\r
529         SetThreadPriority( pvThread, portDELETE_SELF_THREAD_PRIORITY );\r
530 \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
534 \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
538 \r
539         /* Close the thread. */\r
540         ulErrorCode = CloseHandle( pvThread );\r
541         configASSERT( ulErrorCode );\r
542 \r
543         /* This is called from a critical section, which must be exited before the\r
544         thread stops. */\r
545         taskEXIT_CRITICAL();\r
546 \r
547         ExitThread( 0 );\r
548 }\r
549 /*-----------------------------------------------------------*/\r
550 \r
551 void vPortEndScheduler( void )\r
552 {\r
553         /* This function IS NOT TESTED! */\r
554         TerminateProcess( GetCurrentProcess(), 0 );\r
555 }\r
556 /*-----------------------------------------------------------*/\r
557 \r
558 void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )\r
559 {\r
560         configASSERT( xPortRunning );\r
561 \r
562         if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )\r
563         {\r
564                 /* Yield interrupts are processed even when critical nesting is\r
565                 non-zero. */\r
566                 WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
567                 ulPendingInterrupts |= ( 1 << ulInterruptNumber );\r
568 \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
574                 {\r
575                         SetEvent( pvInterruptEvent );\r
576                 }\r
577 \r
578                 ReleaseMutex( pvInterruptEventMutex );\r
579         }\r
580 }\r
581 /*-----------------------------------------------------------*/\r
582 \r
583 void vPortSetInterruptHandler( uint32_t ulInterruptNumber, uint32_t (*pvHandler)( void ) )\r
584 {\r
585         if( ulInterruptNumber < portMAX_INTERRUPTS )\r
586         {\r
587                 if( pvInterruptEventMutex != NULL )\r
588                 {\r
589                         WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
590                         ulIsrHandler[ ulInterruptNumber ] = pvHandler;\r
591                         ReleaseMutex( pvInterruptEventMutex );\r
592                 }\r
593                 else\r
594                 {\r
595                         ulIsrHandler[ ulInterruptNumber ] = pvHandler;\r
596                 }\r
597         }\r
598 }\r
599 /*-----------------------------------------------------------*/\r
600 \r
601 void vPortEnterCritical( void )\r
602 {\r
603         if( xPortRunning == pdTRUE )\r
604         {\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
609         }\r
610         else\r
611         {\r
612                 ulCriticalNesting++;\r
613         }\r
614 }\r
615 /*-----------------------------------------------------------*/\r
616 \r
617 void vPortExitCritical( void )\r
618 {\r
619 int32_t lMutexNeedsReleasing;\r
620 \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
623 \r
624         lMutexNeedsReleasing = pdTRUE;\r
625 \r
626         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
627         {\r
628                 if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )\r
629                 {\r
630                         ulCriticalNesting--;\r
631 \r
632                         /* Were any interrupts set to pending while interrupts were\r
633                         (simulated) disabled? */\r
634                         if( ulPendingInterrupts != 0UL )\r
635                         {\r
636                                 configASSERT( xPortRunning );\r
637                                 SetEvent( pvInterruptEvent );\r
638 \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
643                         }\r
644                 }\r
645                 else\r
646                 {\r
647                         /* Tick interrupts will still not be processed as the critical\r
648                         nesting depth will not be zero. */\r
649                         ulCriticalNesting--;\r
650                 }\r
651         }\r
652 \r
653         if( pvInterruptEventMutex != NULL )\r
654         {\r
655                 if( lMutexNeedsReleasing == pdTRUE )\r
656                 {\r
657                         configASSERT( xPortRunning );\r
658                         ReleaseMutex( pvInterruptEventMutex );\r
659                 }\r
660         }\r
661 }\r
662 /*-----------------------------------------------------------*/\r
663 \r