Jan Kiszka wrote:
> Dmitry Adamushko wrote:
>> On 21/06/07, Jan Kiszka <[EMAIL PROTECTED]> wrote:
>>>> [ .. ]
>>>> surprise-surprise.. sure, one way or another it must be fixed. heh..
>>>> too many bugs (and I don't even want to say who's responsible) :-/
>>> I wouldn't accept all the responsibility if I were you.
>> I have no problems in this respect. I was just a bit sarcastic with
>> the way to say "it's my fault".
>>
>>
>>> It's a sign that the design might be
>>> too complex now
>> frankly speaking, I don't think it's really complex :)
>>
>>
>>> Things get worse, at least with XENO_OPT_STATS: Due to the runtime
>>> statistics collection, we may end up with dangling references to our
>>> xnintr object even after xnintr_shirq_unlock().
>>>
>>> We would actually need some kind of IRQ_INPROGRESS + synchronize_irq()
>>> at i-pipe level. But we have the problem, in contrast to the kernel,
>>> that we reschedule from inside the handler (more precisely: at nucleus
>>> level), thus synchronize_irq() would not just wait on some simple
>>> handler to exit...
>> Yeah.. we had already conversations on this topic (I think with
>> Philippe) and, if I recall right, that was one of the reasons. That's
>> why synchronize_irq() is in the nucleus layer.
> 
> Hmm, then we may be forced to get the cookie out of ipipe's hands again
> and put it back into a nucleus irq array, i.e. move the cookie
> dereferencing under a nucleus managed per-irq lock. But there is still
> the issue with xnsched_t::current_account...
> 

Hell, what a mess...

Here is a first attempt to address the remaining issues. Take it with a
huge grain of salt, I haven't yet made up my mind if it really solves
our races and if it isn't too ugly.

Please direct special attention to

 - xnintr_sync_stat_references (the comment says it all)

 - xnintr_edge_shirq_handler (unrelated change, but I somehow felt like
   this is nicer)

Only compile-tested under various .configs. Any comment welcome.

Thanks,
Jan
Index: xenomai/ksrc/nucleus/intr.c
===================================================================
--- xenomai.orig/ksrc/nucleus/intr.c
+++ xenomai/ksrc/nucleus/intr.c
@@ -41,6 +41,18 @@
 
 DEFINE_PRIVATE_XNLOCK(intrlock);
 
+typedef struct xnintr_irq {
+
+       DECLARE_XNLOCK(lock);
+
+#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
+       xnintr_t *handlers;
+       int unhandled;
+#endif
+} ____cacheline_aligned_in_smp xnintr_irq_t;
+
+static xnintr_irq_t xnirqs[RTHAL_NR_IRQS];
+
 #ifdef CONFIG_XENO_OPT_STATS
 xnintr_t nkclock;      /* Only for statistics */
 int xnintr_count = 1;  /* Number of attached xnintr objects + nkclock */
@@ -63,9 +75,23 @@ static inline void xnintr_stat_counter_d
        xnarch_memory_barrier();
        xnintr_list_rev++;
 }
+
+static inline void xnintr_sync_stat_references(xnintr_t *intr)
+{
+       int cpu;
+
+       for_each_online_cpu(cpu) {
+               xnsched_t *sched = xnpod_sched_slot(cpu);
+
+               /* I don't feel very well... hacking this. */
+               while (sched->current_account == &intr->stat[cpu].account)
+                       cpu_relax();
+       }
+}
 #else
 static inline void xnintr_stat_counter_inc(void) {}
 static inline void xnintr_stat_counter_dec(void) {}
+static inline void xnintr_sync_stat_references(xnintr_t *intr) {}
 #endif /* CONFIG_XENO_OPT_STATS */
 
 /*
@@ -76,7 +102,7 @@ static inline void xnintr_stat_counter_d
 static void xnintr_irq_handler(unsigned irq, void *cookie)
 {
        xnsched_t *sched = xnpod_current_sched();
-       xnintr_t *intr = (xnintr_t *)cookie;
+       xnintr_t *intr;
        xnstat_runtime_t *prev;
        xnticks_t start;
        int s;
@@ -86,6 +112,16 @@ static void xnintr_irq_handler(unsigned 
        xnltt_log_event(xeno_ev_ienter, irq);
 
        ++sched->inesting;
+
+       xnlock_get(&xnirqs[irq].lock);
+
+#ifdef CONFIG_SMP
+       /* In SMP case, we have to reload the cookie under the per-IRQ lock
+          to avoid racing with xnintr_detach. */
+       intr = rthal_irq_cookie(&rthal_domain, irq);
+#else
+       intr = cookie;
+#endif
        s = intr->isr(intr);
 
        if (unlikely(s == XN_ISR_NONE)) {
@@ -102,6 +138,8 @@ static void xnintr_irq_handler(unsigned 
                intr->unhandled = 0;
        }
 
+       xnlock_put(&xnirqs[irq].lock);
+
        if (s & XN_ISR_PROPAGATE)
                xnarch_chain_irq(irq);
        else if (!(s & XN_ISR_NOENABLE))
@@ -161,18 +199,6 @@ void xnintr_clock_handler(void)
 
 #if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
 
-typedef struct xnintr_shirq {
-
-       xnintr_t *handlers;
-       int unhandled;
-#ifdef CONFIG_SMP
-       xnlock_t lock;
-#endif
-
-} xnintr_shirq_t;
-
-static xnintr_shirq_t xnshirqs[RTHAL_NR_IRQS];
-
 #if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL)
 /*
  * Low-level interrupt handler dispatching the user-defined ISRs for
@@ -184,7 +210,7 @@ static void xnintr_shirq_handler(unsigne
        xnsched_t *sched = xnpod_current_sched();
        xnstat_runtime_t *prev;
        xnticks_t start;
-       xnintr_shirq_t *shirq = &xnshirqs[irq];
+       xnintr_irq_t *shirq = &xnirqs[irq];
        xnintr_t *intr;
        int s = 0;
 
@@ -253,7 +279,7 @@ static void xnintr_edge_shirq_handler(un
        xnsched_t *sched = xnpod_current_sched();
        xnstat_runtime_t *prev;
        xnticks_t start;
-       xnintr_shirq_t *shirq = &xnshirqs[irq];
+       xnintr_irq_t *shirq = &xnirqs[irq];
        xnintr_t *intr, *end = NULL;
        int s = 0, counter = 0;
 
@@ -277,15 +303,15 @@ static void xnintr_edge_shirq_handler(un
                s |= ret;
 
                if (code == XN_ISR_HANDLED) {
-                       end = NULL;
+                       if (!(end = (intr->next)))
+                               end = shirq->handlers;
                        xnstat_counter_inc(
                                &intr->stat[xnsched_cpu(sched)].hits);
                        xnstat_runtime_lazy_switch(sched,
                                &intr->stat[xnsched_cpu(sched)].account,
                                start);
                        start = xnstat_runtime_now();
-               } else if (code == XN_ISR_NONE && end == NULL)
-                       end = intr;
+               }
 
                if (counter++ > MAX_EDGEIRQ_COUNTER)
                        break;
@@ -326,7 +352,7 @@ static void xnintr_edge_shirq_handler(un
 
 static inline int xnintr_irq_attach(xnintr_t *intr)
 {
-       xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
+       xnintr_irq_t *shirq = &xnirqs[intr->irq];
        xnintr_t *prev, **p = &shirq->handlers;
        int err;
 
@@ -379,17 +405,16 @@ static inline int xnintr_irq_attach(xnin
 
        intr->next = NULL;
 
-       /* Add a given interrupt object. */
-       xnlock_get(&shirq->lock);
+       /* Add the given interrupt object. No need to synchronise with the IRQ
+          handler, we are only extending the chain. */
        *p = intr;
-       xnlock_put(&shirq->lock);
 
        return 0;
 }
 
 static inline int xnintr_irq_detach(xnintr_t *intr)
 {
-       xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
+       xnintr_irq_t *shirq = &xnirqs[intr->irq];
        xnintr_t *e, **p = &shirq->handlers;
        int err = 0;
 
@@ -406,6 +431,7 @@ static inline int xnintr_irq_detach(xnin
                        /* Remove the given interrupt object from the list. */
                        xnlock_get(&shirq->lock);
                        *p = e->next;
+                       xnintr_sync_stat_references(intr);
                        xnlock_put(&shirq->lock);
 
                        /* Release the IRQ line if this was the last user */
@@ -422,14 +448,6 @@ static inline int xnintr_irq_detach(xnin
        return err;
 }
 
-int xnintr_mount(void)
-{
-       int i;
-       for (i = 0; i < RTHAL_NR_IRQS; ++i)
-               xnlock_init(&xnshirqs[i].lock);
-       return 0;
-}
-
 #else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
 
 static inline int xnintr_irq_attach(xnintr_t *intr)
@@ -439,13 +457,29 @@ static inline int xnintr_irq_attach(xnin
 
 static inline int xnintr_irq_detach(xnintr_t *intr)
 {
-       return xnarch_release_irq(intr->irq);
-}
+       int irq = intr->irq;
+       int err;
+
+       xnlock_get(&xnirqs[irq].lock);
 
-int xnintr_mount(void) { return 0; }
+       err = xnarch_release_irq(intr->irq);
+       xnintr_sync_stat_references(intr);
+
+       xnlock_put(&xnirqs[irq].lock);
+
+       return err;
+}
 
 #endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
 
+int xnintr_mount(void)
+{
+       int i;
+       for (i = 0; i < RTHAL_NR_IRQS; ++i)
+               xnlock_init(&xnirqs[i].lock);
+       return 0;
+}
+
 /*!
  * \fn int xnintr_init (xnintr_t *intr,const char *name,unsigned irq,xnisr_t 
isr,xniack_t iack,xnflags_t flags)
  * \brief Initialize an interrupt object.
@@ -809,7 +843,7 @@ int xnintr_irq_proc(unsigned int irq, ch
        xnlock_get_irqsave(&intrlock, s);
 
 #if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-       intr = xnshirqs[irq].handlers;
+       intr = xnirqs[irq].handlers;
        if (intr) {
                strcpy(p, "        "); p += 8;
 
@@ -862,7 +896,7 @@ int xnintr_query(int irq, int *cpu, xnin
        else if (irq == XNARCH_TIMER_IRQ)
                intr = &nkclock;
        else
-               intr = xnshirqs[irq].handlers;
+               intr = xnirqs[irq].handlers;
 #else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
        if (*prev)
                intr = NULL;

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to