void tcpcb_expire_timeouts(void) { struct tcpcb_list_s *n = tcpcbs, *next; while (n) { next = n->next; switch (n->tcpcb.state) { case TS_TIME_WAIT: if (TIME_GT(Now, n->tcpcb.time_wait_exp)) { LEAVE_TIME_WAIT(&n->tcpcb); tcpcb_remove(n); } break; case TS_FIN_WAIT_1: case TS_FIN_WAIT_2: case TS_LAST_ACK: case TS_CLOSING: if (TIME_GT(Now - (240 << 4), n->tcpcb.time_wait_exp)) { cbs_in_user_timeout--; tcpcb_remove(n); } break; } n = next; } }
/* insert a non-pending timer into the scheduler */ void __ci_ip_timer_set(ci_netif *netif, ci_ip_timer *ts, ci_iptime_t t) { ci_ni_dllist_t* bucket; int w; ci_iptime_t stime = IPTIMER_STATE(netif)->sched_ticks; ci_assert(TIME_GT(t, stime)); /* this is absolute time */ ts->time = t; if( TIME_LT(t, IPTIMER_STATE(netif)->closest_timer) ) IPTIMER_STATE(netif)->closest_timer = t; /* Previous error in this code was to choose wheel based on time delta * before timer fires (ts->time - stime). This is bogus as the timer wheels * work like a clock and we need to find wheel based on the absolute time */ /* insert in wheel 0 if the top 3 wheels have the same time */ if ((stime & WHEEL0_MASK) == (t & WHEEL0_MASK)) w = 0; /* else, insert in wheel 1 if the top 2 wheels have the same time */ else if ((stime & WHEEL1_MASK) == (t & WHEEL1_MASK)) w = 1; /* else, insert in wheel 2 if the top wheel has the same time */ else if ((stime & WHEEL2_MASK) == (t & WHEEL2_MASK)) w = 2; else w = 3; bucket = BUCKET(netif, w, t); LOG_ITV(log("%s: delta=0x%x (t=0x%x-s=0x%x), w=0x%x, b=0x%x", __FUNCTION__, ts->time-stime, ts->time, stime, w, BUCKETNO(w, ts->time))); /* append onto the correct bucket ** ** NB this might not be stable because a later insert with a ** smaller relative time will be before an earlier insert with a ** larger relative time. Oh well doesn't really matter */ ci_ni_dllist_push_tail(netif, bucket, &ts->link); ci_assert(ci_ip_timer_is_link_valid(netif, ts)); DETAILED_CHECK_TIMERS(netif); }
void ci_ip_timer_state_assert_valid(ci_netif* ni, const char* file, int line) { ci_ip_timer_state* ipts; ci_ip_timer* ts; ci_ni_dllist_t* bucket; ci_ni_dllist_link* l; ci_iptime_t stime, wheel_base, max_time, min_time; int a1, a2, a3, w, b, bit_shift; /* shifting a 32 bit integer left or right 32 bits has undefined results * (i.e. not 0 which is required). Therefore I now use an array of mask * values */ unsigned wheel_mask[CI_IPTIME_WHEELS] = { WHEEL0_MASK, WHEEL1_MASK, WHEEL2_MASK, 0 }; ipts = IPTIMER_STATE(ni); stime = ipts->sched_ticks; /* for each wheel */ for(w=0; w < CI_IPTIME_WHEELS; w++) { /* base time of wheel */ wheel_base = stime & wheel_mask[w]; /* for each bucket in wheel */ for (b=0; b < CI_IPTIME_BUCKETS; b++) { /* max and min relative times for this bucket */ bit_shift = CI_IPTIME_BUCKETBITS*w; min_time = wheel_base + (b << bit_shift); max_time = min_time + (1 << bit_shift); bucket = &ipts->warray[w*CI_IPTIME_BUCKETS + b]; /* check list looks valid */ if ( ci_ni_dllist_start(ni, bucket) == ci_ni_dllist_end(ni, bucket) ) { ci_assert( ci_ni_dllist_is_empty(ni, bucket) ); } /* check buckets that should be empty are! */ a3 = TIME_GT(min_time, stime) || ci_ni_dllist_is_empty(ni, bucket); /* run through timers in bucket */ for (l = ci_ni_dllist_start(ni, bucket); l != ci_ni_dllist_end(ni, bucket); ci_ni_dllist_iter(ni, l) ) { ci_ni_dllist_link_assert_valid(ni, l); /* get timer */ ts = LINK2TIMER(l); /* must be in the future */ a1 = TIME_GT(ts->time, stime); /* must be within time range of bucket */ a2 = TIME_LT(ts->time, max_time) && TIME_GE(ts->time, min_time); /* if any of the checks fail then print out timer details */ if (!a1 || !a2 || !a3) { ci_log("%s: [w=0x%x/b=0x%x] stime=0x%x", __FUNCTION__, w, b, stime); ci_log(" --> t=0x%x, min=0x%x, max=0x%x", ts->time, min_time, max_time); ci_log(" [%s line=%d]", file, line); } /* stop if assertion failed */ ci_assert(a1 && a2 && a3); } } } }