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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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