shirq locking rework
RFC PATCH 1/1 shirq locking rework
Hi Dmitry,
I had a look at the shared IRQ thing /wrt to my idea of switching between two list revisions. It turned out to be as nice as I expected when marvelling at the new xnintr_edge_shirq_handler() -- but it became horribly complex for setup/cleanup :(. So forget it, also the ring idea which took quite some part in the complexity increase.
Looking at xnintr_shirq_lock again: We have an atomic op, we have a memory barrier -- what do we actually gain by not using a usual xnlock here? I mean one that is per-IRQ, embedded in xnintr_shirq_t?
Well, I hate nested locks when it comes to real-time, but in this case I really found no simpler approach. There is the risk of deadlocks via
IRQ: xnintr_shirq::lock -> handler -> nklock vs.
Application: nklock -> xnintr_attach/detach -> xnintr_shirq::lock,
but we have no such case in-tree, nor should anyone try to do so elsewhere I assume (restriction is documented now). Note that this code is only compile-tested, and my brain still suffers from serious knots due to the first approach, thus no guarantee that I didn't messed things up.
Comments?
Jan
--- ksrc/nucleus/intr.c | 70 +++++++++++++++------------------------------------- 1 file changed, 21 insertions(+), 49 deletions(-)
ksrc/nucleus/intr.c +21 -49
@@ -169,40 +169,12 @@ typedef struct xnintr_shirq {xnintr_t *handlers;int unhandled; -#ifdef CONFIG_SMP -atomic_counter_t active; -#endif +DECLARE_XNLOCK (lock); } xnintr_shirq_t;static xnintr_shirq_t xnshirqs[RTHAL_NR_IRQS ]; -static inline void xnintr_shirq_lock (xnintr_shirq_t *shirq) -{ -#ifdef CONFIG_SMP -xnarch_atomic_inc (&shirq->active); -xnarch_memory_barrier (); -#endif -} - -static inline void xnintr_shirq_unlock (xnintr_shirq_t *shirq) -{ -#ifdef CONFIG_SMP -xnarch_memory_barrier (); -xnarch_atomic_dec (&shirq->active); -#endif -} - -void xnintr_synchronize (xnintr_t *intr) -{ -#ifdef CONFIG_SMP -xnintr_shirq_t *shirq = &xnshirqs[intr->irq]; - -while (xnarch_atomic_get (&shirq->active)) -cpu_relax (); -#endif -} -#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL )/* * Low-level interrupt handler dispatching the user-defined ISRs for
@@ -226,7 +198,7 @@ static void xnintr_shirq_handler(unsigne ++sched->inesting; -xnintr_shirq_lock (shirq); +xnlock_get (&shirq->lock); intr = shirq->handlers;while (intr) {
@@ -247,7 +219,7 @@ static void xnintr_shirq_handler(unsigne intr = intr->next; } -xnintr_shirq_unlock (shirq); +xnlock_put (&shirq->lock);if (unlikely (s ==XN_ISR_NONE )) {if (++shirq->unhandled ==XNINTR_MAX_UNHANDLED ) {
@@ -297,7 +269,7 @@ static void xnintr_edge_shirq_handler(un ++sched->inesting; -xnintr_shirq_lock (shirq); +xnlock_get (&shirq->lock); intr = shirq->handlers;while (intr != end) {
@@ -328,7 +300,7 @@ static void xnintr_edge_shirq_handler(un intr = shirq->handlers; } -xnintr_shirq_unlock (shirq); +xnlock_put (&shirq->lock);if (counter >MAX_EDGEIRQ_COUNTER ) xnlogerr
@@ -411,9 +383,12 @@ static inline int xnintr_irq_attach(xnin__setbits (intr->flags,XN_ISR_ATTACHED ); -/* Add a given interrupt object. */ intr->next =NULL ; + +/* Add a given interrupt object. */ +xnlock_get (&shirq->lock); *p = intr; +xnlock_put (&shirq->lock);return 0 ; }
@@ -434,8 +409,10 @@ static inline int xnintr_irq_detach(xninwhile ((e = *p) !=NULL ) {if (e == intr) { -/* Remove a given interrupt object from the list. */ +/* Remove the given interrupt object from the list. */ +xnlock_get (&shirq->lock); *p = e->next; +xnlock_put (&shirq->lock);/* Release the IRQ line if this was the last user */ if (shirq->handlers ==NULL )
@@ -454,12 +431,8 @@ static inline int xnintr_irq_detach(xninint xnintr_mount (void ) {int i; -for (i =0 ; i <RTHAL_NR_IRQS ; ++i) { - xnshirqs[i].handlers =NULL ; -#ifdef CONFIG_SMP -xnarch_atomic_set (&xnshirqs[i].active,0 ); -#endif - } +for (i =0 ; i <RTHAL_NR_IRQS ; ++i) +xnlock_init (&xnshirqs[i].lock);return 0 ; }
@@ -475,7 +448,6 @@ static inline int xnintr_irq_detach(xnin return xnarch_release_irq(intr->irq); } -void xnintr_synchronize (xnintr_t *intr) {}int xnintr_mount (void ) {return 0 ; }#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
@@ -651,6 +623,9 @@ int xnintr_destroy(xnintr_t *intr)* a low-level error occurred while attaching the interrupt. -EBUSY is * specifically returned if the interrupt object was already attached. * +* @note The caller <b>must not</b> hold nklock when invoking this service, +* this would cause deadlocks. +* * Environments: * * This service can be called from:
@@ -682,7 +657,7 @@ int xnintr_attach(xnintr_t *intr, void *if (!err)xnintr_stat_counter_inc (); - +xnlock_put_irqrestore (&intrlock, s);return err;
@@ -706,6 +681,9 @@ int xnintr_attach(xnintr_t *intr, void ** a non-attached interrupt object leads to a null-effect and returns * 0. * +* @note The caller <b>must not</b> hold nklock when invoking this service, +* this would cause deadlocks. +* * Environments: * * This service can be called from:
@@ -731,12 +709,6 @@ int xnintr_detach(xnintr_t *intr)xnlock_put_irqrestore (&intrlock, s); -/* The idea here is to keep a detached interrupt object valid as long -as the corresponding irq handler is running. This is one of the -requirements to iterate over the xnintr_shirq_t::handlers list in -xnintr_irq_handler() in a lockless way. */ -xnintr_synchronize (intr); -return err; }
Hello Jan,
Quoted 5 lines
Well, I hate nested locks when it comes to real-time, but in this case I really found no simpler approach. There is the risk of deadlocks via
IRQ: xnintr_shirq::lock -> handler -> nklock vs. Application: nklock -> xnintr_attach/detach -> xnintr_shirq::lock,
it's also relevant for the current code - xnintr_attach/detach() must not be called while holding the 'nklock'.
I think, your approach should work as well.. provided we have only a single reader vs. a single writter contention case, which seems to be the case here ('intrlock' is responsible for synchronization between xnintr_attach/detach()).. your approach does increase a worst case length of the lock(&intrlock) --> unlock(&intrlock) section... but that's unlikely to be critical.
I think, the patch I sent before addresses a reported earlier case with xnintr_edge_shirq_handler().. but your approach does make code shorter (and likely simpler), right? I don't see any problems it would possibly cause (maybe I'm missing smth yet :)
Signature · 2 lines
Best regards, Dmitry Adamushko
Quoted 10 lines · Dmitry Adamushko
Hello Jan,
Quoted 5 lines
Well, I hate nested locks when it comes to real-time, but in this case I really found no simpler approach. There is the risk of deadlocks via
IRQ: xnintr_shirq::lock -> handler -> nklock vs. Application: nklock -> xnintr_attach/detach -> xnintr_shirq::lock,it's also relevant for the current code - xnintr_attach/detach() must not be called while holding the 'nklock'.
That's good, no new restriction (the existing one will be documented now).
Quoted 4 lines
I think, your approach should work as well.. provided we have only a single reader vs. a single writter contention case, which seems to be the case here ('intrlock' is responsible for synchronization between
Single writer is ensured by intrlock, single reader comes from the per-IRQ scope of the inner lock.
Quoted 8 lines
xnintr_attach/detach()).. your approach does increase a worst case length of the
lock(&intrlock)-->unlock(&intrlock)section... but that's unlikely to be critical.I think, the patch I sent before addresses a reported earlier case with
xnintr_edge_shirq_handler().. but your approach does make code shorter (and likely simpler), right? I don't see any problems it would possibly cause (maybe I'm missing smth yet :)
I must confess I didn't get your idea immediately. Later on (cough, after hacking my own patch, cough) I had a closer look, and it first appeared fairly nice, despite the additional "ifs". But then I realised that "end == old_end" may produce false positives in case we have several times the same (and only the same) IRQ in a row. So, I'm afraid we have to live with only one candidate. :->
OK, will point our bug reporter to that patch now and ask for testing.
Jan
Quoted 10 lines · Jan Kiszka
[ ... ]
Quoted 8 lines
xnintr_attach/detach()).. your approach does increase a worst case length of the
lock(&intrlock)-->unlock(&intrlock)section... but that's unlikely to be critical.I think, the patch I sent before addresses a reported earlier case with
xnintr_edge_shirq_handler().. but your approach does make code shorter (and likely simpler), right? I don't see any problems it would possibly cause (maybe I'm missing smth yet :)
Quoted 7 lines
I must confess I didn't get your idea immediately. Later on (cough, after hacking my own patch, cough) I had a closer look, and it first appeared fairly nice, despite the additional "ifs". But then I realised that "end ==
old_end" may produce false positives in case we have several times the same (and only the same) IRQ in a row.
So, I'm afraid
we have to live with only one candidate. :->
It's not clear, can you elaborate your (non-working) scenario in more details? :-)
Note: I sent the second patch with the following correction :
...
} else if (code == XN_ISR_NONE && end == NULL) {
end = intr;
+ old_end = NULL;
}...
I don't see why this idea can't work (even if I made yet another error). Under some circumstances the following code will be triggered to end a loop even when 'end' is still valid
if (end && old_end == end)
intr = NULL;_but_ it'd be exactly a case when "intr == end" and hence, the loop would be finished anyway by the "while (intr && intr != end)" condition.. So sometimes it acts as yet _another_ check to exit the loop, IOW "while (intr && intr != end)" may be converted to just "while (intr)".
Quoted 3 lines
Jan
Signature · 2 lines
Best regards, Dmitry Adamushko
Quoted 35 lines · Dmitry Adamushko
Quoted 10 lines · Jan Kiszka
[ ... ]
Quoted 8 lines
xnintr_attach/detach()).. your approach does increase a worst case length of the
lock(&intrlock)-->unlock(&intrlock)section... but that's unlikely to be critical.I think, the patch I sent before addresses a reported earlier case with
xnintr_edge_shirq_handler().. but your approach does make code shorter (and likely simpler), right? I don't see any problems it would possibly cause (maybe I'm missing smth yet :)Quoted 7 lines
I must confess I didn't get your idea immediately. Later on (cough, after hacking my own patch, cough) I had a closer look, and it first appeared fairly nice, despite the additional "ifs". But then I realised that "end ==
old_end" may produce false positives in case we have several times the same (and only the same) IRQ in a row.
So, I'm afraid
we have to live with only one candidate. :->It's not clear, can you elaborate your (non-working) scenario in more details? :-)
Note: I sent the second patch with the following correction :
...
} else if (code == XN_ISR_NONE && end == NULL) { end = intr; + old_end = NULL; }...
I don't see why this idea can't work (even if I made yet another error). Under some circumstances the following code will be triggered to end a loop even when 'end' is still valid
Quoted 8 lines
if (end && old_end == end) intr = NULL;_but_ it'd be exactly a case when "intr == end" and hence, the loop would be finished anyway by the "while (intr && intr != end)" condition.. So sometimes it acts as yet _another_ check to exit the loop, IOW "while (intr && intr != end)" may be converted to just "while (intr)".
Yeah, looks like you are right again, should work as well.
Unfortunately, that whole thing make me meditate about the whole issue again. And now I wonder why we make such a fuss about locking for shared IRQs (where it should be correct with any of the new patches) while we do not care about the non-shared, standard scenario. I currently find no reason why we shouldn't race when some non-shared IRQ pops up on one CPU and deregistration takes place on another. Also in this case, the xnintr object must remain valid for the whole handler execution time. Do we need
struct xnintr_irq {
xnintr_t *handler;
<whatever-lock>;
} xnirqs[RTHAL_NR_IRQS];unconditionally? Or should we better move the whole locking thing into i-pipe somehow? Argh.
Well, and I wonder what this xnarch_memory_barrier() at each handler entry is for. Seems to be there for ages, don't see why right now. (The kernel has a golden rule for this: no barrier without comments!)
Sigh, the never ending IRQ story...
Jan
Quoted 6 lines · Jan Kiszka
[ ... ]
Unfortunately, that whole thing make me meditate about the whole issue again. And now I wonder why we make such a fuss about locking for shared IRQs (where it should be correct with any of the new patches) while we do not care about the non-shared, standard scenario.
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) :-/
Quoted 1 line
Sigh, the never ending IRQ story...
should be reviewed.
Quoted 3 lines
Jan
Signature · 2 lines
Best regards, Dmitry Adamushko
Quoted 10 lines · Dmitry Adamushko
Quoted 6 lines · Jan Kiszka
[ ... ]
Unfortunately, that whole thing make me meditate about the whole issue again. And now I wonder why we make such a fuss about locking for shared IRQs (where it should be correct with any of the new patches) while we do not care about the non-shared, standard scenario.
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. We all went through this code several times. It's a sign that the design might be too complex now, and I feel like having some share in this.
Quoted 5 lines
Quoted 2 lines
Sigh, the never ending IRQ story...
should be reviewed.
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...
Jan
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
[ .. ]
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".
Quoted 2 lines
It's a sign that the design might be
too complex now
frankly speaking, I don't think it's really complex :)
Quoted 9 lines
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 afterxnintr_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), thussynchronize_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.
Quoted 3 lines
Jan
Signature · 2 lines
Best regards, Dmitry Adamushko
Quoted 27 lines · Dmitry Adamushko
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
[ .. ]
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".
Quoted 2 lines
It's a sign that the design might be
too complex nowfrankly speaking, I don't think it's really complex :)
Quoted 9 lines
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 afterxnintr_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), thussynchronize_irq()would not just wait on some simple handler to exit...
Quoted 3 lines
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...
Quoted 24 lines · Jan Kiszka
Quoted 23 lines · Dmitry Adamushko
Quoted 4 lines · Jan Kiszka
Quoted 3 lines
[ .. ]
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".
Quoted 2 lines
It's a sign that the design might be
too complex nowfrankly speaking, I don't think it's really complex :)
Quoted 9 lines
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 afterxnintr_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), thussynchronize_irq()would not just wait on some simple handler to exit...
Quoted 9 lines
Quoted 3 lines
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
ksrc/nucleus/intr.c +70 -36
@@ -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_dxnarch_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_dstatic 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(unsignedxnltt_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(unsignexnsched_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(unxnsched_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(unstatic 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(xninstatic 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, chxnlock_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 ;
Quoted 19 lines · Jan Kiszka
[ ... ]
Only compile-tested under various .configs. Any comment welcome.
ksrc/nucleus/intr.c +2
-1@@ -76,7 +102,7 @@ static inline void xnintr_stat_counter_dstatic 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(unsignedxnltt_log_event (xeno_ev_ienter, irq); ++sched->inesting; +
ksrc/nucleus/intr.c static void xnintr_irq_handler(unsigned · line 125
Quoted 10 lines
ksrc/nucleus/intr.c +9
-0+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);
I guess, 'intr' can be NULL here.
Could you please send me attached (non-inlined) a combo patch on top of the trunk version (as I see this one seems to be on top of your previous one)? I'll try to come up with some solution during this weekend.
Signature · 2 lines
Best regards, Dmitry Adamushko
Quoted 18 lines · Dmitry Adamushko
Quoted 17 lines · Jan Kiszka
[ ... ]
Only compile-tested under various .configs. Any comment welcome.
ksrc/nucleus/intr.c +1
-1@@ -76,7 +102,7 @@ static inline void xnintr_stat_counter_dstatic 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(unsignedxnltt_log_event (xeno_ev_ienter, irq);
Quoted 15 lines
ksrc/nucleus/intr.c static void xnintr_irq_handler(unsigned · line 125
Quoted 13 lines
ksrc/nucleus/intr.c +5
-0++sched->inesting; + +xnlock_get (&xnirqs[irq].lock); + +#ifdef CONFIG_SMP +/* In SMP case, we have to reload the cookie under the per-IRQ lock
ksrc/nucleus/intr.c +5
-0+to avoid racing with xnintr_detach. */ + intr =rthal_irq_cookie (&rthal_domain, irq); +#else + intr = cookie; +#endif s = intr->isr (intr);I guess, 'intr' can be NULL here.
Yeah, needs to be caught as well.
Quoted 5 lines
Could you please send me attached (non-inlined) a combo patch on top of the trunk version (as I see this one seems to be on top of your previous one)? I'll try to come up with some solution during this weekend.
My patch was an attachment (though I wonder we everyone has so much problems with inlines - broken mailers all over the place), and it was already against trunk (#2654). Philippe merged my preliminary fix this morning.
Looking forward to your suggestions!
Jan
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 3 lines · Jan Kiszka
Quoted 2 lines · Jan Kiszka
Well, and I wonder what this
xnarch_memory_barrier()at each handler entry is for. Seems to be there for ages, don't see why right now.
AFAICT, this probably dates back to Xenomai 1.x, when we used to have a threaded interrupt model. The actual code looked like as follows, and the barrier was likely here to make sure that any change to the interrupt hit counter was visible from any other CPU which would run the interrupt service thread. The funny thing is that we did not have SMP support at that time, anyway...
static void xnintr_irq_handler (unsigned irq, void *cookie)
{
xnintr_t *intr = (xnintr_t *)cookie;
int s = XN_ISR_SCHED_T;
intr->hits++;
xnarch_memory_barrier();In short, I don't see any reason to keep this membar.
Quoted 2 lines
(The
Quoted 1 line
kernel has a golden rule for this: no barrier without comments!)
Yeah, right. It looks like the kernel has a slew of very official golden rules it basically does not care one dime to enforce in practice. Looking at the code, commenting membars is surely one of them...
Signature · 1 line
Philippe.
Quoted 23 lines · Philippe Gerum
Quoted 3 lines · Jan Kiszka
Quoted 2 lines · Jan Kiszka
Well, and I wonder what this
xnarch_memory_barrier()at each handler entry is for. Seems to be there for ages, don't see why right now.AFAICT, this probably dates back to Xenomai 1.x, when we used to have a threaded interrupt model. The actual code looked like as follows, and the barrier was likely here to make sure that any change to the interrupt hit counter was visible from any other CPU which would run the interrupt service thread. The funny thing is that we did not have SMP support at that time, anyway...
static void
xnintr_irq_handler(unsigned irq, void *cookie){ xnintr_t *intr = (xnintr_t *)cookie; int s = XN_ISR_SCHED_T; intr->hits++; xnarch_memory_barrier();
Quoted 1 line
In short, I don't see any reason to keep this membar.
Fascinating: So many people came along this place, but no one dared to touch it. :)
Quoted 8 lines
Quoted 3 lines
(The
Quoted 1 line
kernel has a golden rule for this: no barrier without comments!)
Yeah, right. It looks like the kernel has a slew of very official golden rules it basically does not care one dime to enforce in practice. Looking at the code, commenting membars is surely one of them...
I saw Andrew Morton being strictly after uncommented ones in new code at least.
Jan