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