X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/102b0fcc467c77d0a8f82cfee060353e3cf17261..c6d6f58c34e1b6a4c03d1e86d1abf48eeb6f5624:/lincan/src/can_queue.c diff --git a/lincan/src/can_queue.c b/lincan/src/can_queue.c index 75853a9..6ee0550 100644 --- a/lincan/src/can_queue.c +++ b/lincan/src/can_queue.c @@ -6,16 +6,8 @@ * Version lincan-0.2 9 Jul 2003 */ -#define __NO_VERSION__ -#include -#include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) -#include -#else -#include -#endif -#include #include "../include/can.h" +#include "../include/can_sysdep.h" #include "../include/can_queue.h" /* @@ -26,19 +18,21 @@ */ extern int processlocal; -/*#define CAN_DEBUG*/ +atomic_t edge_num_cnt; + +//#define CAN_DEBUG #ifdef CAN_DEBUG #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\ ##args) - - atomic_t edge_num_cnt; + #else #define DEBUGQUE(fmt,args...) #endif #define CANQUE_ROUNDROB 1 + /** * canque_fifo_flush_slots - free all ready slots from the FIFO * @fifo: pointer to the FIFO structure @@ -134,15 +128,11 @@ int canque_get_inslot(struct canque_ends_t *qends, struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd) { int ret=-2; - unsigned long flags; struct canque_edge_t *edge; - spin_lock_irqsave(&qends->ends_lock, flags); - if(!list_empty(&qends->inlist)){ - edge=list_entry(qends->inlist.next,struct canque_edge_t,inpeers); - if(!canque_fifo_test_fl(&edge->fifo,BLOCK)&&!canque_fifo_test_fl(&edge->fifo,DEAD)){ - atomic_inc(&edge->edge_used); - spin_unlock_irqrestore(&qends->ends_lock, flags); + edge=canque_first_inedge(qends); + if(edge){ + if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){ ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd); if(ret>0){ *qedgep=edge; @@ -150,12 +140,9 @@ int canque_get_inslot(struct canque_ends_t *qends, return ret; } - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&edge->edge_used)) - canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); } + canque_edge_decref(edge); } - spin_unlock_irqrestore(&qends->ends_lock, flags); *qedgep=NULL; DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd); return ret; @@ -183,14 +170,10 @@ int canque_get_inslot4id(struct canque_ends_t *qends, int cmd, unsigned long id, int prio) { int ret=-2; - unsigned long flags; struct canque_edge_t *edge, *bestedge=NULL; - struct list_head *entry; - spin_lock_irqsave(&qends->ends_lock, flags); - list_for_each(entry,&qends->inlist){ - edge=list_entry(entry,struct canque_edge_t,inpeers); - if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD)) + canque_for_each_inedge(qends, edge){ + if(canque_fifo_test_fl(&edge->fifo,BLOCK)) continue; if((id^edge->filtid)&edge->filtmask) continue; @@ -199,7 +182,9 @@ int canque_get_inslot4id(struct canque_ends_t *qends, if (!edge->filtmask) continue; } else { if(edge->filtmask){ + canque_edge_decref(bestedge); bestedge=edge; + canque_edge_incref(bestedge); continue; } } @@ -208,23 +193,20 @@ int canque_get_inslot4id(struct canque_ends_t *qends, } else { if(bestedge->edge_prio<=prio) continue; } + canque_edge_decref(bestedge); } bestedge=edge; + canque_edge_incref(bestedge); } if((edge=bestedge)!=NULL){ - atomic_inc(&edge->edge_used); - spin_unlock_irqrestore(&qends->ends_lock, flags); ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd); if(ret>0){ *qedgep=edge; DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num); return ret; } - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&edge->edge_used)) - canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + canque_edge_decref(bestedge); } - spin_unlock_irqrestore(&qends->ends_lock, flags); *qedgep=NULL; DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio); return ret; @@ -246,16 +228,12 @@ int canque_put_inslot(struct canque_ends_t *qends, struct canque_edge_t *qedge, struct canque_slot_t *slot) { int ret; - unsigned long flags; ret=canque_fifo_put_inslot(&qedge->fifo,slot); if(ret) { canque_activate_edge(qends,qedge); canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC); } - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&qedge->edge_used)) - canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); - spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(qedge); DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret); return ret; } @@ -274,15 +252,11 @@ int canque_abort_inslot(struct canque_ends_t *qends, struct canque_edge_t *qedge, struct canque_slot_t *slot) { int ret; - unsigned long flags; ret=canque_fifo_abort_inslot(&qedge->fifo,slot); if(ret) { canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE); } - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&qedge->edge_used)) - canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); - spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(qedge); DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret); return ret; } @@ -300,26 +274,19 @@ int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg) { int destnr=0; int ret; - unsigned long flags; unsigned long msgid; struct canque_edge_t *edge; - struct list_head *entry; struct canque_slot_t *slot; DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n", msg->id, msg->flags); msgid = canque_filtid2internal(msg->id, msg->flags); - spin_lock_irqsave(&qends->ends_lock, flags); - list_for_each(entry,&qends->inlist){ - edge=list_entry(entry,struct canque_edge_t,inpeers); - if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD)) + canque_for_each_inedge(qends, edge) { + if(canque_fifo_test_fl(&edge->fifo,BLOCK)) continue; - /* FIXME: the next comparison should be outside of ends lock */ if((msgid^edge->filtid)&edge->filtmask) continue; - atomic_inc(&edge->edge_used); - spin_unlock_irqrestore(&qends->ends_lock, flags); ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0); if(ret>0){ slot->msg=*msg; @@ -331,11 +298,7 @@ int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg) } } - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&edge->edge_used)) - canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); } - spin_unlock_irqrestore(&qends->ends_lock, flags); DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr); return destnr; } @@ -358,16 +321,28 @@ int canque_test_outslot(struct canque_ends_t *qends, unsigned long flags; int prio; struct canque_edge_t *edge; + int ret; spin_lock_irqsave(&qends->ends_lock, flags); for(prio=CANQUEUE_PRIO_NR;--prio>=0;){ - if(!list_empty(&qends->active[prio])){ + while(!list_empty(&qends->active[prio])){ edge=list_entry(qends->active[prio].next,struct canque_edge_t,outpeers); - atomic_inc(&edge->edge_used); - spin_unlock_irqrestore(&qends->ends_lock, flags); - *qedgep=edge; - DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num); - return canque_fifo_test_outslot(&edge->fifo, slotp); + if(!canque_fifo_test_fl(&edge->fifo,DEAD)) { + canque_edge_incref(edge); + spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=edge; + DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num); + ret=canque_fifo_test_outslot(&edge->fifo, slotp); + if(ret>=0) + return ret; + spin_lock_irqsave(&qends->ends_lock, flags); + } + 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); + } + spin_unlock(&edge->fifo.fifo_lock); } } spin_unlock_irqrestore(&qends->ends_lock, flags); @@ -399,23 +374,20 @@ int canque_free_outslot(struct canque_ends_t *qends, if(ret&CAN_FIFOF_FULL) canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE); spin_lock_irqsave(&qends->ends_lock, flags); - if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB){ + if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){ 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); - } - #if CANQUE_ROUNDROB - else{ + } else{ list_del(&qedge->outpeers); list_add_tail(&qedge->outpeers,&qends->active[qedge->edge_prio]); } - #endif /*CANQUE_ROUNDROB*/ spin_unlock(&qedge->fifo.fifo_lock); } - if(atomic_dec_and_test(&qedge->edge_used)) - canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(qedge); DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret); return ret; } @@ -434,12 +406,8 @@ int canque_again_outslot(struct canque_ends_t *qends, struct canque_edge_t *qedge, struct canque_slot_t *slot) { int ret; - unsigned long flags; ret=canque_fifo_again_outslot(&qedge->fifo, slot); - spin_lock_irqsave(&qends->ends_lock, flags); - if(atomic_dec_and_test(&qedge->edge_used)) - canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); - spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(qedge); DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret); return ret; } @@ -475,7 +443,7 @@ int canque_set_filt(struct canque_edge_t *qedge, canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH); } spin_lock_irqsave(&qedge->fifo.fifo_lock,flags); - if(!ret)canque_fifo_clear_fl(&qedge->fifo,BLOCK); + if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK); spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags); DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n", @@ -534,155 +502,6 @@ int canqueue_ends_init_gen(struct canque_ends_t *qends) } -/** - * canqueue_notify_kern - notification callback handler for Linux userspace clients - * @qends: pointer to the callback side ends structure - * @qedge: edge which invoked notification - * @what: notification type - */ -void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) -{ - DEBUGQUE("canqueue_notify_kern for edge %d and event %d\n",qedge->edge_num,what); - switch(what){ - case CANQUEUE_NOTIFY_EMPTY: - wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); - break; - case CANQUEUE_NOTIFY_SPACE: - wake_up_interruptible(&qends->endinfo.fileinfo.writeq); - break; - case CANQUEUE_NOTIFY_PROC: - wake_up_interruptible(&qends->endinfo.fileinfo.readq); - break; - case CANQUEUE_NOTIFY_NOUSR: - wake_up_interruptible(&qends->endinfo.fileinfo.readq); - wake_up_interruptible(&qends->endinfo.fileinfo.writeq); - wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); - break; - case CANQUEUE_NOTIFY_DEAD: - if(atomic_read(&qedge->edge_used)>0) - atomic_dec(&qedge->edge_used); - break; - case CANQUEUE_NOTIFY_ATACH: - atomic_inc(&qedge->edge_used); - break; - } -} - -/** - * canqueue_ends_init_kern - Linux userspace clients specific ends initialization - * @qends: pointer to the callback side ends structure - */ -int canqueue_ends_init_kern(struct canque_ends_t *qends) -{ - canqueue_ends_init_gen(qends); - qends->context=NULL; - init_waitqueue_head(&qends->endinfo.fileinfo.readq); - init_waitqueue_head(&qends->endinfo.fileinfo.writeq); - init_waitqueue_head(&qends->endinfo.fileinfo.emptyq); - qends->notify=canqueue_notify_kern; - DEBUGQUE("canqueue_ends_init_kern\n"); - return 0; -} - - -/** - * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID - * @qends: ends structure belonging to calling communication object - * @qedgep: place to store pointer to found edge - * @slotp: place to store pointer to allocated slot - * @cmd: command type for slot - * @id: communication ID of message to send into edge - * @prio: optional priority of message - * - * Same as canque_get_inslot4id(), except, that it waits for free slot - * in case, that queue is full. Function is specific for Linux userspace clients. - * Return Value: If there is no usable edge negative value is returned. - */ -int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends, - struct canque_edge_t **qedgep, struct canque_slot_t **slotp, - int cmd, unsigned long id, int prio) -{ - int ret=-1; - DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio); - wait_event_interruptible((qends->endinfo.fileinfo.writeq), - (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1); - return ret; -} - -/** - * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends - * @qends: ends structure belonging to calling communication object - * @qedgep: place to store pointer to found edge - * @slotp: place to store pointer to received slot - * - * The same as canque_test_outslot(), except it waits in the case, that there is - * no ready slot for given ends. Function is specific for Linux userspace clients. - * Return Value: Negative value informs, that there is no ready output - * slot for given ends. Positive value is equal to the command - * slot has been allocated by the input side. - */ -int canque_get_outslot_wait_kern(struct canque_ends_t *qends, - struct canque_edge_t **qedgep, struct canque_slot_t **slotp) -{ - int ret=-1; - DEBUGQUE("canque_get_outslot_wait_kern\n"); - wait_event_interruptible((qends->endinfo.fileinfo.readq), - (ret=canque_test_outslot(qends,qedgep,slotp))!=-1); - return ret; -} - -/** - * canque_sync_wait_kern - wait for all slots processing - * @qends: ends structure belonging to calling communication object - * @qedge: pointer to edge - * - * Functions waits for ends transition into empty state. - * Return Value: Positive value indicates, that edge empty state has been reached. - * Negative or zero value informs about interrupted wait or other problem. - */ -int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge) -{ - int ret=-1; - DEBUGQUE("canque_sync_wait_kern\n"); - wait_event_interruptible((qends->endinfo.fileinfo.emptyq), - (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)); - return ret; -} - - -/** - * canque_new_edge_kern - allocate new edge structure in the Linux kernel context - * @slotsnr: required number of slots in the newly allocated edge structure - * - * Return Value: Returns pointer to allocated slot structure or %NULL if - * there is not enough memory to process operation. - */ -struct canque_edge_t *canque_new_edge_kern(int slotsnr) -{ - struct canque_edge_t *qedge; - qedge = (struct canque_edge_t *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL); - if(qedge == NULL) return NULL; - - memset(qedge,0,sizeof(struct canque_edge_t)); - spin_lock_init(&qedge->fifo.fifo_lock); - if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){ - kfree(qedge); - DEBUGQUE("canque_new_edge_kern failed\n"); - return NULL; - } - atomic_set(&qedge->edge_used,0); - qedge->filtid = 0; - qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0); - qedge->edge_prio = 0; - #ifdef CAN_DEBUG - /* not exactly clean, but enough for debugging */ - atomic_inc(&edge_num_cnt); - qedge->edge_num=atomic_read(&edge_num_cnt); - #endif /* CAN_DEBUG */ - DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num); - return qedge; -} - /** * canqueue_connect_edge - connect edge between two communication entities * @qedge: pointer to edge @@ -696,7 +515,7 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine unsigned long flags; if(qedge == NULL) return -1; DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num); - atomic_inc(&qedge->edge_used); + canque_edge_incref(qedge); spin_lock_irqsave(&inends->ends_lock, flags); spin_lock(&outends->ends_lock); spin_lock(&qedge->fifo.fifo_lock); @@ -707,12 +526,10 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine spin_unlock(&qedge->fifo.fifo_lock); spin_unlock(&outends->ends_lock); spin_unlock_irqrestore(&inends->ends_lock, flags); - canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATACH); - - spin_lock_irqsave(&qedge->fifo.fifo_lock, flags); - if(atomic_dec_and_test(&qedge->edge_used)) - canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); - spin_unlock_irqrestore(&qedge->fifo.fifo_lock, flags); + canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH); + + if(canque_fifo_test_and_set_fl(&qedge->fifo, READY)) + canque_edge_decref(qedge); return 0; } @@ -720,8 +537,8 @@ int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *ine * canqueue_disconnect_edge - disconnect edge from communicating entities * @qedge: pointer to edge * - * Return Value: Negative value means, that edge is used and cannot - * be disconnected. Operation has to be delayed. + * Return Value: Negative value means, that edge is used by somebody + * other and cannot be disconnected. Operation has to be delayed. */ int canqueue_disconnect_edge(struct canque_edge_t *qedge) { @@ -752,113 +569,3 @@ int canqueue_disconnect_edge(struct canque_edge_t *qedge) return ret; } -/** - * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait - * @qends: ends structure belonging to calling communication object - * @qedge: pointer to edge - * - * Same as canqueue_disconnect_edge(), but tries to wait for state with zero - * use counter. - * Return Value: Negative value means, that edge is used and cannot - * be disconnected yet. Operation has to be delayed. - */ -int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge) -{ - canque_fifo_set_fl(&qedge->fifo,BLOCK); - DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num); - if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){ - canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD); - if(atomic_read(&qedge->edge_used)>0) - atomic_dec(&qedge->edge_used); - DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num); - wait_event_interruptible((qends->endinfo.fileinfo.emptyq), - (canqueue_disconnect_edge(qedge)>=0)); - return 0; - } else { - DEBUGQUE("canqueue_disconnect_edge_kern failed\n"); - return -1; - } -} - - -int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list) -{ - struct canque_edge_t *edge; - unsigned long flags; - for(;;){ - spin_lock_irqsave(&qends->ends_lock,flags); - if(list_empty(list)){ - spin_unlock_irqrestore(&qends->ends_lock,flags); - return 0; - } - 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); - atomic_inc(&edge->edge_used); - spin_unlock_irqrestore(&qends->ends_lock,flags); - if(canqueue_disconnect_edge_kern(qends, edge)>=0) { - /* Free edge memory */ - canque_fifo_done(&edge->fifo); - kfree(edge); - }else{ - DEBUGQUE("canqueue_disconnect_list_kern in troubles\n"); - DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags); - return -1; - } - } -} - -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); - } -} - - -/** - * canqueue_ends_done_kern - finalizing of the ends structure for Linux kernel clients - * @qends: pointer to ends structure - * @sync: flag indicating, that user wants to wait for processing of all remaining - * messages - * - * Return Value: Function should be designed such way to not fail. - */ -int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync) -{ - unsigned long flags; - int i; - - DEBUGQUE("canqueue_ends_done_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); - - for(i=CANQUEUE_PRIO_NR;--i>=0;){ - canqueue_disconnect_list_kern(qends, &qends->active[i]); - } - canqueue_disconnect_list_kern(qends, &qends->idle); - canqueue_disconnect_list_kern(qends, &qends->inlist); - - wake_up_interruptible(&qends->endinfo.fileinfo.readq); - wake_up_interruptible(&qends->endinfo.fileinfo.writeq); - wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); - - - return 0; -} -