OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [Minimal/] [AltQTest.c] - Blame information for rev 623

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

Line No. Rev Author Line
1 606 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
 
55
/*
56
 * This file implements the same demo and test as GenQTest.c, but uses the
57
 * light weight API in place of the fully featured API.
58
 *
59
 * See the comments at the top of GenQTest.c for a description.
60
 */
61
 
62
 
63
#include <stdlib.h>
64
 
65
/* Scheduler include files. */
66
#include "FreeRTOS.h"
67
#include "task.h"
68
#include "queue.h"
69
#include "semphr.h"
70
 
71
/* Demo program include files. */
72
#include "AltQTest.h"
73
 
74
#define genqQUEUE_LENGTH                ( 5 )
75
#define genqNO_BLOCK                    ( 0 )
76
 
77
#define genqMUTEX_LOW_PRIORITY          ( tskIDLE_PRIORITY )
78
#define genqMUTEX_TEST_PRIORITY         ( tskIDLE_PRIORITY + 1 )
79
#define genqMUTEX_MEDIUM_PRIORITY       ( tskIDLE_PRIORITY + 2 )
80
#define genqMUTEX_HIGH_PRIORITY         ( tskIDLE_PRIORITY + 3 )
81
 
82
/*-----------------------------------------------------------*/
83
 
84
/*
85
 * Tests the behaviour of the xQueueAltSendToFront() and xQueueAltSendToBack()
86
 * macros by using both to fill a queue, then reading from the queue to
87
 * check the resultant queue order is as expected.  Queue data is also
88
 * peeked.
89
 */
90
static void prvSendFrontAndBackTest( void *pvParameters );
91
 
92
/*
93
 * The following three tasks are used to demonstrate the mutex behaviour.
94
 * Each task is given a different priority to demonstrate the priority
95
 * inheritance mechanism.
96
 *
97
 * The low priority task obtains a mutex.  After this a high priority task
98
 * attempts to obtain the same mutex, causing its priority to be inherited
99
 * by the low priority task.  The task with the inherited high priority then
100
 * resumes a medium priority task to ensure it is not blocked by the medium
101
 * priority task while it holds the inherited high priority.  Once the mutex
102
 * is returned the task with the inherited priority returns to its original
103
 * low priority, and is therefore immediately preempted by first the high
104
 * priority task and then the medium prioroity task before it can continue.
105
 */
106
static void prvLowPriorityMutexTask( void *pvParameters );
107
static void prvMediumPriorityMutexTask( void *pvParameters );
108
static void prvHighPriorityMutexTask( void *pvParameters );
109
 
110
/*-----------------------------------------------------------*/
111
 
112
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
113
detected in any of the tasks. */
114
static portBASE_TYPE xErrorDetected = pdFALSE;
115
 
116
/* Counters that are incremented on each cycle of a test.  This is used to
117
detect a stalled task - a test that is no longer running. */
118
static volatile unsigned portLONG ulLoopCounter = 0;
119
static volatile unsigned portLONG ulLoopCounter2 = 0;
120
 
121
/* The variable that is guarded by the mutex in the mutex demo tasks. */
122
static volatile unsigned portLONG ulGuardedVariable = 0;
123
 
124
/* Handles used in the mutext test to suspend and resume the high and medium
125
priority mutex test tasks. */
126
static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
127
 
128
/*-----------------------------------------------------------*/
129
 
130
void vStartAltGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
131
{
132
xQueueHandle xQueue;
133
xSemaphoreHandle xMutex;
134
 
135
        /* Create the queue that we are going to use for the
136
        prvSendFrontAndBackTest demo. */
137
        xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
138
 
139
        /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
140
        in use.  The queue registry is provided as a means for kernel aware
141
        debuggers to locate queues and has no purpose if a kernel aware debugger
142
        is not being used.  The call to vQueueAddToRegistry() will be removed
143
        by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
144
        defined to be less than 1. */
145
        vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Alt_Gen_Test_Queue" );
146
 
147
        /* Create the demo task and pass it the queue just created.  We are
148
        passing the queue handle by value so it does not matter that it is
149
        declared on the stack here. */
150
        xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * ) "FGenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
151
 
152
        /* Create the mutex used by the prvMutexTest task. */
153
        xMutex = xSemaphoreCreateMutex();
154
 
155
        /* vQueueAddToRegistry() adds the mutex to the registry, if one is
156
        in use.  The registry is provided as a means for kernel aware
157
        debuggers to locate mutex and has no purpose if a kernel aware debugger
158
        is not being used.  The call to vQueueAddToRegistry() will be removed
159
        by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
160
        defined to be less than 1. */
161
        vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Alt_Q_Mutex" );
162
 
163
        /* Create the mutex demo tasks and pass it the mutex just created.  We are
164
        passing the mutex handle by value so it does not matter that it is declared
165
        on the stack here. */
166
        xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * ) "FMuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
167
        xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * ) "FMuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
168
        xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * ) "FMuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
169
}
170
/*-----------------------------------------------------------*/
171
 
172
static void prvSendFrontAndBackTest( void *pvParameters )
173
{
174
unsigned portLONG ulData, ulData2;
175
xQueueHandle xQueue;
176
 
177
        #ifdef USE_STDIO
178
        void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
179
 
180
                const portCHAR * const pcTaskStartMsg = "Alt queue SendToFront/SendToBack/Peek test started.\r\n";
181
 
182
                /* Queue a message for printing to say the task has started. */
183
                vPrintDisplayMessage( &pcTaskStartMsg );
184
        #endif
185
 
186
        xQueue = ( xQueueHandle ) pvParameters;
187
 
188
        for( ;; )
189
        {
190
                /* The queue is empty, so sending an item to the back of the queue
191
                should have the same efect as sending it to the front of the queue.
192
 
193
                First send to the front and check everything is as expected. */
194
                xQueueAltSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
195
 
196
                if( uxQueueMessagesWaiting( xQueue ) != 1 )
197
                {
198
                        xErrorDetected = pdTRUE;
199
                }
200
 
201
                if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
202
                {
203
                        xErrorDetected = pdTRUE;
204
                }
205
 
206
                /* The data we sent to the queue should equal the data we just received
207
                from the queue. */
208
                if( ulLoopCounter != ulData )
209
                {
210
                        xErrorDetected = pdTRUE;
211
                }
212
 
213
                /* Then do the same, sending the data to the back, checking everything
214
                is as expected. */
215
                if( uxQueueMessagesWaiting( xQueue ) != 0 )
216
                {
217
                        xErrorDetected = pdTRUE;
218
                }
219
 
220
                xQueueAltSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
221
 
222
                if( uxQueueMessagesWaiting( xQueue ) != 1 )
223
                {
224
                        xErrorDetected = pdTRUE;
225
                }
226
 
227
                if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
228
                {
229
                        xErrorDetected = pdTRUE;
230
                }
231
 
232
                if( uxQueueMessagesWaiting( xQueue ) != 0 )
233
                {
234
                        xErrorDetected = pdTRUE;
235
                }
236
 
237
                /* The data we sent to the queue should equal the data we just received
238
                from the queue. */
239
                if( ulLoopCounter != ulData )
240
                {
241
                        xErrorDetected = pdTRUE;
242
                }
243
 
244
                #if configUSE_PREEMPTION == 0
245
                        taskYIELD();
246
                #endif
247
 
248
 
249
 
250
                /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
251
                for( ulData = 2; ulData < 5; ulData++ )
252
                {
253
                        xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
254
                }
255
 
256
                /* Now the order in the queue should be 2, 3, 4, with 2 being the first
257
                thing to be read out.  Now add 1 then 0 to the front of the queue. */
258
                if( uxQueueMessagesWaiting( xQueue ) != 3 )
259
                {
260
                        xErrorDetected = pdTRUE;
261
                }
262
                ulData = 1;
263
                xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
264
                ulData = 0;
265
                xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
266
 
267
                /* Now the queue should be full, and when we read the data out we
268
                should receive 0, 1, 2, 3, 4. */
269
                if( uxQueueMessagesWaiting( xQueue ) != 5 )
270
                {
271
                        xErrorDetected = pdTRUE;
272
                }
273
 
274
                if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
275
                {
276
                        xErrorDetected = pdTRUE;
277
                }
278
 
279
                if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
280
                {
281
                        xErrorDetected = pdTRUE;
282
                }
283
 
284
                #if configUSE_PREEMPTION == 0
285
                        taskYIELD();
286
                #endif
287
 
288
                /* Check the data we read out is in the expected order. */
289
                for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
290
                {
291
                        /* Try peeking the data first. */
292
                        if( xQueueAltPeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
293
                        {
294
                                xErrorDetected = pdTRUE;
295
                        }
296
 
297
                        if( ulData != ulData2 )
298
                        {
299
                                xErrorDetected = pdTRUE;
300
                        }
301
 
302
 
303
                        /* Now try receiving the data for real.  The value should be the
304
                        same.  Clobber the value first so we know we really received it. */
305
                        ulData2 = ~ulData2;
306
                        if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
307
                        {
308
                                xErrorDetected = pdTRUE;
309
                        }
310
 
311
                        if( ulData != ulData2 )
312
                        {
313
                                xErrorDetected = pdTRUE;
314
                        }
315
                }
316
 
317
                /* The queue should now be empty again. */
318
                if( uxQueueMessagesWaiting( xQueue ) != 0 )
319
                {
320
                        xErrorDetected = pdTRUE;
321
                }
322
 
323
                #if configUSE_PREEMPTION == 0
324
                        taskYIELD();
325
                #endif
326
 
327
 
328
                /* Our queue is empty once more, add 10, 11 to the back. */
329
                ulData = 10;
330
                if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
331
                {
332
                        xErrorDetected = pdTRUE;
333
                }
334
                ulData = 11;
335
                if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
336
                {
337
                        xErrorDetected = pdTRUE;
338
                }
339
 
340
                if( uxQueueMessagesWaiting( xQueue ) != 2 )
341
                {
342
                        xErrorDetected = pdTRUE;
343
                }
344
 
345
                /* Now we should have 10, 11 in the queue.  Add 7, 8, 9 to the
346
                front. */
347
                for( ulData = 9; ulData >= 7; ulData-- )
348
                {
349
                        if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
350
                        {
351
                                xErrorDetected = pdTRUE;
352
                        }
353
                }
354
 
355
                /* Now check that the queue is full, and that receiving data provides
356
                the expected sequence of 7, 8, 9, 10, 11. */
357
                if( uxQueueMessagesWaiting( xQueue ) != 5 )
358
                {
359
                        xErrorDetected = pdTRUE;
360
                }
361
 
362
                if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
363
                {
364
                        xErrorDetected = pdTRUE;
365
                }
366
 
367
                if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
368
                {
369
                        xErrorDetected = pdTRUE;
370
                }
371
 
372
                #if configUSE_PREEMPTION == 0
373
                        taskYIELD();
374
                #endif
375
 
376
                /* Check the data we read out is in the expected order. */
377
                for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
378
                {
379
                        if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
380
                        {
381
                                xErrorDetected = pdTRUE;
382
                        }
383
 
384
                        if( ulData != ulData2 )
385
                        {
386
                                xErrorDetected = pdTRUE;
387
                        }
388
                }
389
 
390
                if( uxQueueMessagesWaiting( xQueue ) != 0 )
391
                {
392
                        xErrorDetected = pdTRUE;
393
                }
394
 
395
                ulLoopCounter++;
396
        }
397
}
398
/*-----------------------------------------------------------*/
399
 
400
static void prvLowPriorityMutexTask( void *pvParameters )
401
{
402
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
403
 
404
        #ifdef USE_STDIO
405
        void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
406
 
407
                const portCHAR * const pcTaskStartMsg = "Fast mutex with priority inheritance test started.\r\n";
408
 
409
                /* Queue a message for printing to say the task has started. */
410
                vPrintDisplayMessage( &pcTaskStartMsg );
411
        #endif
412
 
413
        ( void ) pvParameters;
414
 
415
 
416
        for( ;; )
417
        {
418
                /* Take the mutex.  It should be available now. */
419
                if( xSemaphoreAltTake( xMutex, genqNO_BLOCK ) != pdPASS )
420
                {
421
                        xErrorDetected = pdTRUE;
422
                }
423
 
424
                /* Set our guarded variable to a known start value. */
425
                ulGuardedVariable = 0;
426
 
427
                /* Our priority should be as per that assigned when the task was
428
                created. */
429
                if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
430
                {
431
                        xErrorDetected = pdTRUE;
432
                }
433
 
434
                /* Now unsuspend the high priority task.  This will attempt to take the
435
                mutex, and block when it finds it cannot obtain it. */
436
                vTaskResume( xHighPriorityMutexTask );
437
 
438
                /* We should now have inherited the prioritoy of the high priority task,
439
                as by now it will have attempted to get the mutex. */
440
                if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
441
                {
442
                        xErrorDetected = pdTRUE;
443
                }
444
 
445
                /* We can attempt to set our priority to the test priority - between the
446
                idle priority and the medium/high test priorities, but our actual
447
                prioroity should remain at the high priority. */
448
                vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
449
                if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
450
                {
451
                        xErrorDetected = pdTRUE;
452
                }
453
 
454
                /* Now unsuspend the medium priority task.  This should not run as our
455
                inherited priority is above that of the medium priority task. */
456
                vTaskResume( xMediumPriorityMutexTask );
457
 
458
                /* If the did run then it will have incremented our guarded variable. */
459
                if( ulGuardedVariable != 0 )
460
                {
461
                        xErrorDetected = pdTRUE;
462
                }
463
 
464
                /* When we give back the semaphore our priority should be disinherited
465
                back to the priority to which we attempted to set ourselves.  This means
466
                that when the high priority task next blocks, the medium priority task
467
                should execute and increment the guarded variable.   When we next run
468
                both the high and medium priority tasks will have been suspended again. */
469
                if( xSemaphoreAltGive( xMutex ) != pdPASS )
470
                {
471
                        xErrorDetected = pdTRUE;
472
                }
473
 
474
                /* Check that the guarded variable did indeed increment... */
475
                if( ulGuardedVariable != 1 )
476
                {
477
                        xErrorDetected = pdTRUE;
478
                }
479
 
480
                /* ... and that our priority has been disinherited to
481
                genqMUTEX_TEST_PRIORITY. */
482
                if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
483
                {
484
                        xErrorDetected = pdTRUE;
485
                }
486
 
487
                /* Set our priority back to our original priority ready for the next
488
                loop around this test. */
489
                vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
490
 
491
                /* Just to show we are still running. */
492
                ulLoopCounter2++;
493
 
494
                #if configUSE_PREEMPTION == 0
495
                        taskYIELD();
496
                #endif          
497
        }
498
}
499
/*-----------------------------------------------------------*/
500
 
501
static void prvMediumPriorityMutexTask( void *pvParameters )
502
{
503
        ( void ) pvParameters;
504
 
505
        for( ;; )
506
        {
507
                /* The medium priority task starts by suspending itself.  The low
508
                priority task will unsuspend this task when required. */
509
                vTaskSuspend( NULL );
510
 
511
                /* When this task unsuspends all it does is increment the guarded
512
                variable, this is so the low priority task knows that it has
513
                executed. */
514
                ulGuardedVariable++;
515
        }
516
}
517
/*-----------------------------------------------------------*/
518
 
519
static void prvHighPriorityMutexTask( void *pvParameters )
520
{
521
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
522
 
523
        ( void ) pvParameters;
524
 
525
        for( ;; )
526
        {
527
                /* The high priority task starts by suspending itself.  The low
528
                priority task will unsuspend this task when required. */
529
                vTaskSuspend( NULL );
530
 
531
                /* When this task unsuspends all it does is attempt to obtain
532
                the mutex.  It should find the mutex is not available so a
533
                block time is specified. */
534
                if( xSemaphoreAltTake( xMutex, portMAX_DELAY ) != pdPASS )
535
                {
536
                        xErrorDetected = pdTRUE;
537
                }
538
 
539
                /* When we eventually obtain the mutex we just give it back then
540
                return to suspend ready for the next test. */
541
                if( xSemaphoreAltGive( xMutex ) != pdPASS )
542
                {
543
                        xErrorDetected = pdTRUE;
544
                }
545
        }
546
}
547
/*-----------------------------------------------------------*/
548
 
549
/* This is called to check that all the created tasks are still running. */
550
portBASE_TYPE xAreAltGenericQueueTasksStillRunning( void )
551
{
552
static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
553
 
554
        /* If the demo task is still running then we expect the loopcounters to
555
        have incremented since this function was last called. */
556
        if( ulLastLoopCounter == ulLoopCounter )
557
        {
558
                xErrorDetected = pdTRUE;
559
        }
560
 
561
        if( ulLastLoopCounter2 == ulLoopCounter2 )
562
        {
563
                xErrorDetected = pdTRUE;
564
        }
565
 
566
        ulLastLoopCounter = ulLoopCounter;
567
        ulLastLoopCounter2 = ulLoopCounter2;
568
 
569
        /* Errors detected in the task itself will have latched xErrorDetected
570
        to true. */
571
 
572
        return !xErrorDetected;
573
}
574
 
575
 

powered by: WebSVN 2.1.0

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