I don't think your implementation of call_pending_DSRs_inner() is
save. You cannot reset the dsr_list and dsr_list_tail entries before
running the dsr routines, because the irqs are activated while the
dsr
routines run, so another irq with a dsr could happend. This will
result in a change of the dsr order and also dsr could be missed
because the irq->next pointer is changed. The dsr_list and
dsr_list_tail pointer must be current while the dsrs are running.
I believe you are wrong here.
Under interrupts disabled I take the entire current list of DSRs out
of
sight of post_dsr() routine (except it can modify 'dsr_count' of an
ISR
in the list), so if post_dsr() is called while I handle current
DSRs, it
will add DSR to a fresh list that will later be handled at top
level (in
the unlock_inner()).
No, i think you're wrong. You save the pointer to the first dsr, but
not the list. The irq structures are the elements and the next pointer
can be modified.
Example:
You have 3 dsr's pending on the call_pending_DSRs_inner() call (let's
call the dsr a,b and c). You save a pointer to dsr a for you dsr
calling loop. The dsr routine will of dsr a will be called and before
it returns another irq happened. This is the irq for dsr b. The
dsr_list will be set to dsr b and and next pointer of dsr b will be
set to 0 because the dsr_list_tail pointer was 0.
No. If DSR "b" is already in the list I'm handling, its 'dsr_count'
field is non-zero. Should ISR "b" fire, the post_dsr() will simply
increment the "b->dsr_count". It won't change "b->next_dsr".
But the IRQ doesn't know the dsr b is already on the list because you
cleared the dsr_list and dsr_list_tail pointers.
It does know because "dsr_count" is non-zero. It doesn't care about
pointers if "dsr_count" is non-zero on entry.
Please look at the post_dsr() -- it only checks for "dsr_count" to be
non-zero, it begins with:
if( dsr_count++ == 0 )
{
and does nothing else when the 'if' is not taken. Where do you see the
dsr_list and dsr_list_tail are checked?!