Mercurial > flash_v2
diff packages/net/tcpip/current/src/ecos/timeout.c @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | 02ea4320376c |
| children | 6bd9d475ed4b |
line wrap: on
line diff
--- a/packages/net/tcpip/current/src/ecos/timeout.c +++ b/packages/net/tcpip/current/src/ecos/timeout.c @@ -41,8 +41,8 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): gthomas -// Contributors: gthomas +// Author(s): gthomas, hmt +// Contributors: gthomas, hmt // Date: 1999-02-05 // Description: Simple timeout functions //####DESCRIPTIONEND#### @@ -50,6 +50,7 @@ #include <sys/param.h> #include <pkgconf/net.h> #include <cyg/kernel/kapi.h> +#include <cyg/infra/cyg_ass.h> // Timeout support @@ -65,30 +66,55 @@ static timeout_entry timeouts[NTIMEOUTS] static cyg_handle_t timeout_alarm_handle; static cyg_alarm timeout_alarm; static cyg_int32 last_delta; +static cyg_tick_count_t last_set_time; + +extern cyg_uint32 cyg_in_softnet( void ); static void do_timeout(cyg_handle_t alarm, cyg_addrword_t data) { int i; cyg_int32 min_delta; - timeout_entry *e = timeouts; - min_delta = 0x7FFFFFFF; // Maxint - for (i = 0; i < NTIMEOUTS; i++, e++) { + timeout_entry *e; + + CYG_ASSERT( 0 < last_delta, "last_delta underflow" ); + + min_delta = last_delta; // local copy + last_delta = -1; // flag recursive call underway + + for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) { if (e->delta) { - e->delta -= last_delta; - if (e->delta == 0) { + CYG_ASSERT( e->delta >= min_delta, "e->delta underflow" ); + e->delta -= min_delta; + if (e->delta <= 0) { // Defensive // Time for this item to 'fire' - (e->fun)(e->arg); + timeout_fun *fun = e->fun; + void *arg = e->arg; + // Call it *after* cleansing the record e->fun = 0; - } else { - if (e->delta < min_delta) min_delta = e->delta; + e->delta = 0; + (*fun)(arg); } } } + + // Now scan for a new timeout *after* running all the callbacks + // (because they can add timeouts themselves) + min_delta = 0x7FFFFFFF; // Maxint + for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) + if (e->delta) + if (e->delta < min_delta) + min_delta = e->delta; + + CYG_ASSERT( 0 < min_delta, "min_delta underflow" ); + if (min_delta != 0x7FFFFFFF) { // Still something to do, schedule it - cyg_alarm_initialize(timeout_alarm_handle, cyg_current_time()+min_delta, 0); + last_set_time = cyg_current_time(); + cyg_alarm_initialize(timeout_alarm_handle, last_set_time+min_delta, 0); last_delta = min_delta; + } else { + last_delta = 0; // flag no activity } } @@ -96,18 +122,31 @@ cyg_uint32 timeout(timeout_fun *fun, void *arg, cyg_int32 delta) { int i; - cyg_int32 min_delta; static bool init = false; - timeout_entry *e = timeouts; + timeout_entry *e; cyg_uint32 stamp; + + CYG_ASSERT( 0 < delta, "delta is right now, or even sooner!" ); + + // this needs to be atomic wrt threads and DSRs + cyg_scheduler_lock(); + if (!init) { cyg_handle_t h; cyg_clock_to_counter(cyg_real_time_clock(), &h); cyg_alarm_create(h, do_timeout, 0, &timeout_alarm_handle, &timeout_alarm); init = true; } + + // Renormalize delta wrt the existing set alarm, if there is one + if ( last_delta > 0 ) + delta += (cyg_int32)(cyg_current_time() - last_set_time); + // So recorded_delta is set to either: + // alarm is active: delta + NOW - THEN + // alarm is inactive: delta + stamp = 0; // Assume no slots available - for (i = 0; i < NTIMEOUTS; i++, e++) { + for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) { if ((e->delta == 0) && (e->fun == 0)) { // Free entry e->delta = delta; @@ -117,31 +156,71 @@ timeout(timeout_fun *fun, void *arg, cyg break; } } - e = timeouts; - min_delta = 0x7FFFFFFF; - for (i = 0; i < NTIMEOUTS; i++, e++) { - if (e->delta && (e->delta < min_delta)) min_delta = e->delta; + + if ( stamp && // we did add a record AND + (0 == last_delta || // alarm was inactive OR + delta < last_delta) ) { // alarm was active but later than we need + + // (if last_delta is -1, this call is recursive from the handler so + // also do nothing in that case) + + // Here, we know the new item added is sooner than that which was + // most recently set, if any, so we can just go and set it up. + if ( 0 == last_delta ) + last_set_time = cyg_current_time(); + + // So we use, to set the alarm either: + // alarm is active: (delta + NOW - THEN) + THEN + // alarm is inactive: delta + NOW + // and in either case it is true that + // (recorded_delta + last_set_time) == (delta + NOW) + cyg_alarm_initialize(timeout_alarm_handle, last_set_time+delta, 0); + last_delta = delta; } - if (min_delta != 0x7FFFFFFF) { - // Still something to do, schedule it - cyg_alarm_initialize(timeout_alarm_handle, cyg_current_time()+min_delta, 0); - last_delta = min_delta; + // Otherwise, the alarm is active, AND it is set to fire sooner than we + // require, so when it does, that will sort out calling the item we + // just added. Or we didn't actually add a record, so nothing has + // changed. + +#ifdef CYGPKG_INFRA_DEBUG + // Do some more checking akin to that in the alarm handler: + if ( last_delta != -1 ) { // not a recursive call + CYG_ASSERT( last_delta >= 0, "Bad last delta" ); + delta = 0x7fffffff; + for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) { + if (e->delta) { + CYG_ASSERT( e->delta >= last_delta, "e->delta underflow" ); + CYG_ASSERT( last_set_time + e->delta > cyg_current_time(), + "Recorded alarm not in the future!" ); + if ( e->delta < delta ) + delta = e->delta; + } else { + CYG_ASSERT( 0 == e->fun, "Function recorded for 0 delta" ); + } + } + CYG_ASSERT( delta == last_delta, "We didn't pick the smallest delta!" ); } +#endif + + cyg_scheduler_unlock(); + return stamp; } void untimeout(timeout_fun *fun, void * arg) { - int i; - timeout_entry *e = timeouts; - - for (i = 0; i < NTIMEOUTS; i++, e++) { - if (e->delta && (e->fun == fun) && (e->arg == arg)) { + int i; + timeout_entry *e; + cyg_scheduler_lock(); + for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) { + if (e->delta && (e->fun == fun) && (e->arg == arg)) { e->delta = 0; e->fun = 0; - return; + break; } } + cyg_scheduler_unlock(); } +// EOF timeout.c
