]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/sched_table.c
9aa5edb7f60c9a507d8fde72e34ba5550ecc06c6
[arc.git] / system / kernel / sched_table.c
1 /* -------------------------------- Arctic Core ------------------------------
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com
3  *
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>
5  *
6  * This source code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by the
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  * -------------------------------- Arctic Core ------------------------------*/
15
16 #include "Os.h"
17 #include "internal.h"\r
18 #include "alist_i.h"
19
20 /*
21  * Generic requirements this module can handle
22  */
23  /** @req OS007 */
24  /** @req OS410 */
25  /** @req OS411 */
26  /** @req OS347 */
27  /** @req OS358 */
28  /** @req OS428 */
29 \r
30 /*\r
31  * How Autosar sees the scheduletable\r
32  *\r
33  * duration\r
34  * repeating\r
35  * accessionApplication\r
36  * counterRef\r
37  * autostart [0..1]\r
38  * |--- absValue   (only if type==ABSOLUTE )\r
39  * |--- relOffset  (only if type==RELATIVE )\r
40  * |--- type       (ABSOLUTE, RELATIVE, SYNCHRON )\r
41  * |--- modeRef\r
42  * |\r
43  * expiryPoint [1..*]\r
44  * |--- offset\r
45  * |--- EventSetting [0..*]\r
46  * |    |--- SetEvent\r
47  * |    `--- SetEventTaskRef\r
48  * |\r
49  * |--- TaskActivation [0..*]\r
50  * |    `- TaskRef\r
51  * |\r
52  * |--- AdjustableExpPoint [0..1] (only if syncStrategy!=NONE)\r
53  * |    |--- maxAdvance\r
54  * |    `--- macRetard\r
55  * |\r
56  * sync\r
57  * |--- explicitPrecision (only if syncStrategy==EXPLICIT )\r
58  * |--- syncStrategy      (NONE,EXPLICIT,IMPLICIT )\r
59  *
60  */\r
61 \r
62 \r
63 // Cancel\r
64 \r
65 #define SCHED_CHECK_ID(x)                               \\r
66         if( (x) > Os_CfgGetSchedCnt()) { \\r
67                 rv = E_OS_ID;                                   \\r
68                 goto err;                                               \\r
69         }\r
70 \r
71 #define SCHED_STD_END   \\r
72                 return rv;              \\r
73         err:                            \\r
74                 ERRORHOOK(rv);  \\r
75                 return rv;\r
76 \r
77 extern TickType GetCountValue( OsCounterType *counter );\r
78
79
80 #if 0\r
81 enum OsScheduleTableSyncStrategy getSyncStrategy( OsSchTblType *stblPtr ) {\r
82         return stblPtr->sync.syncStrategy;\r
83 }\r
84 #endif
85 \r
86 \r
87 /**\r
88  * Consistency checks for scheduletables. This should really be checked by\r
89  * the generator.\r
90  *\r
91  * See chapter 11.2.\r
92  *
93  * @return
94  */\r
95 static void ScheduleTableConsistenyCheck( OsSchTblType *sTblPtr ) {\r
96
97 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )\r
98         /** @req OS440 */\r
99         if( sTblPtr->sync.syncStrategy == IMPLICIT ) {\r
100                 assert( sTblPtr->duration == (sTblPtr->counter->alarm_base.maxallowedvalue +1) );\r
101         }\r
102 \r
103         /** @req OS431 */\r
104         if( sTblPtr->sync.syncStrategy == EXPLICIT ) {\r
105                 assert( sTblPtr->duration <= (sTblPtr->counter->alarm_base.maxallowedvalue +1) );\r
106         }
107 #endif
108
109         /** @req OS401 */
110         assert(SA_LIST_CNT(&sTblPtr->expirePointList)>=1);
111
112
113
114         {
115                 int iter;
116                 TickType delta = 0;
117                 TickType minCycle = Os_CounterGetMinCycle(sTblPtr->counter);
118                 TickType maxValue =  Os_CounterGetMaxValue(sTblPtr->counter);
119
120                 /* - start at offset=0
121                  * - X expiry points = SA_LIST_CNT
122                  * - Final offset.
123                  */
124                 /** @req OS443 */
125                 /** @req OS408 */
126                 for(iter=0; iter  <  SA_LIST_CNT(&sTblPtr->expirePointList) ; iter++) {
127                         delta = SA_LIST_GET(&sTblPtr->expirePointList,iter)->offset - delta;
128                         assert( delta >=  minCycle );
129                         assert( delta <=  maxValue );
130                 }
131
132                 /* Final */
133                 /** @req OS444 */
134                 delta = sTblPtr->duration - SA_LIST_GET(&sTblPtr->expirePointList,iter-1)->offset;
135                 assert( delta >=  minCycle );
136                 assert( delta <=  maxValue );
137         }
138
139 }\r
140 \r
141 StatusType StartScheduleTableRel(ScheduleTableType sid, TickType offset) {\r
142         StatusType rv = E_OK;\r
143         OsSchTblType *sPtr;\r
144         TickType max_offset;
145
146
147 #if (OS_STATUS_EXTENDED == STD_ON )\r
148         /** @req OS275 */
149         SCHED_CHECK_ID(sid);
150 #endif
151 \r
152         sPtr = Os_CfgGetSched(sid);
153
154 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )
155         if( sPtr->sync != NULL ) {
156                 /* EXPLICIT or IMPLICIT */
157
158                 /** @req OS452 */
159                 if( sPtr->sync->syncStrategy == IMPLICIT ) {
160                         rv = E_OS_ID;
161                         goto err;
162                 }
163         }
164 #endif
165
166         max_offset = Os_CounterGetMaxValue(sPtr->counter);
167 #if (OS_STATUS_EXTENDED == STD_ON )
168         /** @req OS276 */
169         /** @req OS332 */
170         if( (offset == 0) || ((offset + Os_SchTblGetInitialOffset(sPtr)) > max_offset ) ) {\r
171                 rv = E_OS_VALUE;\r
172                 goto err;\r
173         }
174 #endif\r
175 \r
176         /** @req OS277 */\r
177         if( sPtr->state != SCHEDULETABLE_STOPPED ) {\r
178                 rv = E_OS_STATE;
179                 goto err;\r
180         }\r
181
182         Irq_Disable();\r
183         /* calculate the expire value.. */
184         /** @req OS278 */\r
185         sPtr->expire_val = Os_CounterAdd(
186                                                         Os_CounterGetValue(sPtr->counter),
187                                                         max_offset,
188                                                         offset + Os_SchTblGetInitialOffset(sPtr) );\r
189         sPtr->state = SCHEDULETABLE_RUNNING;\r
190         Irq_Enable();
191 \r
192         SCHED_STD_END;\r
193 }\r
194 \r
195 StatusType StartScheduleTableAbs(ScheduleTableType sid, TickType start ){
196         StatusType rv = E_OK;
197         OsSchTblType *sTblPtr;\r
198
199         /** @req OS348 */\r
200         SCHED_CHECK_ID(sid);
201         sTblPtr =  Os_CfgGetSched(sid);\r
202
203         /** @req OS349 */
204         if( start > Os_CounterGetMaxValue(sTblPtr->counter) ) {
205                 rv = E_OS_VALUE;
206                 goto err;
207         }
208
209         /** @req OS350 */
210         if( sTblPtr->state != SCHEDULETABLE_STOPPED ) {
211                 rv = E_OS_STATE;
212                 goto err;
213         }
214
215
216         Irq_Disable();
217         /** @req OS351 */
218         sTblPtr->expire_val = start + Os_SchTblGetInitialOffset(sTblPtr);
219         sTblPtr->state = SCHEDULETABLE_RUNNING;
220         Irq_Enable();
221
222         SCHED_STD_END;
223 }\r
224 \r
225 /**\r
226  *
227  * @param sid
228  * @return
229  */\r
230 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )
231 \r
232 StatusType StartScheduleTableSynchron(ScheduleTableType sid ){\r
233         OsSchTblType *s_p;\r
234         StatusType rv = E_OK;\r
235 \r
236         Irq_Disable();\r
237 \r
238         SCHED_CHECK_ID(sid);\r
239 \r
240         /** @req OS387 */\r
241         if( s_p->sync.syncStrategy != EXPLICIT ) {\r
242                 rv = E_OS_ID;\r
243                 goto err;\r
244         }\r
245 \r
246         /** @req OS388 */\r
247         if( s_p->state != SCHEDULETABLE_STOPPED ) {\r
248                 rv = E_OS_STATE;\r
249                 goto err;\r
250         }\r
251 \r
252         /** @req OS389 */\r
253         s_p->state = SCHEDULETABLE_WAITING;\r
254 \r
255         Irq_Enable();\r
256 \r
257         SCHED_STD_END;\r
258 }\r
259 #endif
260 \r
261
262 \r
263 /** @req OS006 */
264 /* TODO: Implement StopScheduleTable */\r
265 StatusType StopScheduleTable(ScheduleTableType sid) {\r
266         StatusType rv = E_OK;\r
267         OsSchTblType *sPtr;
268         /** @req OS279 */\r
269         SCHED_CHECK_ID(sid);\r
270         sPtr = Os_CfgGetSched(sid);
271
272         /** @req OS280 */
273         if(sPtr->state == SCHEDULETABLE_STOPPED ) {
274                 rv = E_OS_NOFUNC;
275                 goto err;
276         }\r
277
278         /** @req OS281 */
279         sPtr->state = SCHEDULETABLE_STOPPED;\r
280 \r
281         SCHED_STD_END;\r
282 }\r
283
284 /** @req OS191 */\r
285 StatusType NextScheduleTable( ScheduleTableType sid_curr, ScheduleTableType sid_next) {\r
286         StatusType rv = E_OK;\r
287         (void)sid_curr;\r
288         (void)sid_next;\r
289 \r
290         OsSchTblType *sFromPtr;\r
291         OsSchTblType *sToPtr;\r
292
293         /** @req OS282 */\r
294         SCHED_CHECK_ID(sid_curr);\r
295         SCHED_CHECK_ID(sid_next);\r
296 \r
297         sFromPtr = Os_CfgGetSched(sid_curr);\r
298         sToPtr = Os_CfgGetSched(sid_curr);\r
299 \r
300         /** @req OS330 */\r
301         if( sFromPtr->counter != sToPtr->counter) {\r
302                 rv = E_OS_ID;\r
303                 goto err;\r
304         }\r
305 \r
306         /** @req OS283 */\r
307         if( sFromPtr->state == SCHEDULETABLE_STOPPED ||\r
308                 sFromPtr->state == SCHEDULETABLE_NEXT )\r
309         {\r
310                 rv = E_OS_NOFUNC;\r
311                 goto err;\r
312         }\r
313 \r
314         /** @req OS309 */\r
315         if( sToPtr->state != SCHEDULETABLE_STOPPED ) {\r
316                 rv = E_OS_STATE;\r
317                 goto err;\r
318         }
319
320         Irq_Disable();
321
322         /** @req OS453 */
323         if( sFromPtr->state == SCHEDULETABLE_STOPPED ) {
324                 sFromPtr->next->state = SCHEDULETABLE_STOPPED;
325         } else {
326                 /** @req OS324 */
327                 if( sFromPtr->next != NULL ) {
328                         // Stop the schedule-table that was to be next.
329                         sFromPtr->next->state = SCHEDULETABLE_STOPPED;
330                 }
331
332                 sFromPtr->next = sToPtr;
333                 sToPtr->state = SCHEDULETABLE_NEXT;
334                 sToPtr->expire_curr_index = 0;
335         }
336 \r
337         Irq_Enable();\r
338 \r
339         SCHED_STD_END;\r
340 }\r
341 \r
342 \r
343 \r
344 /**\r
345  *
346  * @param sid
347  * @param globalTime
348  * @return
349  */
350 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )\r
351 StatusType SyncScheduleTable( ScheduleTableType sid, GlobalTimeTickType globalTime  ) {\r
352         StatusType rv = E_OK;\r
353         OsSchTblType *s_p =  Os_CfgGetSched(sid);\r
354 \r
355         SCHED_CHECK_ID(sid);\r
356
357 \r
358         /** @req OS454 */\r
359         if( s_p->sync.syncStrategy != EXPLICIT ) {\r
360                 rv =  E_OS_ID;\r
361                 goto err;\r
362         }\r
363 \r
364         /** @req OS455 */\r
365         if( globalTime > s_p->duration ) {\r
366                 rv = E_OS_VALUE;\r
367                 goto err;\r
368         }\r
369 \r
370         Irq_Disable();\r
371 \r
372         /** @req OS456 */\r
373         if( (s_p->state == SCHEDULETABLE_STOPPED) ||\r
374                 (s_p->state == SCHEDULETABLE_NEXT)      ) {\r
375                 rv = E_OS_STATE;\r
376                 goto err;\r
377         }\r
378 \r
379         switch(s_p->state) {\r
380         case  SCHEDULETABLE_WAITING:\r
381                 // First time we called since started. Set the sync counter to\r
382                 // the value provided.\r
383                 s_p->sync.syncCounter = globalTime;\r
384                 s_p->state = SCHEDULETABLE_RUNNING_AND_SYNCHRONOUS;\r
385                 break;\r
386 \r
387         case SCHEDULETABLE_RUNNING:\r
388         case SCHEDULETABLE_RUNNING_AND_SYNCHRONOUS:\r
389                 s_p->sync.deviation = s_p->sync.syncCounter - globalTime;\r
390                 if( s_p->sync.deviation != 0 ) {\r
391                         // We are not at sync any more...\r
392                         s_p->state = SCHEDULETABLE_RUNNING;\r
393                 }\r
394                 break;\r
395 \r
396         default:\r
397                 assert(0);\r
398                 break;\r
399         }\r
400 \r
401         Irq_Enable();\r
402 \r
403         SCHED_STD_END;\r
404 }\r
405 #endif
406
407 \r
408 /**\r
409  *
410  * @param sid
411  * @param status
412  * @return
413  */
414
415 /** @req OS359 */
416 /** @req OS227 */\r
417 StatusType GetScheduleTableStatus( ScheduleTableType sid, ScheduleTableStatusRefType status ) {\r
418         StatusType rv = E_OK;\r
419         OsSchTblType *s_p;\r
420         (void)status;
421         /** @req OS293 */\r
422         SCHED_CHECK_ID(sid);\r
423 \r
424         s_p = Os_CfgGetSched(sid);\r
425         Irq_Disable();\r
426 \r
427         switch(s_p->state) {
428                 /** @req OS289 */\r
429         case SCHEDULETABLE_STOPPED:
430                 /** @req OS353 */\r
431         case SCHEDULETABLE_NEXT:
432                 /** @req OS290 */\r
433         case SCHEDULETABLE_RUNNING_AND_SYNCHRONOUS:
434                 /** @req OS354 */\r
435         case SCHEDULETABLE_WAITING:
436                 /** @req OS291 */\r
437         case SCHEDULETABLE_RUNNING:\r
438                 *status = s_p->state;\r
439                 break;\r
440         default:\r
441                 assert(0);\r
442 \r
443         }\r
444 \r
445         Irq_Enable();\r
446 \r
447         SCHED_STD_END;\r
448 }\r
449 \r
450 \r
451 /**\r
452  *
453  * @param sid
454  * @return
455  */
456 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )\r
457 StatusType SetScheduleTableAsync( ScheduleTableType sid ) {\r
458         StatusType rv = E_OK;\r
459         OsSchTblType *s_p = Os_CfgGetSched(sid);\r
460 \r
461         SCHED_CHECK_ID(sid);\r
462 \r
463         /** @req OS458 */\r
464         if( s_p->sync.syncStrategy != EXPLICIT ) {\r
465                 rv = E_OS_ID;\r
466                 goto err;\r
467         }\r
468 \r
469         Irq_Disable();\r
470 \r
471         /** @req_todo OS362 */
472         /** @req_todo OS323 */\r
473 \r
474         /** @req OS300 */\r
475         s_p->state = SCHEDULETABLE_RUNNING;\r
476 \r
477         Irq_Enable();\r
478 \r
479         SCHED_STD_END;\r
480 }\r
481 #endif
482
483
484
485 /**
486  * Go through the schedule tables connected to this counter
487  *
488  * @param c_p Pointer to counter object
489  */
490 void Os_SchTblCheck(OsCounterType *c_p) {
491         /** @req OS002 */
492         /** @req OS007 */
493
494         OsSchTblType *sched_obj;
495
496         /* Iterate through the schedule tables */
497         SLIST_FOREACH(sched_obj,&c_p->sched_head,sched_list) {
498
499                 if( sched_obj->state == SCHEDULETABLE_STOPPED ) {
500                         continue;
501                 }
502
503 #if ( OS_SC2 == STD_ON ) || ( OS_SC4 == STD_ON )
504                 if( sched_obj->sync.syncStrategy == IMPLICIT ) {
505                         // ....
506
507                 } else {
508                         int adj;
509                         // Handle EXPLICIT
510                         if( sched_obj->sync.deviation > 0 ) {
511                                 // The sync counter was set back ==
512                                 // we have more time to complete the table
513                                 adj = MIN(sched_obj->sync.deviation, getAdjExpPoint(sched_obj)->maxAdvance );
514                                 sched_obj->sync.deviation -= adj;
515
516                         } else if( sched_obj->sync.deviation < 0 ) {
517                                 // The sync counter was set forward ==
518                                 // we have less time to complete the table
519                                 adj = MIN((-sched_obj->sync.deviation), getAdjExpPoint(sched_obj)->maxRetard);
520                                 sched_obj->sync.deviation -= adj;
521
522                         } else {
523                                 // all is well
524                                 sched_obj->state = SCHEDULETABLE_RUNNING_AND_SYNCHRONOUS;
525                         }
526                 }
527 #endif
528
529                 /* Check if the expire point have been hit */
530                 if( (sched_obj->state == SCHEDULETABLE_RUNNING ||
531                         sched_obj->state == SCHEDULETABLE_RUNNING_AND_SYNCHRONOUS ) &&
532                         (c_p->val == sched_obj->expire_val) )
533                 {
534                         if ( sched_obj->expire_curr_index < SA_LIST_CNT(&sched_obj->expirePointList) ) {
535                                 OsScheduleTableExpiryPointType * action;
536                                 int i;
537
538                                 action = SA_LIST_GET(&sched_obj->expirePointList,sched_obj->expire_curr_index);
539
540                                 /** @req OS407 */
541                                 /** @req OS412 */
542
543                                 /* According to OS412 activate tasks before events */
544                                 for(i=0; i< action->taskListCnt;i++ ) {
545                                         ActivateTask(action->taskList[i]);
546                                 }
547
548                                 for(i=0; i< action->eventListCnt;i++ ) {
549                                         SetEvent( action->eventList[i].task, action->eventList[i].event);
550                                 }
551                         }
552                         // Calc new expire val and state
553                         Os_SchTblUpdateState(sched_obj);
554                 }
555
556         }
557 }
558 \r
559 /**\r
560  *
561  */\r
562 void Os_SchTblInit( void ) {\r
563         OsSchTblType *s_p;\r
564         for( int i=0; i < Os_CfgGetSchedCnt();i++ ) {\r
565                 s_p = Os_CfgGetSched(i);
566 \r
567                 ScheduleTableConsistenyCheck(s_p);\r
568         }\r
569 }\r
570
571 void Os_SchTblAutostart( void ) {
572
573         for(int j=0; j < Os_CfgGetSchedCnt(); j++ ) {
574                 OsSchTblType *sPtr;
575                 sPtr = Os_CfgGetSched(j);
576
577                 if( sPtr->autostartPtr != NULL ) {
578                         const struct OsSchTblAutostart *autoPtr = sPtr->autostartPtr;
579
580                         /* Check appmode */
581                         if( os_sys.appMode & autoPtr->appMode ) {
582
583                                 /* Start the schedule table */
584                                 switch(autoPtr->type) {
585                                 case SCHTBL_AUTOSTART_ABSOLUTE:
586                                         StartScheduleTableAbs(j,autoPtr->offset);
587                                         break;
588                                 case SCHTBL_AUTOSTART_RELATIVE:
589                                         StartScheduleTableRel(j,autoPtr->offset);
590                                         break;
591         #if defined(OS_SC2) || defined(OS_SC4)
592                                 case SCHTBL_AUTOSTART_SYNCHRONE:
593                                         /* TODO: */
594                                         break;
595         #endif
596                                 default:
597                                         assert(0);              // Illegal value
598                                         break;
599                                 }
600                         }
601                 }
602         }
603 }
604
605 \r
606 /**\r
607  * Calculates expire value and changes state depending it's state.
608  *
609  * Note!
610  * We can't cheat with the final + initial expire-point, instead we
611  * must setup trigger after the final delay and set the "previous"
612  * table to SCHEDULETABLE_STOPPED and the new to SCHEDULETABLE_RUNNING.
613  *
614  * @param stbl Ptr to a Schedule Table.
615  */\r
616 void Os_SchTblUpdateState( OsSchTblType *stbl ) {\r
617 \r
618         TickType delta;
619         TickType initalOffset;
620         TickType finalOffset;
621         OsSchTblType *nextStblPtr;
622         _Bool handleLast = 0;
623
624         if( (stbl->expire_curr_index) == (SA_LIST_CNT(&stbl->expirePointList) - 1) ) {
625                 /* We are at the last expiry point */
626                 finalOffset = Os_SchTblGetFinalOffset(stbl);
627
628                 if (finalOffset != 0) {
629                         stbl->expire_val =      Os_CounterAdd(
630                                                         Os_CounterGetValue(stbl->counter),
631                                                         Os_CounterGetMaxValue(stbl->counter),
632                                                         finalOffset );
633
634                         stbl->expire_curr_index++;
635                         return;
636                 } else {
637                         /* Only single shot may have an offset of 0 */
638                         assert(stbl->repeating == SINGLE_SHOT);
639                         handleLast = 1;
640                 }
641         }
642
643         if( handleLast ||
644                 ( (stbl->expire_curr_index) == SA_LIST_CNT(&stbl->expirePointList) ) )
645         {
646                 /* At final offset */
647                 /** @req OS194 */
648                 if( (stbl->repeating == REPEATING) || (stbl->next != NULL) ) {
649                         if( stbl->next != NULL ) {
650                                 /** @req OS284 */
651                                 nextStblPtr = stbl->next;
652                                 /* NextScheduleTable() have been called */
653                                 assert( nextStblPtr->state==SCHEDULETABLE_NEXT );
654
655                                 /* We don't care about REPEATING or SINGLE_SHOT here */
656                                 initalOffset = Os_SchTblGetInitialOffset(nextStblPtr);
657                                 stbl->state = SCHEDULETABLE_STOPPED;
658                                 nextStblPtr->state = SCHEDULETABLE_RUNNING;
659                         } else {
660                                 /** @req OS414 */
661
662                                 /* REPEATING */
663                                 assert( stbl->repeating == REPEATING );
664                                 initalOffset = Os_SchTblGetInitialOffset(stbl);
665                         }
666
667                         stbl->expire_val =      Os_CounterAdd(
668                                                         Os_CounterGetValue(stbl->counter),
669                                                         Os_CounterGetMaxValue(stbl->counter),
670                                                         initalOffset );
671
672                 } else {
673                         assert( stbl->repeating == SINGLE_SHOT );
674                         /** @req OS009 */
675                         stbl->state = SCHEDULETABLE_STOPPED;
676                 }
677                 stbl->expire_curr_index = 0;
678
679         } else {
680
681                 delta = SA_LIST_GET(&stbl->expirePointList,stbl->expire_curr_index+1)->offset -
682                                 SA_LIST_GET(&stbl->expirePointList,stbl->expire_curr_index)->offset ;
683
684                 stbl->expire_val =      Os_CounterAdd(
685                                                 Os_CounterGetValue(stbl->counter),
686                                                 Os_CounterGetMaxValue(stbl->counter),
687                                                 delta );
688
689                 stbl->expire_curr_index++;
690
691         }
692
693         return;\r
694 }\r
695 \r
696 \r