void print_timer_list(struct list_link *head) { struct list_link *ll; DBG("DEBUG:pike:print_timer_list --->\n"); for ( ll=head->next ; ll!=head; ll=ll->next) { DBG("\t %p [byte=%x](expires=%d)\n", ll, ll2ipnode(ll)->byte, ll2ipnode(ll)->expires); } }
/* "head" list MUST not be empty */ void check_and_split_timer(struct list_link *head, int time, struct list_link *split, unsigned char *mask) { struct list_link *ll; unsigned char b; int i; /* reset the mask */ for(i=0;i<32;mask[i++]=0); ll = head->next; while( ll!=head && ll2ipnode(ll)->expires<=time) { DBG("DEBUG:pike:check_and_split_timer: splitting %p(%p,%p)node=%p\n", ll,ll->prev,ll->next,ll2ipnode(ll)); b = ll2ipnode(ll)->branch; ll=ll->next; /*DBG("DEBUG:pike:check_and_split_timer: b=%d; [%d,%d]\n", b,b>>3,1<<(b&0x07));*/ mask[b>>3] |= (1<<(b&0x07)); } if (ll==head->next) { /* nothing to return */ split->next = split->prev = split; } else { /* the detached list begins with current beginning */ split->next = head->next; split->next->prev = split; /* and we mark the end of the split list */ split->prev = ll->prev; split->prev->next = split; /* the shortened list starts from where we suspended */ head->next = ll; ll->prev = head; } DBG("DEBUG:pike:check_and_split_timer: succ. to split (h=%p)(p=%p,n=%p)\n", head,head->prev,head->next); return; }
/* "head" list MUST not be empty */ void check_and_split_timer(struct list_link *head, unsigned int time, struct list_link *split, unsigned char *mask) { struct list_link *ll; struct ip_node *node; unsigned char b; int i; /* reset the mask */ for(i=0;i<32;mask[i++]=0); ll = head->next; while( ll!=head && (node=ll2ipnode(ll))->expires<=time) { LM_DBG("splitting %p(%p,%p)node=%p\n", ll,ll->prev,ll->next, node); /* mark the node as expired and un-mark it as being in timer list */ node->flags |= NODE_EXPIRED_FLAG; node->flags &= ~NODE_INTIMER_FLAG; b = node->branch; ll=ll->next; /*LM_DBG("b=%d; [%d,%d]\n", b,b>>3,1<<(b&0x07));*/ mask[b>>3] |= (1<<(b&0x07)); } if (ll==head->next) { /* nothing to return */ split->next = split->prev = split; } else { /* the detached list begins with current beginning */ split->next = head->next; split->next->prev = split; /* and we mark the end of the split list */ split->prev = ll->prev; split->prev->next = split; /* the shortened list starts from where we suspended */ head->next = ll; ll->prev = head; } LM_DBG("succ. to split (h=%p)(p=%p,n=%p)\n", head,head->prev,head->next); return; }
void clean_routine(unsigned int ticks , void *param) { static unsigned char mask[32]; /* 256 positions mask */ struct list_link head; struct list_link *ll; struct ip_node *dad; struct ip_node *node; int i; /* LM_DBG("entering (%d)\n",ticks); */ /* before locking check first if the list is not empty and if can * be at least one element removed */ if ( is_list_empty( timer )) return; /* quick exit */ /* get the expired elements */ lock_get( timer_lock ); /* check again for empty list */ if (is_list_empty(timer) || (ll2ipnode(timer->next)->expires>ticks )){ lock_release( timer_lock ); return; } check_and_split_timer( timer, ticks, &head, mask); /*print_timer_list(timer);*/ /* debug */ lock_release( timer_lock ); /*print_tree( 0 );*/ /*debug*/ /* got something back? */ if ( is_list_empty(&head) ) return; /* process what we got -> don't forget to lock the tree!! */ for(i=0;i<MAX_IP_BRANCHES;i++) { /* if no element from this branch -> skip it */ if ( ((mask[i>>3])&(1<<(i&0x07)))==0 ) continue; lock_tree_branch( i ); for( ll=head.next ; ll!=&head ; ) { node = ll2ipnode( ll ); ll = ll->next; /* skip nodes from a different branch */ if (node->branch!=i) continue; /* unlink the node -> the list will get shorter and it will be * faster for the next branches to process it */ ll->prev->prev->next = ll; ll->prev = ll->prev->prev; node->expires = 0; node->timer_ll.prev = node->timer_ll.next = 0; if ( node->flags&NODE_EXPIRED_FLAG ) node->flags &= ~NODE_EXPIRED_FLAG; else continue; /* process the node */ LM_DBG("clean node %p (kids=%p; hits=[%d,%d];leaf=[%d,%d])\n", node,node->kids, node->hits[PREV_POS],node->hits[CURR_POS], node->leaf_hits[PREV_POS],node->leaf_hits[CURR_POS]); /* if it's a node, leaf for an ipv4 address inside an * ipv6 address -> just remove it from timer it will be deleted * only when all its kids will be deleted also */ if (node->kids) { assert( node->flags&NODE_IPLEAF_FLAG ); node->flags &= ~NODE_IPLEAF_FLAG; node->leaf_hits[CURR_POS] = 0; } else { /* if the node has no prev, means its a top branch node -> just * removed and destroy it */ if (node->prev!=0) { /* if this is the last kid, we have to put the father * into timer list */ if (node->prev->kids==node && node->next==0) { /* this is the last kid node */ dad = node->prev; /* put it in the list only if it's not an IP leaf * (in this case, it's already there) */ if ( !(dad->flags&NODE_IPLEAF_FLAG) ) { lock_get(timer_lock); dad->expires = get_ticks() + timeout; assert( !has_timer_set(&(dad->timer_ll)) ); append_to_timer( timer, &(dad->timer_ll)); dad->flags |= NODE_INTIMER_FLAG; lock_release(timer_lock); } else { assert( has_timer_set(&(dad->timer_ll)) ); } } } LM_DBG("rmv node %p[%d] \n", node,node->byte); /* del the node */ remove_node( node); } } /* for all expired elements */ unlock_tree_branch( i ); } /* for all branches */ }