From: ppisa Date: Tue, 18 Nov 2003 13:47:17 +0000 (+0000) Subject: Edge and ends structures equipped with single purpose outlist. X-Git-Tag: CLT_COMM_CAN_pre_canmsg_change~16 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/94b8e4f0425cebad0a186daf054168fa6910f9b8 Edge and ends structures equipped with single purpose outlist. This additional list enlarges structures about 8 bytes, but it is big help for asynchronous dispose of the ends. This breaks last spinlock_irqsave holding loops and simplifies edge handling logic. --- diff --git a/lincan/include/can_queue.h b/lincan/include/can_queue.h index 5951186..264fce5 100644 --- a/lincan/include/can_queue.h +++ b/lincan/include/can_queue.h @@ -269,10 +269,13 @@ struct chip_t; * @filtid: the possible CAN message identifiers filter. * @filtmask: the filter mask, the comparison considers only * @filtid bits corresponding to set bits in the @filtmask field. - * @inpeers: the lists of all peer FIFOs connected by their + * @inpeers: the lists of all peers FIFOs connected by their * input side (@inends) to the same terminal (@struct canque_ends_t). - * @outpeers: the lists of all peer FIFOs connected by their + * @outpeers: the lists of all peers FIFOs connected by their * output side (@outends) to the same terminal (@struct canque_ends_t). + * @activepeers: the lists of peers FIFOs connected by their + * output side (@outends) to the same terminal (@struct canque_ends_t) + * with same priority and active state. * @inends: the pointer to the FIFO input side terminal (@struct canque_ends_t). * @outends: the pointer to the FIFO output side terminal (@struct canque_ends_t). * @edge_used: the atomic usage counter, mainly used for safe destruction of the edge. @@ -289,6 +292,7 @@ struct canque_edge_t { unsigned long filtmask; struct list_head inpeers; struct list_head outpeers; + struct list_head activepeers; struct canque_ends_t *inends; struct canque_ends_t *outends; atomic_t edge_used; @@ -328,6 +332,7 @@ struct canque_ends_t { struct list_head active[CANQUEUE_PRIO_NR]; struct list_head idle; struct list_head inlist; + struct list_head outlist; spinlock_t ends_lock; /* spin_lock_irqsave / spin_lock_irqrestore */ void (*notify)(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what); void *context; @@ -419,8 +424,8 @@ void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qe spin_lock(&outends->ends_lock); spin_lock(&qedge->fifo.fifo_lock); if(!canque_fifo_test_fl(&qedge->fifo,EMPTY)){ - list_del(&qedge->outpeers); - list_add_tail(&qedge->outpeers,&outends->active[qedge->edge_prio]); + list_del(&qedge->activepeers); + list_add_tail(&qedge->activepeers,&outends->active[qedge->edge_prio]); } spin_unlock(&qedge->fifo.fifo_lock); spin_unlock(&outends->ends_lock); @@ -479,6 +484,9 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine int canqueue_ends_init_gen(struct canque_ends_t *qends); +void canqueue_block_inlist(struct canque_ends_t *qends); + +void canqueue_block_outlist(struct canque_ends_t *qends); /* edge reference and traversal functions */ @@ -566,6 +574,59 @@ struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct can #define canque_for_each_inedge(qends, edge) \ for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge)) +static inline +struct canque_edge_t *canque_first_outedge(struct canque_ends_t *qends) +{ + unsigned long flags; + struct list_head *entry; + struct canque_edge_t *edge; + + spin_lock_irqsave(&qends->ends_lock, flags); + entry=qends->outlist.next; + skip_dead: + if(entry != &qends->outlist) { + edge=list_entry(entry,struct canque_edge_t,outpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(edge); + } else { + edge=NULL; + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + return edge; +} + + +static inline +struct canque_edge_t *canque_next_outedge(struct canque_ends_t *qends, struct canque_edge_t *edge) +{ + unsigned long flags; + struct list_head *entry; + struct canque_edge_t *next; + + spin_lock_irqsave(&qends->ends_lock, flags); + entry=edge->outpeers.next; + skip_dead: + if(entry != &qends->outlist) { + next=list_entry(entry,struct canque_edge_t,outpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(next); + } else { + next=NULL; + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(edge); + return next; +} + +#define canque_for_each_outedge(qends, edge) \ + for(edge=canque_first_outedge(qends);edge;edge=canque_next_outedge(qends, edge)) + /* Linux kernel specific functions */ struct canque_edge_t *canque_new_edge_kern(int slotsnr); diff --git a/lincan/src/can_quekern.c b/lincan/src/can_quekern.c index 4ffdaa0..55e8063 100644 --- a/lincan/src/can_quekern.c +++ b/lincan/src/can_quekern.c @@ -68,7 +68,6 @@ void canque_dead_func(unsigned long data) struct canque_edge_t *qedge; struct canque_ends_t *qends; struct list_head *entry; - int i; while((qedge=canque_dead_edges_cut_first())){ DEBUGQUE("edge %d disposed\n",qedge->edge_num); @@ -83,11 +82,8 @@ void canque_dead_func(unsigned long data) entry=entry->next; if(!list_empty(&qends->inlist)) continue; - if(!list_empty(&qends->idle)) + if(!list_empty(&qends->outlist)) continue; - for(i=CANQUEUE_PRIO_NR;i--;) - if(!list_empty(&qends->active[i])) - continue; spin_lock_irqsave(&canque_dead_func_lock, flags); list_del(&qends->dead_peers); spin_unlock_irqrestore(&canque_dead_func_lock,flags); @@ -278,6 +274,8 @@ struct canque_edge_t *canque_new_edge_kern(int slotsnr) return qedge; } +#ifdef USE_DELAYED_DISCONNECT_EDGE_KERN + /** * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait * @qends: ends structure belonging to calling communication object @@ -342,20 +340,8 @@ int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head } } -void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list) -{ - struct canque_edge_t *edge; - struct list_head *entry; - - /* has to be called with qends->ends_lock already locked */ - list_for_each(entry,&qends->inlist){ - if(list == &qends->inlist) - edge=list_entry(list->next,struct canque_edge_t,inpeers); - else - edge=list_entry(list->next,struct canque_edge_t,outpeers); - canque_fifo_set_fl(&edge->fifo,BLOCK); - } -} +#endif /*USE_DELAYED_DISCONNECT_EDGE_KERN*/ + int canqueue_ends_sync_all_kern(struct canque_ends_t *qends) { @@ -389,6 +375,17 @@ int canqueue_ends_done_inends(struct canque_ends_t *qends, int send_rest) } +int canqueue_ends_done_outends(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_outedge(qends, edge){ + canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED); + } + return list_empty(&qends->outlist)?0:1; +} + + /** * canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients * @qends: pointer to ends structure @@ -400,18 +397,11 @@ int canqueue_ends_done_inends(struct canque_ends_t *qends, int send_rest) int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync) { unsigned long flags; - int i; int delayed; DEBUGQUE("canqueue_ends_dispose_kern\n"); - spin_lock_irqsave(&qends->ends_lock,flags); - canqueue_block_list(qends, &qends->idle); - for(i=CANQUEUE_PRIO_NR;--i>=0;){ - canqueue_block_list(qends, &qends->active[i]); - } - canqueue_block_list(qends, &qends->idle); - canqueue_block_list(qends, &qends->inlist); - spin_unlock_irqrestore(&qends->ends_lock,flags); + canqueue_block_inlist(qends); + canqueue_block_outlist(qends); /*Wait for sending of all pending messages in the output FIFOs*/ if(sync) @@ -420,10 +410,7 @@ int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync) /* Finish all outgoing edges listed in inends */ delayed=canqueue_ends_done_inends(qends, 1); - delayed|=canqueue_disconnect_list_kern(qends, &qends->idle); - for(i=CANQUEUE_PRIO_NR;--i>=0;){ - delayed|=canqueue_disconnect_list_kern(qends, &qends->active[i]); - } + delayed|=canqueue_ends_done_outends(qends); wake_up(&qends->endinfo.fileinfo.readq); wake_up(&qends->endinfo.fileinfo.writeq); diff --git a/lincan/src/can_queue.c b/lincan/src/can_queue.c index 6ee0550..ef06005 100644 --- a/lincan/src/can_queue.c +++ b/lincan/src/can_queue.c @@ -326,7 +326,7 @@ int canque_test_outslot(struct canque_ends_t *qends, spin_lock_irqsave(&qends->ends_lock, flags); for(prio=CANQUEUE_PRIO_NR;--prio>=0;){ while(!list_empty(&qends->active[prio])){ - edge=list_entry(qends->active[prio].next,struct canque_edge_t,outpeers); + edge=list_entry(qends->active[prio].next,struct canque_edge_t,activepeers); if(!canque_fifo_test_fl(&edge->fifo,DEAD)) { canque_edge_incref(edge); spin_unlock_irqrestore(&qends->ends_lock, flags); @@ -339,8 +339,8 @@ int canque_test_outslot(struct canque_ends_t *qends, } spin_lock(&edge->fifo.fifo_lock); if(canque_fifo_test_and_set_fl(&edge->fifo,INACTIVE)) { - list_del(&edge->outpeers); - list_add(&edge->outpeers,&qends->idle); + list_del(&edge->activepeers); + list_add(&edge->activepeers,&qends->idle); } spin_unlock(&edge->fifo.fifo_lock); } @@ -378,11 +378,11 @@ int canque_free_outslot(struct canque_ends_t *qends, spin_lock(&qedge->fifo.fifo_lock); if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ canque_fifo_set_fl(&qedge->fifo,INACTIVE); - list_del(&qedge->outpeers); - list_add(&qedge->outpeers,&qends->idle); + list_del(&qedge->activepeers); + list_add(&qedge->activepeers,&qends->idle); } else{ - list_del(&qedge->outpeers); - list_add_tail(&qedge->outpeers,&qends->active[qedge->edge_prio]); + list_del(&qedge->activepeers); + list_add_tail(&qedge->activepeers,&qends->active[qedge->edge_prio]); } spin_unlock(&qedge->fifo.fifo_lock); } @@ -473,8 +473,8 @@ int canque_flush(struct canque_edge_t *qedge) spin_lock_irqsave(&qedge->outends->ends_lock, flags); spin_lock(&qedge->fifo.fifo_lock); if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ - list_del(&qedge->outpeers); - list_add(&qedge->outpeers,&qedge->outends->idle); + list_del(&qedge->activepeers); + list_add(&qedge->activepeers,&qedge->outends->idle); } spin_unlock(&qedge->fifo.fifo_lock); spin_unlock_irqrestore(&qedge->outends->ends_lock, flags); @@ -497,6 +497,7 @@ int canqueue_ends_init_gen(struct canque_ends_t *qends) } INIT_LIST_HEAD(&qends->idle); INIT_LIST_HEAD(&qends->inlist); + INIT_LIST_HEAD(&qends->outlist); spin_lock_init(&qends->ends_lock); return 0; } @@ -522,7 +523,8 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine qedge->inends=inends; list_add(&qedge->inpeers,&inends->inlist); qedge->outends=outends; - list_add(&qedge->outpeers,&outends->idle); + list_add(&qedge->outpeers,&outends->outlist); + list_add(&qedge->activepeers,&outends->idle); spin_unlock(&qedge->fifo.fifo_lock); spin_unlock(&outends->ends_lock); spin_unlock_irqrestore(&inends->ends_lock, flags); @@ -553,6 +555,8 @@ int canqueue_disconnect_edge(struct canque_edge_t *qedge) spin_lock(&qedge->fifo.fifo_lock); if(atomic_read(&qedge->edge_used)==0) { if(qedge->outends){ + list_del(&qedge->activepeers); + mb(); /* memory barrier for list_empty use in canque_dead_func */ list_del(&qedge->outpeers); qedge->outends=NULL; } @@ -569,3 +573,32 @@ int canqueue_disconnect_edge(struct canque_edge_t *qedge) return ret; } + +/** + * canqueue_block_inlist - block slot allocation of all outgoing edges of specified ends + * @qends: pointer to ends structure + */ +void canqueue_block_inlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_inedge(qends, edge) { + canque_fifo_set_fl(&edge->fifo,BLOCK); + } +} + + +/** + * canqueue_block_outlist - block slot allocation of all incoming edges of specified ends + * @qends: pointer to ends structure + */ +void canqueue_block_outlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_outedge(qends, edge) { + canque_fifo_set_fl(&edge->fifo,BLOCK); + } +} + +