This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

re-entrant code

what is a re-entrant code?
again what is re-entrant kernel?

thank you
ece tech

Parents
  • Per wrote:

    You don't test for reentrancy. You specifically develop with that in mind. Reentrancy is a factor of what resources the function makes use of, and how it uses them.

    That's unfortunately what I'm thinking too; and that's a scary fact. I have the feeling that automatic test code that would test for reentrancy would be more difficult to write than the tested code itself.

    Therefore, is it safe to say that, a few high-level ways to prove that code is reentrant are:

    - by doing a code review

    - by having the code generated automatically by a tool that is proven to produce reentrant code

    - ... anything else?

    And then, we could say that the code review would check, amongst other things:

    - code does not call non-reentrant code

    - inspected code must be assembly. When inspecting C, one must mentally process every line and imagine what the assembly code would be in the end.

    - keeping in mind that in C, some casts, floating point calculations, etc. will in turn call a function in a library, which itself must have been designed for reentrancy. In C++, add to this the army of operators like new delete etc.

    - none of the variables that are changed by the reentrant code, can have a fixed address in RAM. That means no "static" variables in C

    - there will inevitably be a few lines of code that simply cannot be made reentrant, in which case additional protection mechanism must be used to make sure that it will not be re-entered. Like disabling interrupts, to the cost of increasing interrupt latency.

    - self modifying code is not reentrant

    - ... ok: what else?

    Steph-

Reply
  • Per wrote:

    You don't test for reentrancy. You specifically develop with that in mind. Reentrancy is a factor of what resources the function makes use of, and how it uses them.

    That's unfortunately what I'm thinking too; and that's a scary fact. I have the feeling that automatic test code that would test for reentrancy would be more difficult to write than the tested code itself.

    Therefore, is it safe to say that, a few high-level ways to prove that code is reentrant are:

    - by doing a code review

    - by having the code generated automatically by a tool that is proven to produce reentrant code

    - ... anything else?

    And then, we could say that the code review would check, amongst other things:

    - code does not call non-reentrant code

    - inspected code must be assembly. When inspecting C, one must mentally process every line and imagine what the assembly code would be in the end.

    - keeping in mind that in C, some casts, floating point calculations, etc. will in turn call a function in a library, which itself must have been designed for reentrancy. In C++, add to this the army of operators like new delete etc.

    - none of the variables that are changed by the reentrant code, can have a fixed address in RAM. That means no "static" variables in C

    - there will inevitably be a few lines of code that simply cannot be made reentrant, in which case additional protection mechanism must be used to make sure that it will not be re-entered. Like disabling interrupts, to the cost of increasing interrupt latency.

    - self modifying code is not reentrant

    - ... ok: what else?

    Steph-

Children
  • You are making it too hard! Reentrant functions are not black magic :)

    You can write reentrant code in C. On some architectures, the compiler will directly generate code that is reentrant (this still requires that the developer takes care of accesses to global/static resources). On some architectures, you have to specifically tell the compiler to generate reentrant code. A C51 compiler normally produces non-reentrant code, specifically because of limitations of the C51 architecture.

    You can have a reentrant function read and write to global resources. It is just a question of making sure that the function always gives predictable results even if having two concurrent calls active. For axample: A pseudo-random number generator must have code to atomically read its old seed and update it with a new value, to make sure that two concurrent calls doesn't result in the same random number. malloc()/free() or new/delete must protect internal lists of used/released memory.

    The compiler vendor documentation will tell if floating-point code, and memory allocation functions etc are reentrant or not.

    But as already noted: C51 is not an architecture that likes reentrant functions! You really want the compiler to convert parameters and local variables to reusable global variables because of size and efficiency!

  • You have to realize that when talking about global variables, the problem is more about architecture than the used code-generating tool.

    Most architectures can read an 8-bit variable atomically. But can they read a 16-bit, 32-bit or 64-bit variable atomically?

    Some architectures can increment a memory variable atomically, while other architectures may need a load + increment + store. If the variable is too large to increment directly, then the code-generating tool (any tool - or yourself, using assembler) will have to care about overflow rippling to the upper parts of the variable - for example by adding extra add-with-carry steps.

  • To make Per happy:
    This relates to the '51
    Since the OP started the thread with C51 I have changed MCU back to the C51 to stay with the OPs intent.

    I have never used reentrant code. Yes, I have had cases where it might have been desirable (e.g. a function shared by an ISR and main) but the potential debugging nightmare has kept me from using reentrant code.

    I think the OPs worry that he 'might' have reentranr code is greatly overblown. Just make sure that all functions called from ISRs (if you absolutely have to have them) have names that are e.g. ISR..... and no ISR.... function is called from main.

    Erik

    PS the one '51 case I can see for reentrant code would be to 'core use squeeze' a unit that was to be made in millions.

  • Hello,

    You are making it too hard! Reentrant functions are not black magic :)

    All I'm trying to say is that the design of a reentrant function requires extra attention, i.e. extra time and money, because reentrancy problems are usually very hard to troubleshoot, so it's best to get it right the first time. Hence my feeble attempt to draw a checklist to test for reentrancy (using elbow grease, since there is no software to do that for me).

    Agreed that there is no black magic wizardry involved there. I couldn't find any entry on reentrancy in my book of shadows. That said, it's a rather old edition...

  • But the question here is: why do you need reentrancy?

    If you write a thread-safe c library, where the functions should be called from multiple threads, then you need it. And you also need it if you want to call the same function from both an interrupt service routine and a main application.

    You need a little bit simpler form of reentrant-safe if the function is part of a recursive chain - in that case you don't have to worry about atomicity of instructions.

    The C51 architecture isn't the worlds most powerful, so a lot of applications are implemented without an RTOS. Just a super-loop and a number of ISR. An ISR should be as fast as possible, so normally don't call any functions.

    In the end, there isn't too much need for reentrant functions on the C51 architecture.

  • Hello Per,

    Sometimes, reentrancy is needed. Sometimes, it is not. Sometimes, as in the case of the C51 MCU, it makes sense, from an architectural point of view, to ban anything that uses reentrancy, I agree with all that.

    Now: let's say I need to use reentrancy. There are several flavors of it: ISR-safe, thread-safe, recursion-safe, let's say I need something that is thread-safe. Say I'm using RTX51.

    Reentrancy cannot be tested. Wicca does not work either. So I will have to be careful about what I write.

    This begs the question: is there a finite checklist that I can check my code against, to ensure it is reentrant (thread-safe)?

    Steph-

  • Now: let's say I need to use reentrancy. There are several flavors of it: ISR-safe, thread-safe, recursion-safe, let's say I need something that is thread-safe. Say I'm using RTX51.
    While the '51, since it is programmable, is capable of operating with a RTOS the jumping through hoops the '51 architecture requires makes the '51 (with the exception of some PIGs, I guess) the worst possible choice for an application that requires a RTOS. When you then add reentrancy which, again, does not fit the '51 architecture you get problms piled on top of problems.

    This begs the question: is there a finite checklist that I can check my code against, to ensure it is reentrant (thread-safe)?
    yes, 1) check that no RTOS is involved and 2) do not call functions from ISRs.

    you can, since the '51 is programmable, of course use both a RTOS and reentrant functions, but with all the concern you seems to have about "ensuring" I would strongly advise aganst it.

    Erik