In your notion about the meaning of Reentrant interrupt, you write:
interrupt A can preempt handling of interrupt A; interrupt A's handler can be active concurrently with itself
I. The first half of the notion correctly states a condition that might trigger re-entrance of an ISR (interrupt service routine). Note, an ISR that allows re-entrance might or might not be called reentrant: an ISR's code is reentrant if it performs correctly when it is re-entered.
On most processors that use a single stack, code will be reentrant if it has no side effects and does not access variables that are not in its stack frame. It might be reentrant even if it does have side effects or accesses non-local variables, if its actions are idempotent or if some proper concurrency protocol is implemented.
II. The second half of the notion is misleadingly stated: true concurrency does not occur on a single-thread-of-execution processor. However, time sharing and task overlap may occur on such a processor via task switching using either preemptive or cooperative multitasking.
As explained in the next paragraph, to the best of my knowledge preemptive serial multitasking is what would happen if you re-enable the interrupt system within an ISR.
Let's suppose ISR A is written in a reentrant fashion, and that it clears the interrupt A interrupt flag early in its processing, and enables interrupts so more A interrupts can occur and be processed. Also suppose three interrupt A's occur in quick succession (more precisely, quickly enough that processing of one does not complete before another comes along, but not so quickly that the A flag has not been cleared, which would cause loss of an A interrupt) followed by a hiatus. In this case, the first interrupt A occurs; the ISR entry prologue creates a stack frame for the ISR code to use, then saves a number of registers, then begins executing user code, which we suppose turns interrupts back on. After a bit the second interrupt A occurs. ISR entry prologue creates stack frame and saves registers. User code enables interrupts. Third interrupt A occurs. ISR entry prologue creates stack frame and saves registers. User code enables interrupts. As we've posited a hiatus, no more A interrupts occur for a while. So processing of interrupt 3 proceeds and finishes. The ISR epilogue reloads registers, clears the stack frame, and returns from interrupt, restoring the previous interrupt state. Then processing of interrupt 2 proceeds, finishes, reloads registers, returns from interrupt. Then processing of interrupt 1 proceeds, finishes, reloads registers, returns from interrupt. Then
loop() [or whatever is running in the main thread of execution] resumes its work.
As you can see from this example, interrupt processing will occur in a LIFO (last-in, first-out) order if an ISR simply accommodates re-entrance. If that is what you want, fine. If, however, you want interrupt processing to complete in order; want to do lengthy processing while avoiding interrupt misses; and want to process in a secondary thread of execution, ie, a callback-like system, then the thing to do is have the ISR make a queue entry (in a static or heap-based circular queue) each time it starts; return from interrupt if it was re-entered; and process queue entries until the queue is empty, using atomic operations when changing queue pointers.
Edit 2: In §10.20.9.1 of the SAM3x/SAM3A datasheet, “Hardware and software control of interrupts”, we find
A peripheral interrupt becomes pending for one of the following reasons:
• the NVIC detects that the interrupt signal is HIGH and the interrupt is not active
A pending interrupt remains pending until one of the following:
• The processor enters the ISR for the interrupt. This changes the state of the interrupt from pending to active. Then:
• For a level-sensitive interrupt, when the processor returns from the ISR, the NVIC samples the interrupt signal. If the signal is asserted, the state of the interrupt changes to pending, [...] Otherwise, the state of the interrupt changes to inactive.
• If the interrupt signal is not pulsed while the processor is in the ISR, when the processor returns from the ISR the state of the interrupt changes to inactive.
• Software writes to the corresponding interrupt clear-pending register bit.
This suggests that although the ISR for a given interrupt source on a SAM3x/SAM3A system can be interrupted by a higher-priority source, a given source can not re-interrupt until “the processor returns from the ISR”. Without some research or testing, it isn't clear to me if that is correct, and whether software can simulate a return from ISR without actually returning. Setting that possibility aside, here is a workaround to allow interrupt A to recur:
Set the interrupt priority of A fairly high, say level z. Set up several selected SGI's (software generated interrupts) at levels p, q, r ..., all lower-priority than z. Initialize an A level variable to point to the least-priority SGI ISR among those selected. Upon any A interrupt, the A ISR issues an A level SGI, saves any data that SGI ISR needs, updates A level to next-higher-priority SGI [if possible], and returns from interrupt. This re-enables A interrupts and allows the most recently issued (and currently highest priority) SGI to fire and start doing its thing. When it's done, it atomically sets A level equal to its own level. Thus, while any of the SGI ISR's is processing, if another A interrupt occurs, the current SGI ISR's processing suspends; when the A interrupt is handled, the next-higher SGI ISR starts. All higher level ISRs finish before a lower level ISR resumes.