/* 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); }
ci_inline ci_tcp_state* get_ts_from_cache(ci_netif *netif, ci_tcp_state_synrecv* tsr, ci_tcp_socket_listen* tls) { ci_tcp_state *ts = NULL; #if CI_CFG_FD_CACHING if( ci_ni_dllist_not_empty(netif, &tls->epcache.cache) ) { /* Take the entry from the cache */ ci_ni_dllist_link *link = ci_ni_dllist_pop(netif, &tls->epcache.cache); ts = CI_CONTAINER (ci_tcp_state, epcache_link, link); ci_assert (ts); ci_ni_dllist_self_link(netif, &ts->epcache_link); LOG_EP(ci_log("Taking cached fd %d off cached list, (onto acceptq)", ts->cached_on_fd)); if( tcp_laddr_be32(ts) == tsr->l_addr ) { ci_tcp_state_init(netif, ts, 1); /* Shouldn't have touched these bits of state */ ci_assert(!(ts->s.b.sb_aflags & CI_SB_AFLAG_ORPHAN)); ci_assert(ci_tcp_is_cached(ts)); CITP_STATS_NETIF(++netif->state->stats.sockcache_hit); CITP_STATS_TCP_LISTEN(++tls->stats.n_sockcache_hit); } else { /* Oh dear -- the tcp-state we cached was using a different local IP * address. This means we've accepted a connection from a different * interface as we did for the thing we've cached. Which means we * can't share the hardware filter after all. For now, just bung it * back on the list. */ LOG_EP(ci_log("changed interface of cached EP, re-queueing")); ci_ni_dllist_push_tail(netif, &tls->epcache.cache, &ts->epcache_link); ts = NULL; CITP_STATS_NETIF(++netif->state->stats.sockcache_miss_intmismatch); } } #endif return ts; }
void ci_tcp_listenq_insert(ci_netif* ni, ci_tcp_socket_listen* tls, ci_tcp_state_synrecv* tsr) { int is_first; tls->n_listenq++; ci_tcp_listenq_bucket_insert(ni, tls, ci_ni_aux_p2bucket(ni, tls->bucket), tsr, 0); if( OO_SP_NOT_NULL(tsr->local_peer) ) return; is_first = ci_ni_dllist_is_empty(ni, &tls->listenq[0]); ci_ni_dllist_push_tail(ni, &tls->listenq[0], ci_tcp_synrecv2link(tsr)); tsr->retries = 0; tsr->timeout = ci_tcp_time_now(ni) + NI_CONF(ni).tconst_rto_initial; ++tls->n_listenq_new; if( is_first ) ci_tcp_listen_timer_set(ni, tls, tsr->timeout); }
/* take the bucket corresponding to time t in the given wheel and ** reinsert them back into the wheel (i.e. into wheelno -1) */ static int ci_ip_timer_cascadewheel(ci_netif* netif, int wheelno, ci_iptime_t stime) { ci_ip_timer* ts; ci_ni_dllist_t* bucket; oo_p curid, buckid; int changed = 0; ci_assert(wheelno > 0 && wheelno < CI_IPTIME_WHEELS); /* check time is on the boundary expected by the wheel number passed in */ ci_assert( (stime & ((unsigned)(-1) << (CI_IPTIME_BUCKETBITS*wheelno))) == stime ); /* bucket to empty */ bucket = BUCKET(netif, wheelno, stime); buckid = ci_ni_dllist_link_addr(netif, &bucket->l); curid = bucket->l.next; LOG_ITV(log(LN_FMT "cascading wheel=%u sched_ticks=0x%x bucket=%i", LN_PRI_ARGS(netif), wheelno, stime, BUCKETNO(wheelno, stime))); /* ditch the timers in this dll, pointers held in curid and buckid */ ci_ni_dllist_init(netif, bucket, ci_ni_dllist_link_addr(netif, &bucket->l), "timw"); while( ! OO_P_EQ(curid, buckid) ) { ts = ADDR2TIMER(netif, curid); /* get next in linked list */ curid = ts->link.next; #ifndef NDEBUG { /* if inserting in wheel 0 - top 3 wheels must have the same time */ if (wheelno == 1) ci_assert( (stime & WHEEL0_MASK) == (ts->time & WHEEL0_MASK) ); /* else, if inserting in wheel 1 - top 2 wheels must have the same time */ else if (wheelno == 2) ci_assert( (stime & WHEEL1_MASK) == (ts->time & WHEEL1_MASK) ); /* else, if inserting in wheel 2 - the top wheel must have the same time */ else { ci_assert(wheelno == 3); ci_assert( (stime & WHEEL2_MASK) == (ts->time & WHEEL2_MASK) ); } } #endif /* insert ts into wheel below */ bucket = BUCKET(netif, wheelno-1, ts->time); changed = 1; /* 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)); } return changed; }