]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/can_queue.c
c4130aa489733194a3849bed79251948e0871584
[lincan.git] / lincan / src / can_queue.c
1 /* can_queue.c - CAN message queues
2  * Linux CAN-bus device driver.
3  * New CAN queues by Pavel Pisa - OCERA team member
4  * email:pisa@cmp.felk.cvut.cz
5  * This software is released under the GPL-License.
6  * Version lincan-0.2  9 Jul 2003
7  */
8
9 #include "../include/can.h"
10 #include "../include/can_sysdep.h"
11 #include "../include/can_queue.h"
12
13 /* 
14  * Modifies Tx message processing 
15  *  0 .. local message processing disabled
16  *  1 .. local messages disabled by default but can be enabled by canque_set_filt
17  *  2 .. local messages enabled by default, can be disabled by canque_set_filt
18  */
19 extern int processlocal;
20
21 atomic_t edge_num_cnt;
22
23 //#define CAN_DEBUG
24 #undef CAN_DEBUG
25
26 #ifdef CAN_DEBUG
27         #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
28         ##args)
29
30 #else
31         #define DEBUGQUE(fmt,args...)
32 #endif
33
34 #define CANQUE_ROUNDROB 1
35
36
37 /**
38  * canque_fifo_flush_slots - free all ready slots from the FIFO
39  * @fifo: pointer to the FIFO structure
40  *
41  * The caller should be prepared to handle situations, when some
42  * slots are held by input or output side slots processing.
43  * These slots cannot be flushed or their processing interrupted.
44  *
45  * Return Value: The nonzero value indicates, that queue has not been
46  *      empty before the function call.
47  */
48 int canque_fifo_flush_slots(struct canque_fifo_t *fifo)
49 {
50         int ret;
51         can_spin_irqflags_t flags;
52         struct canque_slot_t *slot;
53         can_spin_lock_irqsave(&fifo->fifo_lock, flags);
54         slot=fifo->head;
55         if(slot){
56                 *fifo->tail=fifo->flist;
57                 fifo->flist=slot;
58                 fifo->head=NULL;
59                 fifo->tail=&fifo->head;
60         }
61         canque_fifo_clear_fl(fifo,FULL);
62         ret=canque_fifo_test_and_set_fl(fifo,EMPTY)?0:1;
63         can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
64         return ret;
65 }
66
67
68 /**
69  * canque_fifo_init_slots - initializes slot chain of one CAN FIFO
70  * @fifo: pointer to the FIFO structure
71  *
72  * Return Value: The negative value indicates, that there is no memory
73  *      to allocate space for the requested number of the slots.
74  */
75 int canque_fifo_init_slots(struct canque_fifo_t *fifo)
76 {
77         struct canque_slot_t *slot;
78         int slotsnr=fifo->slotsnr;
79         if(!fifo->entry || !slotsnr) return -1;
80         slot=fifo->entry;
81         fifo->flist=slot;
82         while(--slotsnr){
83                 slot->next=slot+1;
84                 slot++;
85         }
86         slot->next=NULL;
87         fifo->head=NULL;
88         fifo->tail=&fifo->head;
89         canque_fifo_set_fl(fifo,EMPTY);
90         return 1;
91 }
92
93 /* atomic_dec_and_test(&qedge->edge_used);
94  void atomic_inc(&qedge->edge_used);
95  list_add_tail(struct list_head *new, struct list_head *head)
96  list_for_each(edge,qends->inlist);
97  list_entry(ptr, type, member)
98 */
99
100 /**
101  * canque_get_inslot - finds one outgoing edge and allocates slot from it
102  * @qends: ends structure belonging to calling communication object
103  * @qedgep: place to store pointer to found edge
104  * @slotp: place to store pointer to  allocated slot
105  * @cmd: command type for slot
106  *
107  * Function looks for the first non-blocked outgoing edge in @qends structure
108  * and tries to allocate slot from it.
109  * Return Value: If there is no usable edge or there is no free slot in edge
110  *      negative value is returned.
111  */
112 int canque_get_inslot(struct canque_ends_t *qends,
113         struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd)
114 {
115         int ret=-2;
116         struct canque_edge_t *edge;
117         
118         edge=canque_first_inedge(qends);
119         if(edge){
120                 if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){
121                         ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
122                         if(ret>0){
123                                 *qedgep=edge;
124                                 DEBUGQUE("canque_get_inslot cmd=%d found edge %d\n",cmd,edge->edge_num);
125                                 return ret;
126
127                         }
128                 }
129                 canque_edge_decref(edge);
130         }
131         *qedgep=NULL;
132         DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd);
133         return ret;
134 }
135
136 /**
137  * canque_get_inslot4id - finds best outgoing edge and slot for given ID
138  * @qends: ends structure belonging to calling communication object
139  * @qedgep: place to store pointer to found edge
140  * @slotp: place to store pointer to  allocated slot
141  * @cmd: command type for slot
142  * @id: communication ID of message to send into edge
143  * @prio: optional priority of message
144  *
145  * Function looks for the non-blocked outgoing edge accepting messages
146  * with given ID. If edge is found, slot is allocated from that edge.
147  * The edges with non-zero mask are preferred over edges open to all messages.
148  * If more edges with mask accepts given message ID, the edge with
149  * highest priority below or equal to required priority is selected.
150  * Return Value: If there is no usable edge or there is no free slot in edge
151  *      negative value is returned.
152  */
153 int canque_get_inslot4id(struct canque_ends_t *qends,
154         struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
155         int cmd, unsigned long id, int prio)
156 {
157         int ret=-2;
158         struct canque_edge_t *edge, *bestedge=NULL;
159         
160         canque_for_each_inedge(qends, edge){
161                 if(canque_fifo_test_fl(&edge->fifo,BLOCK))
162                         continue;
163                 if((id^edge->filtid)&edge->filtmask)
164                         continue;
165                 if(bestedge){
166                         if(bestedge->filtmask){
167                                 if (!edge->filtmask) continue;
168                         } else {
169                                 if(edge->filtmask){
170                                         canque_edge_decref(bestedge);
171                                         bestedge=edge;
172                                         canque_edge_incref(bestedge);
173                                         continue;
174                                 }
175                         }
176                         if(bestedge->edge_prio<edge->edge_prio){
177                                 if(edge->edge_prio>prio) continue;
178                         } else {
179                                 if(bestedge->edge_prio<=prio) continue;
180                         }
181                         canque_edge_decref(bestedge);
182                 }
183                 bestedge=edge;
184                 canque_edge_incref(bestedge);
185         }
186         if((edge=bestedge)!=NULL){
187                 ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
188                 if(ret>0){
189                         *qedgep=edge;
190                         DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num);
191                         return ret;
192                 }
193                 canque_edge_decref(bestedge);
194         }
195         *qedgep=NULL;
196         DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio);
197         return ret;
198 }
199
200
201 /**
202  * canque_put_inslot - schedules filled slot for processing
203  * @qends: ends structure belonging to calling communication object
204  * @qedge: edge slot belong to
205  * @slot: pointer to the prepared slot
206  *
207  * Puts slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
208  * function call into FIFO queue and activates edge processing if needed.
209  * Return Value: Positive value informs, that activation of output end
210  *      has been necessary
211  */
212 int canque_put_inslot(struct canque_ends_t *qends,
213         struct canque_edge_t *qedge, struct canque_slot_t *slot)
214 {
215         int ret;
216         ret=canque_fifo_put_inslot(&qedge->fifo,slot);
217         if(ret) {
218                 canque_activate_edge(qends,qedge);
219                 canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC);
220         }
221         canque_edge_decref(qedge);
222         DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret);
223         return ret;
224 }
225
226 /**
227  * canque_abort_inslot - aborts preparation of the message in the slot
228  * @qends: ends structure belonging to calling communication object
229  * @qedge: edge slot belong to
230  * @slot: pointer to the previously allocated slot
231  *
232  * Frees slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
233  * function call. Used when message copying into slot fails.
234  * Return Value: Positive value informs, that queue full state has been negated.
235  */
236 int canque_abort_inslot(struct canque_ends_t *qends,
237         struct canque_edge_t *qedge, struct canque_slot_t *slot)
238 {
239         int ret;
240         ret=canque_fifo_abort_inslot(&qedge->fifo,slot);
241         if(ret) {
242                 canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE);
243         }
244         canque_edge_decref(qedge);
245         DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret);
246         return ret;
247 }
248
249 /**
250  * canque_filter_msg2edges - sends message into all edges which accept its ID
251  * @qends: ends structure belonging to calling communication object
252  * @msg: pointer to CAN message
253  *
254  * Sends message to all outgoing edges connected to the given ends, which accepts
255  * message communication ID.
256  * Return Value: Returns number of edges message has been send to
257  */
258 int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
259 {
260         int destnr=0;
261         int ret;
262         unsigned long msgid;
263         struct canque_edge_t *edge;
264         struct canque_slot_t *slot;
265         
266         DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
267                         msg->id, msg->flags);
268         msgid = canque_filtid2internal(msg->id, msg->flags);
269
270         canque_for_each_inedge(qends, edge) {
271                 if(canque_fifo_test_fl(&edge->fifo,BLOCK))
272                         continue;
273                 if((msgid^edge->filtid)&edge->filtmask)
274                         continue;
275                 ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0);
276                 if(ret>0){
277                         slot->msg=*msg;
278                         destnr++;
279                         ret=canque_fifo_put_inslot(&edge->fifo,slot);
280                         if(ret) {
281                                 canque_activate_edge(qends,edge);
282                                 canque_notify_outends(edge,CANQUEUE_NOTIFY_PROC);
283                         }
284
285                 }
286         }
287         DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr);
288         return destnr;
289 }
290
291 /**
292  * canque_test_outslot - test and retrieve ready slot for given ends
293  * @qends: ends structure belonging to calling communication object
294  * @qedgep: place to store pointer to found edge
295  * @slotp: place to store pointer to received slot
296  *
297  * Function takes highest priority active incoming edge and retrieves
298  * oldest ready slot from it.
299  * Return Value: Negative value informs, that there is no ready output
300  *      slot for given ends. Positive value is equal to the command
301  *      slot has been allocated by the input side.
302  */
303 int canque_test_outslot(struct canque_ends_t *qends,
304         struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
305 {
306         can_spin_irqflags_t flags;
307         int prio;
308         struct canque_edge_t *edge;
309         int ret;
310         
311         can_spin_lock_irqsave(&qends->ends_lock, flags);
312         for(prio=CANQUEUE_PRIO_NR;--prio>=0;){
313                 while(!list_empty(&qends->active[prio])){
314                         edge=list_entry(qends->active[prio].next,struct canque_edge_t,activepeers);
315                         if(!canque_fifo_test_fl(&edge->fifo,DEAD)) {
316                                 /* The first test on unlocked FIFO */
317                                 if(canque_fifo_test_fl(&edge->fifo,EMPTY)) {
318                                         can_spin_lock(&edge->fifo.fifo_lock);
319                                         /* Test has to be repeated to ensure that EMPTY
320                                            state has not been nagated when locking FIFO */
321                                         if(canque_fifo_test_fl(&edge->fifo,EMPTY)) {
322                                                 canque_fifo_set_fl(&edge->fifo,INACTIVE);
323                                                 list_del(&edge->activepeers);
324                                                 list_add(&edge->activepeers,&qends->idle);
325                                                 can_spin_unlock(&edge->fifo.fifo_lock);
326                                                 continue;
327                                         }
328                                         can_spin_unlock(&edge->fifo.fifo_lock);
329                                 }
330                                 canque_edge_incref(edge);
331                                 can_spin_unlock_irqrestore(&qends->ends_lock, flags);
332                                 *qedgep=edge;
333                                 DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
334                                 ret=canque_fifo_test_outslot(&edge->fifo, slotp);
335                                 if(ret>=0)
336                                         return ret;
337
338                                 canque_edge_decref(edge);
339                                 can_spin_lock_irqsave(&qends->ends_lock, flags);
340                         } else {
341                                 can_spin_lock(&edge->fifo.fifo_lock);
342                                 canque_fifo_set_fl(&edge->fifo,INACTIVE);
343                                 list_del(&edge->activepeers);
344                                 list_add(&edge->activepeers,&qends->idle);
345                                 can_spin_unlock(&edge->fifo.fifo_lock);
346                         }
347                 }
348         }
349         can_spin_unlock_irqrestore(&qends->ends_lock, flags);
350         *qedgep=NULL;
351         DEBUGQUE("canque_test_outslot no ready slot\n");
352         return -1;
353 }
354
355 /**
356  * canque_free_outslot - frees processed output slot
357  * @qends: ends structure belonging to calling communication object
358  * @qedge: edge slot belong to
359  * @slot: pointer to the processed slot
360  *
361  * Function releases processed slot previously acquired by canque_test_outslot()
362  * function call.
363  * Return Value: Return value informs if input side has been notified
364  *      to know about change of edge state
365  */
366 int canque_free_outslot(struct canque_ends_t *qends,
367         struct canque_edge_t *qedge, struct canque_slot_t *slot)
368 {
369         int ret;
370         can_spin_irqflags_t flags;
371         ret=canque_fifo_free_outslot(&qedge->fifo, slot);
372         if(ret&CAN_FIFOF_EMPTY){
373                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
374         }
375         if(ret&CAN_FIFOF_FULL)
376                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
377         can_spin_lock_irqsave(&qends->ends_lock, flags);
378         if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){
379                 can_spin_lock(&qedge->fifo.fifo_lock);
380                 if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
381                         canque_fifo_set_fl(&qedge->fifo,INACTIVE);
382                         list_del(&qedge->activepeers);
383                         list_add(&qedge->activepeers,&qends->idle);
384                 } else{
385                         list_del(&qedge->activepeers);
386                         list_add_tail(&qedge->activepeers,&qends->active[qedge->edge_prio]);
387                 }
388                 can_spin_unlock(&qedge->fifo.fifo_lock);
389         }
390         can_spin_unlock_irqrestore(&qends->ends_lock, flags);
391         canque_edge_decref(qedge);
392         DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret);
393         return ret;
394 }
395
396 /**
397  * canque_again_outslot - reschedule output slot to process it again later
398  * @qends: ends structure belonging to calling communication object
399  * @qedge: edge slot belong to
400  * @slot: pointer to the slot for re-processing
401  *
402  * Function reschedules slot previously acquired by canque_test_outslot()
403  * function call for second time processing.
404  * Return Value: Function cannot fail.
405  */
406 int canque_again_outslot(struct canque_ends_t *qends,
407         struct canque_edge_t *qedge, struct canque_slot_t *slot)
408 {
409         int ret;
410         ret=canque_fifo_again_outslot(&qedge->fifo, slot);
411         canque_edge_decref(qedge);
412         DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret);
413         return ret;
414 }
415
416 /**
417  * canque_set_filt - sets filter for specified edge
418  * @qedge: pointer to the edge
419  * @filtid: ID to set for the edge
420  * @filtmask: mask used for ID match check
421  * @filtflags: required filer flags
422  *
423  * Return Value: Negative value is returned if edge is in the process of delete.
424  */
425 int canque_set_filt(struct canque_edge_t *qedge,
426         unsigned long filtid, unsigned long filtmask, int filtflags)
427 {
428         int ret;
429         can_spin_irqflags_t flags;
430
431         can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
432         
433         if(!(filtflags&MSG_PROCESSLOCAL) && (processlocal<2))
434                 filtflags |= MSG_LOCAL_MASK;
435         
436         qedge->filtid=canque_filtid2internal(filtid, filtflags);
437         qedge->filtmask=canque_filtid2internal(filtmask, filtflags>>MSG_FILT_MASK_SHIFT);
438         
439         if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1;
440         else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0;
441
442         can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
443         if(ret>=0){
444                 canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH);
445         }
446         can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
447         if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK);
448         can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
449         
450         DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
451                   qedge->edge_num,filtid,filtmask,filtflags,ret);
452         return ret;
453 }
454
455 /**
456  * canque_flush - fluesh all ready slots in the edge
457  * @qedge: pointer to the edge
458  *
459  * Tries to flush all allocated slots from the edge, but there could
460  * exist some slots associated to edge which are processed by input
461  * or output side and cannot be flushed at this moment.
462  * Return Value: The nonzero value indicates, that queue has not been
463  *      empty before the function call.
464  */
465 int canque_flush(struct canque_edge_t *qedge)
466 {
467         int ret;
468         can_spin_irqflags_t flags;
469
470         ret=canque_fifo_flush_slots(&qedge->fifo);
471         if(ret){
472                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
473                 canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
474                 can_spin_lock_irqsave(&qedge->outends->ends_lock, flags);
475                 can_spin_lock(&qedge->fifo.fifo_lock);
476                 if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
477                         list_del(&qedge->activepeers);
478                         list_add(&qedge->activepeers,&qedge->outends->idle);
479                 }
480                 can_spin_unlock(&qedge->fifo.fifo_lock);
481                 can_spin_unlock_irqrestore(&qedge->outends->ends_lock, flags);
482         }
483         DEBUGQUE("canque_flush for edge %d returned %d\n",qedge->edge_num,ret);
484         return ret;
485 }
486
487 /**
488  * canqueue_ends_init_gen - subsystem independent routine to initialize ends state
489  * @qends: pointer to the ends structure
490  *
491  * Return Value: Cannot fail.
492  */
493 int canqueue_ends_init_gen(struct canque_ends_t *qends)
494 {
495         int i;
496         qends->ends_flags=0;
497         for(i=CANQUEUE_PRIO_NR;--i>=0;){
498                 INIT_LIST_HEAD(&qends->active[i]);
499         }
500         INIT_LIST_HEAD(&qends->idle);
501         INIT_LIST_HEAD(&qends->inlist);
502         INIT_LIST_HEAD(&qends->outlist);
503         can_spin_lock_init(&qends->ends_lock);
504         return 0;
505 }
506
507
508 /**
509  * canqueue_connect_edge - connect edge between two communication entities
510  * @qedge: pointer to edge
511  * @inends: pointer to ends the input of the edge should be connected to
512  * @outends: pointer to ends the output of the edge should be connected to
513  *
514  * Return Value: Negative value informs about failed operation.
515  */
516 int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends)
517 {
518         can_spin_irqflags_t flags;
519         if(qedge == NULL) return -1;
520         DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num);
521         canque_edge_incref(qedge);
522         can_spin_lock_irqsave(&inends->ends_lock, flags);
523         can_spin_lock(&outends->ends_lock);
524         can_spin_lock(&qedge->fifo.fifo_lock);
525         qedge->inends=inends;
526         list_add(&qedge->inpeers,&inends->inlist);
527         qedge->outends=outends;
528         list_add(&qedge->outpeers,&outends->outlist);
529         list_add(&qedge->activepeers,&outends->idle);
530         can_spin_unlock(&qedge->fifo.fifo_lock);
531         can_spin_unlock(&outends->ends_lock);
532         can_spin_unlock_irqrestore(&inends->ends_lock, flags);
533         canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH);
534
535         if(canque_fifo_test_and_set_fl(&qedge->fifo, READY))
536                 canque_edge_decref(qedge);
537         return 0;
538 }
539
540 /**
541  * canqueue_disconnect_edge - disconnect edge from communicating entities
542  * @qedge: pointer to edge
543  *
544  * Return Value: Negative value means, that edge is used by somebody
545  *      other and cannot be disconnected. Operation has to be delayed.
546  */
547 int canqueue_disconnect_edge(struct canque_edge_t *qedge)
548 {
549         int ret;
550         can_spin_irqflags_t flags;
551         struct canque_ends_t *inends, *outends;
552
553         inends=qedge->inends;
554         if(inends) can_spin_lock_irqsave(&inends->ends_lock,flags);
555         outends=qedge->outends;
556         if(outends) can_spin_lock(&outends->ends_lock);
557         can_spin_lock(&qedge->fifo.fifo_lock);
558         if(atomic_read(&qedge->edge_used)==0) {
559                 if(qedge->outends){
560                         list_del(&qedge->activepeers);
561                         mb(); /* memory barrier for list_empty use in canque_dead_func */
562                         list_del(&qedge->outpeers);
563                         qedge->outends=NULL;
564                 }
565                 if(qedge->inends){
566                         list_del(&qedge->inpeers);
567                         qedge->inends=NULL;
568                 }
569                 ret=1;
570         } else ret=-1;
571         can_spin_unlock(&qedge->fifo.fifo_lock);
572         if(outends) can_spin_unlock(&outends->ends_lock);
573         if(inends) can_spin_unlock_irqrestore(&inends->ends_lock,flags);
574         DEBUGQUE("canqueue_disconnect_edge %d returned %d\n",qedge->edge_num,ret);
575         return ret;
576 }
577
578
579 /**
580  * canqueue_block_inlist - block slot allocation of all outgoing edges of specified ends  
581  * @qends: pointer to ends structure
582  */
583 void canqueue_block_inlist(struct canque_ends_t *qends)
584 {
585         struct canque_edge_t *edge;
586
587         canque_for_each_inedge(qends, edge) {
588                 canque_fifo_set_fl(&edge->fifo,BLOCK);
589         }
590 }
591
592
593 /**
594  * canqueue_block_outlist - block slot allocation of all incoming edges of specified ends  
595  * @qends: pointer to ends structure
596  */
597 void canqueue_block_outlist(struct canque_ends_t *qends)
598 {
599         struct canque_edge_t *edge;
600
601         canque_for_each_outedge(qends, edge) {
602                 canque_fifo_set_fl(&edge->fifo,BLOCK);
603         }
604 }
605
606
607 /**
608  * canqueue_ends_kill_inlist - sends request to die to all outgoing edges
609  * @qends: pointer to ends structure
610  * @send_rest: select, whether already allocated slots should be processed
611  *      by FIFO output side
612  *
613  * Return Value: Non-zero value means, that not all edges could be immediately
614  *      disconnected and that ends structure memory release has to be delayed
615  */
616 int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest)
617 {
618         struct canque_edge_t *edge;
619         
620         canque_for_each_inedge(qends, edge){
621                 canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
622                 if(send_rest){
623                         canque_edge_incref(edge);
624                         if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){
625                                 if(!canque_fifo_test_fl(&edge->fifo, EMPTY))
626                                         continue;
627                                 if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY))
628                                         continue;
629                         }
630                         canque_edge_decref(edge);
631                 }
632         }
633         return list_empty(&qends->inlist)?0:1;
634 }
635
636
637 /**
638  * canqueue_ends_kill_outlist - sends request to die to all incoming edges
639  * @qends: pointer to ends structure
640  *
641  * Return Value: Non-zero value means, that not all edges could be immediately
642  *      disconnected and that ends structure memory release has to be delayed
643  */
644 int canqueue_ends_kill_outlist(struct canque_ends_t *qends)
645 {
646         struct canque_edge_t *edge;
647         
648         canque_for_each_outedge(qends, edge){
649                 canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
650         }
651         return list_empty(&qends->outlist)?0:1;
652 }
653
654
655 /**
656  * canqueue_ends_filt_conjuction - computes conjunction of incoming edges filters filters
657  * @qends: pointer to ends structure
658  * @filt: pointer the filter structure filled by computed filters conjunction
659  *
660  * Return Value: Number of incoming edges
661  */
662 int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt)
663 {
664         struct canque_edge_t *edge;
665         int cnt=0;
666         unsigned long filtid=0;
667         unsigned long filtmask=~0;
668         unsigned long local_only=canque_filtid2internal(0,MSG_LOCAL);
669
670         canque_for_each_inedge(qends, edge){
671                 /* skip edges processing only local messages */
672                 if(edge->filtid & edge->filtmask & local_only)
673                         continue;
674
675                 if(!cnt++)
676                         filtid = edge->filtid;
677                 else
678                         filtmask &= ~(filtid ^ edge->filtid);
679         
680                 filtmask &= edge->filtmask;
681         }
682         
683         filt->id = filtid & MSG_ID_MASK;
684         filt->mask = filtmask & MSG_ID_MASK;
685         filtid >>= 28;
686         filtmask >>= 28;
687         filt->flags = filtid & MSG_EXT;
688         if(filtmask & (MSG_EXT))
689                 filt->flags |= MSG_EXT_MASK;
690         if(filtid & (MSG_RTR<<1))
691                 filt->flags |= MSG_RTR<<1;
692         if(filtmask & (MSG_RTR<<1))
693                 filt->flags |= MSG_RTR_MASK;
694         return cnt;
695 }
696