Re-entrancy is/becomes a major headache the more your ISRs are complex. The wikipedia entry has a pretty succinct description of a re-entrant ISR:
A reentrant interrupt handler is an interrupt handler that re-enables interrupts early in the interrupt handler. This may reduce interrupt latency.[6] In general, while programming interrupt service routines, it is recommended to re-enable interrupts as soon as possible in the interrupt handler. This practice helps to avoid losing interrupts.[7]
Assuming you're not writing a general purpose OS where re-entrancy might very well be unavoidable, you have to keep in mind the added complexity of having re-entrancy in your custom bespoke controller code might just not be worth the perceived ease of writing lazy long runninng ISRs.
Here's an example:
- long running, low priority ISR starts doing something, calls a version of
malloc
that you have implemented.
- Mid
malloc
call, you get interrupted by a higher priority thread: it calls malloc
too
- scenario a: high priority ISR exits malloc before low priority
- scenario b: high priority ISR exits malloc after low priority *
Ok, you'll say, I'll put a spin lock on malloc, then all you need to do is repeat the above condition to the spinlock_aquire
primitive you've created: is it re-entrant?
I should point out here that just slapping locks on things and calling it a day is a recipe for priority inversion based deadlocks. It's not that simple.
The poor man's solution to all these problems is to keep your ISRs short. For instance, in the NT kernel, a long time ago (haven't kept up to date), any IRQL above the bottom two most weren't allowed to even look at paged memory. This was because paging was handled by an interrupt...
So choice becomes: implement a basic queuing mechanism and have your ISRs dispatch work units, or make your ISRs behave freely but ensure you have an extremely robust environment that will not choke on weird issues (e.g. priority inversion).
If your task at hand is super simple, like turning on a light in your arduino controlled drone, then by all means go ahead. But if you want to avoid engineering headaches later on as your code gets more complex, you really should avoid the perceived benefit of giving yourself no constraints at all with an ISR.
* clarification: scenario b cannot occur at face value since the higher priority ISR will always execute and complete before the lower priority one. However, the code-path taken by either one can be swapped. So in the malloc
routine itself, if there is any access to a global data structure, that code can be interrupted in any possible combination of ways.
Further to this point, it should be stated that the re-entrancy requirement for any function is for its entire call tree. This becomes very difficult to ensure if you end up using third party libraries.
Also note: to address a comment from @user253751, re-entrancy isn't solved by merely wrapping things in a lock. Rather, re-entrancy has a set of requirements that are well understood. Here are some relatively trivial code examples that illustrate the matter.
It can be seen, by looking at this that writing a re-entant malloc or resource acquisition function becomes very difficult.