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

Subversion Repositories openfire2

[/] [openfire2/] [trunk/] [sw/] [freertos/] [croutine.c] - Blame information for rev 6

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 toni32
/*
2
        FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
3
 
4
        This file is part of the FreeRTOS.org distribution.
5
 
6
        FreeRTOS.org is free software; you can redistribute it and/or modify
7
        it under the terms of the GNU General Public License as published by
8
        the Free Software Foundation; either version 2 of the License, or
9
        (at your option) any later version.
10
 
11
        FreeRTOS.org is distributed in the hope that it will be useful,
12
        but WITHOUT ANY WARRANTY; without even the implied warranty of
13
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
        GNU General Public License for more details.
15
 
16
        You should have received a copy of the GNU General Public License
17
        along with FreeRTOS.org; if not, write to the Free Software
18
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
20
        A special exception to the GPL can be applied should you wish to distribute
21
        a combined work that includes FreeRTOS.org, without being obliged to provide
22
        the source code for any proprietary components.  See the licensing section
23
        of http://www.FreeRTOS.org for full details of how and when the exception
24
        can be applied.
25
 
26
        ***************************************************************************
27
        See http://www.FreeRTOS.org for documentation, latest information, license
28
        and contact details.  Please ensure to read the configuration and relevant
29
        port sections of the online documentation.
30
        ***************************************************************************
31
*/
32
 
33
#include "FreeRTOS.h"
34
#include "task.h"
35
#include "croutine.h"
36
 
37
/* Lists for ready and blocked co-routines. --------------------*/
38
static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ];  /*< Prioritised ready co-routines. */
39
static xList xDelayedCoRoutineList1;                                                                    /*< Delayed co-routines. */
40
static xList xDelayedCoRoutineList2;                                                                    /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
41
static xList * pxDelayedCoRoutineList;                                                                  /*< Points to the delayed co-routine list currently being used. */
42
static xList * pxOverflowDelayedCoRoutineList;                                                  /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
43
static xList xPendingReadyList;                                                                                 /*< Holds co-routines that have been readied by an external event.  They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
44
 
45
/* Other file private variables. --------------------------------*/
46
corCRCB * pxCurrentCoRoutine = NULL;
47
static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
48
static portTickType xCoRoutineTickCount = 0;
49
 
50
/* The initial state of the co-routine when it is created. */
51
#define corINITIAL_STATE        ( 0 )
52
 
53
/*
54
 * Place the co-routine represented by pxCRCB into the appropriate ready queue
55
 * for the priority.  It is inserted at the end of the list.
56
 *
57
 * This macro accesses the co-routine ready lists and therefore must not be
58
 * used from within an ISR.
59
 */
60
#define prvAddCoRoutineToReadyQueue( pxCRCB )                                                                                                                                           \
61
{                                                                                                                                                                                                                                       \
62
        if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority )                                                                                                                  \
63
        {                                                                                                                                                                                                                               \
64
                uxTopCoRoutineReadyPriority = pxCRCB->uxPriority;                                                                                                                       \
65
        }                                                                                                                                                                                                                               \
66
        vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) );  \
67
}
68
 
69
/*
70
 * Utility to ready all the lists used by the scheduler.  This is called
71
 * automatically upon the creation of the first co-routine.
72
 */
73
static void prvInitialiseCoRoutineLists( void );
74
 
75
/*
76
 * Co-routines that are readied by an interrupt cannot be placed directly into
77
 * the ready lists (there is no mutual exclusion).  Instead they are placed in
78
 * in the pending ready list in order that they can later be moved to the ready
79
 * list by the co-routine scheduler.
80
 */
81
static inline void prvCheckPendingReadyList( void );
82
 
83
/*
84
 * Macro that looks at the list of co-routines that are currently delayed to
85
 * see if any require waking.
86
 *
87
 * Co-routines are stored in the queue in the order of their wake time -
88
 * meaning once one co-routine has been found whose timer has not expired
89
 * we need not look any further down the list.
90
 */
91
static inline void prvCheckDelayedList( void );
92
 
93
/*-----------------------------------------------------------*/
94
 
95
signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
96
{
97
signed portBASE_TYPE xReturn;
98
corCRCB *pxCoRoutine;
99
 
100
        /* Allocate the memory that will store the co-routine control block. */
101
        pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
102
        if( pxCoRoutine )
103
        {
104
                /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
105
                be created and the co-routine data structures need initialising. */
106
                if( pxCurrentCoRoutine == NULL )
107
                {
108
                        pxCurrentCoRoutine = pxCoRoutine;
109
                        prvInitialiseCoRoutineLists();
110
                }
111
 
112
                /* Check the priority is within limits. */
113
                if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
114
                {
115
                        uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
116
                }
117
 
118
                /* Fill out the co-routine control block from the function parameters. */
119
                pxCoRoutine->uxState = corINITIAL_STATE;
120
                pxCoRoutine->uxPriority = uxPriority;
121
                pxCoRoutine->uxIndex = uxIndex;
122
                pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
123
 
124
                /* Initialise all the other co-routine control block parameters. */
125
                vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
126
                vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
127
 
128
                /* Set the co-routine control block as a link back from the xListItem.
129
                This is so we can get back to the containing CRCB from a generic item
130
                in a list. */
131
                listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
132
                listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
133
 
134
                /* Event lists are always in priority order. */
135
                listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
136
 
137
                /* Now the co-routine has been initialised it can be added to the ready
138
                list at the correct priority. */
139
                prvAddCoRoutineToReadyQueue( pxCoRoutine );
140
 
141
                xReturn = pdPASS;
142
        }
143
        else
144
        {
145
                xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
146
        }
147
 
148
        return xReturn;
149
}
150
/*-----------------------------------------------------------*/
151
 
152
void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
153
{
154
portTickType xTimeToWake;
155
 
156
        /* Calculate the time to wake - this may overflow but this is
157
        not a problem. */
158
        xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
159
 
160
        /* We must remove ourselves from the ready list before adding
161
        ourselves to the blocked list as the same list item is used for
162
        both lists. */
163
        vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
164
 
165
        /* The list item will be inserted in wake time order. */
166
        listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
167
 
168
        if( xTimeToWake < xCoRoutineTickCount )
169
        {
170
                /* Wake time has overflowed.  Place this item in the
171
                overflow list. */
172
                vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
173
        }
174
        else
175
        {
176
                /* The wake time has not overflowed, so we can use the
177
                current block list. */
178
                vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
179
        }
180
 
181
        if( pxEventList )
182
        {
183
                /* Also add the co-routine to an event list.  If this is done then the
184
                function must be called with interrupts disabled. */
185
                vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
186
        }
187
}
188
/*-----------------------------------------------------------*/
189
 
190
static inline void prvCheckPendingReadyList( void )
191
{
192
        /* Are there any co-routines waiting to get moved to the ready list?  These
193
        are co-routines that have been readied by an ISR.  The ISR cannot access
194
        the     ready lists itself. */
195
        while( !listLIST_IS_EMPTY( &xPendingReadyList ) )
196
        {
197
                corCRCB *pxUnblockedCRCB;
198
 
199
                /* The pending ready list can be accessed by an ISR. */
200
                portDISABLE_INTERRUPTS();
201
                {
202
                        pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyList) );
203
                        vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
204
                }
205
                portENABLE_INTERRUPTS();
206
 
207
                vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
208
                prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
209
        }
210
}
211
/*-----------------------------------------------------------*/
212
 
213
static inline void prvCheckDelayedList( void )
214
{
215
static portTickType xLastTickCount, xPassedTicks;
216
corCRCB *pxCRCB;
217
 
218
        xPassedTicks = xTaskGetTickCount() - xLastTickCount;
219
        while( xPassedTicks )
220
        {
221
                xCoRoutineTickCount++;
222
                xPassedTicks--;
223
 
224
                /* If the tick count has overflowed we need to swap the ready lists. */
225
                if( xCoRoutineTickCount == 0 )
226
                {
227
                        xList * pxTemp;
228
 
229
                        /* Tick count has overflowed so we need to swap the delay lists.  If there are
230
                        any items in pxDelayedCoRoutineList here then there is an error! */
231
                        pxTemp = pxDelayedCoRoutineList;
232
                        pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
233
                        pxOverflowDelayedCoRoutineList = pxTemp;
234
                }
235
 
236
                /* See if this tick has made a timeout expire. */
237
                while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL )
238
                {
239
                        if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
240
                        {
241
                                /* Timeout not yet expired. */
242
                                break;
243
                        }
244
 
245
                        portDISABLE_INTERRUPTS();
246
                        {
247
                                /* The event could have occurred just before this critical
248
                                section.  If this is the case then the generic list item will
249
                                have been moved to the pending ready list and the following
250
                                line is still valid.  Also the pvContainer parameter will have
251
                                been set to NULL so the following lines are also valid. */
252
                                vListRemove( &( pxCRCB->xGenericListItem ) );
253
 
254
                                /* Is the co-routine waiting on an event also? */
255
                                if( pxCRCB->xEventListItem.pvContainer )
256
                                {
257
                                        vListRemove( &( pxCRCB->xEventListItem ) );
258
                                }
259
                        }
260
                        portENABLE_INTERRUPTS();
261
 
262
                        prvAddCoRoutineToReadyQueue( pxCRCB );
263
                }
264
        }
265
 
266
        xLastTickCount = xCoRoutineTickCount;
267
}
268
/*-----------------------------------------------------------*/
269
 
270
void vCoRoutineSchedule( void )
271
{
272
        /* See if any co-routines readied by events need moving to the ready lists. */
273
        prvCheckPendingReadyList();
274
 
275
        /* See if any delayed co-routines have timed out. */
276
        prvCheckDelayedList();
277
 
278
        /* Find the highest priority queue that contains ready co-routines. */
279
        while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
280
        {
281
                if( uxTopCoRoutineReadyPriority == 0 )
282
                {
283
                        /* No more co-routines to check. */
284
                        return;
285
                }
286
                --uxTopCoRoutineReadyPriority;
287
        }
288
 
289
        /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
290
         of the same priority get an equal share of the processor time. */
291
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
292
 
293
        /* Call the co-routine. */
294
        ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
295
 
296
        return;
297
}
298
/*-----------------------------------------------------------*/
299
 
300
static void prvInitialiseCoRoutineLists( void )
301
{
302
unsigned portBASE_TYPE uxPriority;
303
 
304
        for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
305
        {
306
                vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
307
        }
308
 
309
        vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
310
        vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
311
        vListInitialise( ( xList * ) &xPendingReadyList );
312
 
313
        /* Start with pxDelayedCoRoutineList using list1 and the
314
        pxOverflowDelayedCoRoutineList using list2. */
315
        pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
316
        pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
317
}
318
/*-----------------------------------------------------------*/
319
 
320
signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
321
{
322
corCRCB *pxUnblockedCRCB;
323
signed portBASE_TYPE xReturn;
324
 
325
        /* This function is called from within an interrupt.  It can only access
326
        event lists and the pending ready list. */
327
        pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
328
        vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
329
        vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedCRCB->xEventListItem ) );
330
 
331
        if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
332
        {
333
                xReturn = pdTRUE;
334
        }
335
        else
336
        {
337
                xReturn = pdFALSE;
338
        }
339
 
340
        return xReturn;
341
}
342
 

powered by: WebSVN 2.1.0

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