OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Source/] [portable/] [MSVC-MingW/] [port.c] - Blame information for rev 613

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 572 jeremybenn
/*
2
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
3
 
4
    ***************************************************************************
5
    *                                                                         *
6
    * If you are:                                                             *
7
    *                                                                         *
8
    *    + New to FreeRTOS,                                                   *
9
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
10
    *    + Looking for basic training,                                        *
11
    *    + Wanting to improve your FreeRTOS skills and productivity           *
12
    *                                                                         *
13
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
14
    *                                                                         *
15
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
16
    *                  http://www.FreeRTOS.org/Documentation                  *
17
    *                                                                         *
18
    * A pdf reference manual is also available.  Both are usually delivered   *
19
    * to your inbox within 20 minutes to two hours when purchased between 8am *
20
    * and 8pm GMT (although please allow up to 24 hours in case of            *
21
    * exceptional circumstances).  Thank you for your support!                *
22
    *                                                                         *
23
    ***************************************************************************
24
 
25
    This file is part of the FreeRTOS distribution.
26
 
27
    FreeRTOS is free software; you can redistribute it and/or modify it under
28
    the terms of the GNU General Public License (version 2) as published by the
29
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30
    ***NOTE*** The exception to the GPL is included to allow you to distribute
31
    a combined work that includes FreeRTOS without being obliged to provide the
32
    source code for proprietary components outside of the FreeRTOS kernel.
33
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
36
    more details. You should have received a copy of the GNU General Public
37
    License and the FreeRTOS license exception along with FreeRTOS; if not it
38
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
39
    by writing to Richard Barry, contact details for whom are available on the
40
    FreeRTOS WEB site.
41
 
42
    1 tab == 4 spaces!
43
 
44
    http://www.FreeRTOS.org - Documentation, latest information, license and
45
    contact details.
46
 
47
    http://www.SafeRTOS.com - A version that is certified for use in safety
48
    critical systems.
49
 
50
    http://www.OpenRTOS.com - Commercial support, development, porting,
51
    licensing and training services.
52
*/
53
 
54
/* Scheduler includes. */
55
#include "FreeRTOS.h"
56
#include "task.h"
57
#include <stdio.h>
58
 
59
#define portMAX_INTERRUPTS                              ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */
60
#define portNO_CRITICAL_NESTING                 ( ( unsigned long ) 0 )
61
 
62
/*
63
 * Created as a high priority thread, this function uses a timer to simulate
64
 * a tick interrupt being generated on an embedded target.  In this Windows
65
 * environment the timer does not achieve anything approaching real time
66
 * performance though.
67
 */
68
static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
69
 
70
/*
71
 * Process all the simulated interrupts - each represented by a bit in
72
 * ulPendingInterrupts variable.
73
 */
74
static void prvProcessSimulatedInterrupts( void );
75
 
76
/*
77
 * Interrupt handlers used by the kernel itself.  These are executed from the
78
 * simulated interrupt handler thread.
79
 */
80
static unsigned long prvProcessDeleteThreadInterrupt( void );
81
static unsigned long prvProcessYieldInterrupt( void );
82
static unsigned long prvProcessTickInterrupt( void );
83
 
84
/*-----------------------------------------------------------*/
85
 
86
/* The WIN32 simulator runs each task in a thread.  The context switching is
87
managed by the threads, so the task stack does not have to be managed directly,
88
although the task stack is still used to hold an xThreadState structure this is
89
the only thing it will ever hold.  The structure indirectly maps the task handle
90
to a thread handle. */
91
typedef struct
92
{
93
        /* Handle of the thread that executes the task. */
94
        void *pvThread;
95
 
96
} xThreadState;
97
 
98
/* Simulated interrupts waiting to be processed.  This is a bit mask where each
99
bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
100
static volatile unsigned long ulPendingInterrupts = 0UL;
101
 
102
/* An event used to inform the simulated interrupt processing thread (a high
103
priority thread that simulated interrupt processing) that an interrupt is
104
pending. */
105
static void *pvInterruptEvent = NULL;
106
 
107
/* Mutex used to protect all the simulated interrupt variables that are accessed
108
by multiple threads. */
109
static void *pvInterruptEventMutex = NULL;
110
 
111
/* The critical nesting count for the currently executing task.  This is
112
initialised to a non-zero value so interrupts do not become enabled during
113
the initialisation phase.  As each task has its own critical nesting value
114
ulCriticalNesting will get set to zero when the first task runs.  This
115
initialisation is probably not critical in this simulated environment as the
116
simulated interrupt handlers do not get created until the FreeRTOS scheduler is
117
started anyway. */
118
static unsigned long ulCriticalNesting = 9999UL;
119
 
120
/* Handlers for all the simulated software interrupts.  The first two positions
121
are used for the Yield and Tick interrupts so are handled slightly differently,
122
all the other interrupts can be user defined. */
123
static unsigned long (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };
124
 
125
/* Pointer to the TCB of the currently executing task. */
126
extern void *pxCurrentTCB;
127
 
128
/*-----------------------------------------------------------*/
129
 
130
static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
131
{
132
        /* Just to prevent compiler warnings. */
133
        ( void ) lpParameter;
134
 
135
        for(;;)
136
        {
137
                /* Wait until the timer expires and we can access the simulated interrupt
138
                variables.  *NOTE* this is not a 'real time' way of generating tick
139
                events as the next wake time should be relative to the previous wake
140
                time, not the time that Sleep() is called.  It is done this way to
141
                prevent overruns in this very non real time simulated/emulated
142
                environment. */
143
                Sleep( portTICK_RATE_MS );
144
 
145
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );
146
 
147
                /* The timer has expired, generate the simulated tick event. */
148
                ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
149
 
150
                /* The interrupt is now pending - notify the simulated interrupt
151
                handler thread. */
152
                SetEvent( pvInterruptEvent );
153
 
154
                /* Give back the mutex so the simulated interrupt handler unblocks
155
                and can access the interrupt handler variables. */
156
                ReleaseMutex( pvInterruptEventMutex );
157
        }
158
 
159
        #ifdef __GNUC__
160
                /* Should never reach here - MingW complains if you leave this line out,
161
                MSVC complains if you put it in. */
162
                return 0;
163
        #endif
164
}
165
/*-----------------------------------------------------------*/
166
 
167
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
168
{
169
xThreadState *pxThreadState = NULL;
170
 
171
        /* In this simulated case a stack is not initialised, but instead a thread
172
        is created that will execute the task being created.  The thread handles
173
        the context switching itself.  The xThreadState object is placed onto
174
        the stack that was created for the task - so the stack buffer is still
175
        used, just not in the conventional way.  It will not be used for anything
176
        other than holding this structure. */
177
        pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );
178
 
179
        /* Create the thread itself. */
180
        pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
181
        SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );
182
        SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
183
        SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
184
 
185
        return ( portSTACK_TYPE * ) pxThreadState;
186
}
187
/*-----------------------------------------------------------*/
188
 
189
portBASE_TYPE xPortStartScheduler( void )
190
{
191
void *pvHandle;
192
long lSuccess = pdPASS;
193
xThreadState *pxThreadState;
194
 
195
        /* Install the interrupt handlers used by the scheduler itself. */
196
        vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );
197
        vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );
198
        vPortSetInterruptHandler( portINTERRUPT_DELETE_THREAD, prvProcessDeleteThreadInterrupt );
199
 
200
        /* Create the events and mutexes that are used to synchronise all the
201
        threads. */
202
        pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );
203
        pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
204
 
205
        if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )
206
        {
207
                lSuccess = pdFAIL;
208
        }
209
 
210
        /* Set the priority of this thread such that it is above the priority of
211
        the threads that run tasks.  This higher priority is required to ensure
212
        simulated interrupts take priority over tasks. */
213
        pvHandle = GetCurrentThread();
214
        if( pvHandle == NULL )
215
        {
216
                lSuccess = pdFAIL;
217
        }
218
 
219
        if( lSuccess == pdPASS )
220
        {
221
                if( SetThreadPriority( pvHandle, THREAD_PRIORITY_NORMAL ) == 0 )
222
                {
223
                        lSuccess = pdFAIL;
224
                }
225
                SetThreadPriorityBoost( pvHandle, TRUE );
226
                SetThreadAffinityMask( pvHandle, 0x01 );
227
        }
228
 
229
        if( lSuccess == pdPASS )
230
        {
231
                /* Start the thread that simulates the timer peripheral to generate
232
                tick interrupts.  The priority is set below that of the simulated
233
                interrupt handler so the interrupt event mutex is used for the
234
                handshake / overrun protection. */
235
                pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );
236
                if( pvHandle != NULL )
237
                {
238
                        SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL );
239
                        SetThreadPriorityBoost( pvHandle, TRUE );
240
                        SetThreadAffinityMask( pvHandle, 0x01 );
241
                }
242
 
243
                /* Start the highest priority task by obtaining its associated thread
244
                state structure, in which is stored the thread handle. */
245
                pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
246
                ulCriticalNesting = portNO_CRITICAL_NESTING;
247
 
248
                /* Bump up the priority of the thread that is going to run, in the
249
                hope that this will asist in getting the Windows thread scheduler to
250
                behave as an embedded engineer might expect. */
251
                ResumeThread( pxThreadState->pvThread );
252
 
253
                /* Handle all simulated interrupts - including yield requests and
254
                simulated ticks. */
255
                prvProcessSimulatedInterrupts();
256
        }
257
 
258
        /* Would not expect to return from prvProcessSimulatedInterrupts(), so should
259
        not get here. */
260
        return 0;
261
}
262
/*-----------------------------------------------------------*/
263
 
264
static unsigned long prvProcessDeleteThreadInterrupt( void )
265
{
266
        return pdTRUE;
267
}
268
/*-----------------------------------------------------------*/
269
 
270
static unsigned long prvProcessYieldInterrupt( void )
271
{
272
        return pdTRUE;
273
}
274
/*-----------------------------------------------------------*/
275
 
276
static unsigned long prvProcessTickInterrupt( void )
277
{
278
unsigned long ulSwitchRequired;
279
 
280
        /* Process the tick itself. */
281
        vTaskIncrementTick();
282
        #if( configUSE_PREEMPTION != 0 )
283
        {
284
                /* A context switch is only automatically performed from the tick
285
                interrupt if the pre-emptive scheduler is being used. */
286
                ulSwitchRequired = pdTRUE;
287
        }
288
        #else
289
        {
290
                ulSwitchRequired = pdFALSE;
291
        }
292
        #endif
293
 
294
        return ulSwitchRequired;
295
}
296
/*-----------------------------------------------------------*/
297
 
298
static void prvProcessSimulatedInterrupts( void )
299
{
300
unsigned long ulSwitchRequired, i;
301
xThreadState *pxThreadState;
302
void *pvObjectList[ 2 ];
303
 
304
        /* Going to block on the mutex that ensured exclusive access to the simulated
305
        interrupt objects, and the event that signals that a simulated interrupt
306
        should be processed. */
307
        pvObjectList[ 0 ] = pvInterruptEventMutex;
308
        pvObjectList[ 1 ] = pvInterruptEvent;
309
 
310
        for(;;)
311
        {
312
                WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
313
 
314
                /* Used to indicate whether the simulated interrupt processing has
315
                necessitated a context switch to another task/thread. */
316
                ulSwitchRequired = pdFALSE;
317
 
318
                /* For each interrupt we are interested in processing, each of which is
319
                represented by a bit in the 32bit ulPendingInterrupts variable. */
320
                for( i = 0; i < portMAX_INTERRUPTS; i++ )
321
                {
322
                        /* Is the simulated interrupt pending? */
323
                        if( ulPendingInterrupts & ( 1UL << i ) )
324
                        {
325
                                /* Is a handler installed? */
326
                                if( ulIsrHandler[ i ] != NULL )
327
                                {
328
                                        /* Run the actual handler. */
329
                                        if( ulIsrHandler[ i ]() != pdFALSE )
330
                                        {
331
                                                ulSwitchRequired |= ( 1 << i );
332
                                        }
333
                                }
334
 
335
                                /* Clear the interrupt pending bit. */
336
                                ulPendingInterrupts &= ~( 1UL << i );
337
                        }
338
                }
339
 
340
                if( ulSwitchRequired != pdFALSE )
341
                {
342
                        void *pvOldCurrentTCB;
343
 
344
                        pvOldCurrentTCB = pxCurrentTCB;
345
 
346
                        /* Select the next task to run. */
347
                        vTaskSwitchContext();
348
 
349
                        /* If the task selected to enter the running state is not the task
350
                        that is already in the running state. */
351
                        if( pvOldCurrentTCB != pxCurrentTCB )
352
                        {
353
                                /* Suspend the old thread. */
354
                                pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );
355
 
356
                                if( ( ulSwitchRequired & ( 1 << portINTERRUPT_DELETE_THREAD ) ) != pdFALSE )
357
                                {
358
                                        TerminateThread( pxThreadState->pvThread, 0 );
359
                                }
360
                                else
361
                                {
362
                                        SuspendThread( pxThreadState->pvThread );
363
                                }
364
 
365
                                /* Obtain the state of the task now selected to enter the
366
                                Running state. */
367
                                pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
368
                                ResumeThread( pxThreadState->pvThread );
369
                        }
370
                }
371
 
372
                ReleaseMutex( pvInterruptEventMutex );
373
        }
374
}
375
/*-----------------------------------------------------------*/
376
 
377
void vPortDeleteThread( void *pvTaskToDelete )
378
{
379
xThreadState *pxThreadState;
380
 
381
        if( pvTaskToDelete == pxCurrentTCB )
382
        {
383
                /* The task is deleting itself, and so the thread that is running now
384
                is also to be deleted.  This has to be deferred until this thread is
385
                no longer running, so its done in the simulated interrupt handler thread. */
386
                vPortGenerateSimulatedInterrupt( portINTERRUPT_DELETE_THREAD );
387
        }
388
        else
389
        {
390
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );
391
 
392
                /* Find the handle of the thread being deleted. */
393
                pxThreadState = ( xThreadState * ) ( *( unsigned long *) pvTaskToDelete );
394
                TerminateThread( pxThreadState->pvThread, 0 );
395
 
396
                ReleaseMutex( pvInterruptEventMutex );
397
        }
398
}
399
/*-----------------------------------------------------------*/
400
 
401
void vPortEndScheduler( void )
402
{
403
        /* This function IS NOT TESTED! */
404
        TerminateProcess( GetCurrentProcess(), 0 );
405
}
406
/*-----------------------------------------------------------*/
407
 
408
void vPortGenerateSimulatedInterrupt( unsigned long ulInterruptNumber )
409
{
410
xThreadState *pxThreadState;
411
 
412
        if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
413
        {
414
                /* Yield interrupts are processed even when critical nesting is non-zero. */
415
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );
416
                ulPendingInterrupts |= ( 1 << ulInterruptNumber );
417
 
418
                /* The simulated interrupt is now held pending, but don't actually process it
419
                yet if this call is within a critical section.  It is possible for this to
420
                be in a critical section as calls to wait for mutexes are accumulative. */
421
                if( ulCriticalNesting == 0 )
422
                {
423
                        /* The event handler needs to know to signal the interrupt acknowledge event
424
                        the next time this task runs. */
425
                        pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
426
                        SetEvent( pvInterruptEvent );
427
                }
428
 
429
                ReleaseMutex( pvInterruptEventMutex );
430
        }
431
}
432
/*-----------------------------------------------------------*/
433
 
434
void vPortSetInterruptHandler( unsigned long ulInterruptNumber, unsigned long (*pvHandler)( void ) )
435
{
436
        if( ulInterruptNumber < portMAX_INTERRUPTS )
437
        {
438
                if( pvInterruptEventMutex != NULL )
439
                {
440
                        WaitForSingleObject( pvInterruptEventMutex, INFINITE );
441
                        ulIsrHandler[ ulInterruptNumber ] = pvHandler;
442
                        ReleaseMutex( pvInterruptEventMutex );
443
                }
444
                else
445
                {
446
                        ulIsrHandler[ ulInterruptNumber ] = pvHandler;
447
                }
448
        }
449
}
450
/*-----------------------------------------------------------*/
451
 
452
void vPortEnterCritical( void )
453
{
454
        if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
455
        {
456
                /* The interrupt event mutex is held for the entire critical section,
457
                effectively disabling (simulated) interrupts. */
458
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );
459
                ulCriticalNesting++;
460
        }
461
        else
462
        {
463
                ulCriticalNesting++;
464
        }
465
}
466
/*-----------------------------------------------------------*/
467
 
468
void vPortExitCritical( void )
469
{
470
xThreadState *pxThreadState;
471
long lMutexNeedsReleasing;
472
 
473
        /* The interrupt event mutex should already be held by this thread as it was
474
        obtained on entry to the critical section. */
475
 
476
        lMutexNeedsReleasing = pdTRUE;
477
 
478
        if( ulCriticalNesting > portNO_CRITICAL_NESTING )
479
        {
480
                if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
481
                {
482
                        ulCriticalNesting--;
483
 
484
                        /* Were any interrupts set to pending while interrupts were
485
                        (simulated) disabled? */
486
                        if( ulPendingInterrupts != 0UL )
487
                        {
488
                                SetEvent( pvInterruptEvent );
489
 
490
                                /* The event handler needs to know to signal the interrupt
491
                                acknowledge event the next time this task runs. */
492
                                pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
493
 
494
                                /* Mutex will be released now, so does not require releasing
495
                                on function exit. */
496
                                lMutexNeedsReleasing = pdFALSE;
497
                                ReleaseMutex( pvInterruptEventMutex );
498
                        }
499
                }
500
                else
501
                {
502
                        /* Tick interrupts will still not be processed as the critical
503
                        nesting depth will not be zero. */
504
                        ulCriticalNesting--;
505
                }
506
        }
507
 
508
        if( lMutexNeedsReleasing == pdTRUE )
509
        {
510
                ReleaseMutex( pvInterruptEventMutex );
511
        }
512
}
513
/*-----------------------------------------------------------*/
514
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.