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

Reentrant?

I rarely ask questions on this forum, but since I couldn't [easily] find it in the help-files, or on-line, I'm asking you guys.

I usually (like never) don't use the 'reentrant' pragma, but I think I may have to do that with a particular routine.

BUT I can't find the key-word that declares a function as reentrant. Am I missing something? Is there one for Keil's IDE tools? If so, what is its form? Can I get a link to the 'official' use of it?

Thanks in advance, and I need it asap because I need to pass this class and I don't want to really learn how to do this 'embedded' stuff anyway but the teacher keeps hounding me.

--Cpt. Vince Foster
2nd Cannon Place
Fort Marcy Park, VA

Parents
  • Think about a trivial read/modify/write operation. No problem in a recursive function, since the function source code decides the points where it may recurse. Both the developer and the compiler can see where recursion is possible (if we ignore C++ with operator overloading).

    No, the compiler cannot see it if indirect recursion and/or recursive calls through function pointers are allowed. (Remember what a PITA function pointers are in C51?)

    Also, since the C standard doesn't say anything about read/modify/write operations, it's up to the programmer to make these work correctly.

    But as I mentioned in an earlier post, even hidden helper functions such as performing long long multiplications can be non-reentrant, in which case this little trivial function will be non-reentrant, i.e. not concurrently callable from multiple threads:

    The standard doesn't promise helper functions to be reentrant, I think. And calling a non-reentrant function makes the function from which the call originates also nonreentrant.

Reply
  • Think about a trivial read/modify/write operation. No problem in a recursive function, since the function source code decides the points where it may recurse. Both the developer and the compiler can see where recursion is possible (if we ignore C++ with operator overloading).

    No, the compiler cannot see it if indirect recursion and/or recursive calls through function pointers are allowed. (Remember what a PITA function pointers are in C51?)

    Also, since the C standard doesn't say anything about read/modify/write operations, it's up to the programmer to make these work correctly.

    But as I mentioned in an earlier post, even hidden helper functions such as performing long long multiplications can be non-reentrant, in which case this little trivial function will be non-reentrant, i.e. not concurrently callable from multiple threads:

    The standard doesn't promise helper functions to be reentrant, I think. And calling a non-reentrant function makes the function from which the call originates also nonreentrant.

Children
  • "No, the compiler cannot see it if indirect recursion and/or recursive calls through function pointers are allowed. (Remember what a PITA function pointers are in C51?)"

    You missed the point. The compiler can see the possible points where the function may call another function - that is the only positions where you may introduce any recursion. The function must do an explicit hand-over to make recursion possible, and at this/these points, the compiler can guarantee that any helper code has left no unsafe state.

    The thing is that recursion is a controlled operation that happens synchronously at known sequence points.

    "The standard doesn't promise helper functions to be reentrant, I think. And calling a non-reentrant function makes the function from which the call originates also nonreentrant."

    In short - a recursive function may be reentrant, but need not be. Use of non-reentrant helper functions is allowed in a recursive function, and only leads to problems with concurrent threads or main thread and interrupt handler.

    As a developer, I can protect read/modify/update accesses to my variables, but I need to know that the compiler doesn't hide non-reentrant code.

    To get reentrant functions, you must know that the compiler will produce reentrant-safe code.

  • To get reentrant functions, you must know that the compiler will produce reentrant-safe code.

    I think we've digressed a bit from the original question, which was about calling conventions and function calls, not about the properties of whole functions.

    The quote from the standard doesn't say anything about functions themselves being safe for recursion and/or reentrancy (since this depends on machines specifics, libraries, helper functions, etc), only about the compiler having to allow recursive function calls.

    And I suppose one could come up with a calling convention that's safe for recursion, but not reentrancy (e.g. by first making a copy of the registers to a fixed memory location and then copying them to the stack), however, on most architectures such behavior would be inefficient and at the very least borderline malicious.

  • I'm not so sure the original thread intention was about calling conventions and function calls. Cpt Vince did mention reentrancy, and this quickly got transformed into a debate about recursion.

    I think that the biggest digression in this thread has been the claims that recursion implies reentrancy. Recursion relates to a single execution thread, while reentrancy relates to concurrent threads.

    There are compilers that have special flags to turn on support for multithreading. Requiring flags or keywords for supporting recursion on the other hand is something a standards-complient compiler need not do, unless the compiler needs to make big workarounds because of a processor not suited for C.

  • I'm not so sure the original thread intention was about calling conventions and function calls. Cpt Vince did mention reentrancy, and this quickly got transformed into a debate about recursion.

    Well, he was looking for an ARM equivalent to the C51 "reentrant" keyword, which alters the calling convention and allocation of local variables (from one that's efficient on a '51, but does not support recursion or reentrancy, to one that's inefficient, but does).

    ARM compilers don't really need this switch, since there are efficient calling conventions and memory allocation methods that also conform to the requirements of the C standard.

    And, well, I doubt that using the "reentrant" keyword on C51 makes the function in question magically, completely safe for reentering, since e.g. it doesn't do anything about the helper functions you mentioned, nor about atomicity issues. It's just a necessary condition without which any attempt at reentering the function will fail horribly.

  • There are compilers that have special flags to turn on support for multithreading.

    Also, maybe we should avoid the word "reentrant" altogether and use "recursion-safe" and "thread-safe" instead. The "reentrant" keyword of C51 is about the former, since it's still quite possible to shoot oneself in the foot in a multithreaded environment even when using the keyword.

  • Also, maybe we should avoid the word "reentrant" altogether and use "recursion-safe" and "thread-safe" instead.

    I realise you're scrabbling hard for an out on this one, but that takes the biscuit.

    You were wrong - deal with it.

  • You were wrong - deal with it.

    Yet more handwaving, and going from "because Jack sez so" to "because Per sez so"?

    Didn't I use the phrase "to the compiler" often enough?

    (By the way, how's that attempt at convincing C51 that reentrancy is really a general concept and not something that needs to be allowed by the compiler coming along?)