X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/b34a548a5dfd2f0b068fd835a4cd51680d851068..2827b727d2910a3b48f9de7d67b3a67f59e256c7:/lincan/src/can_quekern.c diff --git a/lincan/src/can_quekern.c b/lincan/src/can_quekern.c index 39c0330..3eea5a3 100644 --- a/lincan/src/can_quekern.c +++ b/lincan/src/can_quekern.c @@ -15,14 +15,14 @@ extern atomic_t edge_num_cnt; #ifdef CAN_DEBUG - #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\ + #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern (debug): " fmt,\ ##args) #else #define DEBUGQUE(fmt,args...) #endif -#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_queue: " fmt,\ +#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern: " fmt,\ ##args) @@ -84,8 +84,10 @@ void canque_dead_func(unsigned long data) can_spin_lock_irqsave(&canque_dead_func_lock, flags); entry=canque_dead_ends.next; can_spin_unlock_irqrestore(&canque_dead_func_lock,flags); + /* lock can be released there, because only one instance of canque_dead_tl + can run at once and all other functions add ends only to head */ while(entry!=&canque_dead_ends){ - qends=list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers); + qends=list_entry(entry,struct canque_ends_t,dead_peers); entry=entry->next; if(!list_empty(&qends->inlist)) continue; @@ -106,6 +108,19 @@ void canque_dead_func(unsigned long data) } +static inline void canque_dead_tasklet_schedule(void) +{ + #ifdef CAN_WITH_RTL + if(!rtl_rt_system_is_idle()){ + set_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend); + rtl_global_pend_irq (canqueue_rtl_irq); + return; + } + #endif /*CAN_WITH_RTL*/ + + tasklet_schedule(&canque_dead_tl); +} + void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl) { @@ -113,6 +128,27 @@ void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl) if(dead_fl) return; + canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + #ifdef CAN_WITH_RTL + /* The problem of the above call is, that in RT-Linux to Linux notify + case is edge scheduled for delayed notify delivery, this needs + to be reflected there */ + if(atomic_read(&edge->edge_used)>0){ + can_spin_lock_irqsave(&edge->inends->ends_lock, flags); + can_spin_lock(&edge->outends->ends_lock); + if(atomic_read(&edge->edge_used)>0){ + /* left edge to live for a while, banshee comes again in a while */ + canque_fifo_clear_fl(&edge->fifo,DEAD); + can_spin_unlock(&edge->outends->ends_lock); + can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags); + can_printk(KERN_ERR "can_quertl (debug): canque_edge_do_dead postponed\n"); + return; + } + can_spin_unlock(&edge->outends->ends_lock); + can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags); + } + #endif /*CAN_WITH_RTL*/ + if(canqueue_disconnect_edge(edge)<0){ ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n"); return; @@ -121,7 +157,7 @@ void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl) can_spin_lock_irqsave(&canque_dead_func_lock, flags); list_add(&edge->inpeers,&canque_dead_edges); can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); - tasklet_schedule(&canque_dead_tl); + canque_dead_tasklet_schedule(); } @@ -140,6 +176,13 @@ void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl) * @qends: pointer to the callback side ends structure * @qedge: edge which invoked notification * @what: notification type + * + * The notification event is handled directly by call of this function except case, + * when called from RT-Linux context in mixed mode Linux/RT-Linux compilation. + * It is not possible to directly call Linux kernel synchronization primitives + * in such case. The notification request is postponed and signaled by @pending_inops flags + * by call canqueue_rtl2lin_check_and_pend() function. + * The edge reference count is increased until until all pending notifications are processed. */ void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) { @@ -340,7 +383,7 @@ struct canque_edge_t *canque_new_edge_kern(int slotsnr) #ifdef USE_SYNC_DISCONNECT_EDGE_KERN -/** +/*not included in doc * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait * @qends: ends structure belonging to calling communication object * @qedge: pointer to edge @@ -427,7 +470,7 @@ void canqueue_ends_dispose_postpone(struct canque_ends_t *qends) qends->ends_flags |= CAN_ENDSF_DEAD; list_add(&qends->dead_peers,&canque_dead_ends); can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); - tasklet_schedule(&canque_dead_tl); + canque_dead_tasklet_schedule(); }