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
  • The premise is "Recursive functions are permitted".

    Oh dearie me, no it isn't. I have never disputed that, only pointed out that it is irrelevant.

    Here's your post again - take note of the premise at the beginning from which you go on to derive your conclusions:

    No, Mr. Sprat. For the compiler, the possibility of recursion implies reentrancy. It's as simple as that. Hence, standard-compliant C compilers must produce reentrant functions by default.

    It's basic logic, really: (recursive function calls allowed) -> (functions must be reentrant). Since you like using your brain, this should be very obvious to you.

    Seems pretty clear to me.

    Nebulous assertions don't make any argument at all, Mr. Sprat.

    No, they don't, do they?

Reply
  • The premise is "Recursive functions are permitted".

    Oh dearie me, no it isn't. I have never disputed that, only pointed out that it is irrelevant.

    Here's your post again - take note of the premise at the beginning from which you go on to derive your conclusions:

    No, Mr. Sprat. For the compiler, the possibility of recursion implies reentrancy. It's as simple as that. Hence, standard-compliant C compilers must produce reentrant functions by default.

    It's basic logic, really: (recursive function calls allowed) -> (functions must be reentrant). Since you like using your brain, this should be very obvious to you.

    Seems pretty clear to me.

    Nebulous assertions don't make any argument at all, Mr. Sprat.

    No, they don't, do they?

Children
  • Seems pretty clear to me.

    You mean the part about the compiler being compliant to the C standard? If the compiler doesn't comply to the C standard, then the points in which it deviates from it must be mentioned in the manual (e.g. C51 and its "reentrant" keyword). Deviations from the standard that aren't mentioned in the manual are bugs in the compiler.

    Oh ... and wasn't it you who claimed that Cpt. Vince was missing basic computer science knowledge, since he was looking for information about reentrancy in the compilers manual and couldn't find it? If there's nothing mentioned in the manual, then the standard applies. And the standard requires the compiler to create reentrant functions.

  • Many Thanks to Captain and Per for the detailed explaination.

  • You mean the part about the compiler being compliant to the C standard?

    No, I made it quite plain that I was referring to the premise at the beginning of you post, which was:

    the possibility of recursion implies reentrancy.

    This is incorrect as are the things you go on to conclude from this statement.

    Oh ... and wasn't it you who claimed that Cpt. Vince was missing basic computer science knowledge, since he was looking for information about reentrancy in the compilers manual and couldn't find it?

    Yes, and my point was that reentrancy is a concept rather than something which must exist as a compile time option.

    If there's nothing mentioned in the manual, then the standard applies.

    Yes.

    And the standard requires the compiler to create reentrant functions.

    No.


  • Yes, and my point was that reentrancy is a concept rather than something which must exist as a compile time option.

    Oh, and now that I have learned this 'basic computer science knowledge' from the Fish-Head, you can see how difficult it is to ensure that a "rule-book" is clear enough so that someone of Jack's caliber doesn't screw up a project.

    Malice Factor: > 0

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

  • This is incorrect as are the things you go on to conclude from this statement.

    Recursive calls imply concurrent execution of the function in question. Concurrent execution is a synonym for reentering a function. Whether or not the concurrent execution is done from separate threads or from the same thread is irrelevant.

    Yes, and my point was that reentrancy is a concept rather than something which must exist as a compile time option.

    Mr Sprat, I see you've wholeheartedly failed to read and understand my postings. I think I've made it abundantly clear the the compiler trying to create reentrant functions is a necessary, but not sufficient condition for any particular function to be reentrant (that's also basic logic, you should know what those terms mean).

    Hence, it is impossible to create a (meaningful) recursive function with a compiler that does not consider functions reentrant (such as C51).

    I really don't think I need to, since you can undoubtedly read, but if you consider it necessary I'll show you the appropriate passages from my earlier postings.

    No.

    Yes. It is not possible to broadly allow recursive functions (as the C standard does) without the compiler considering all functions reentrant by default and making the appropriate provisions.

    We're getting close to the point here where I'll start considering more nebulous, unproven statements from you as a concession.

  • "This is incorrect"

    Is it?

    Go on then, you explain how the possibility of recursion can be supported without reentrancy?

  • Reentrant as in allowing recursion is the "little" definition, and is trivial to manage. This is normally _not_ the definition that is used for a reentrant function. No computer professional should ever think of reentrant functions as just supporting recursion.

    Reentrant as in supporting concurrent calls is a major pita. This is also "the" definition of a reentrant function.

    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). In a concurrent world, you would need to disable interrupts or similar to manage your trivial little read/modify/write, unless you have a processor that has a lock primitive that that delay interrupts for a programmable number of instruction cycles.

    The language standard promises support for recursion.

    The language standard does not promise support for concurrent calls, even for code you have written. For a compiler vendor like Keil, who also pushes an RTOS, it is reasonable that they do their best to make the code reentrant. 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:

    unisgned long long fac(unsigned long long n) {
        if (n <= 1)
            return 1;
        else
            return n * fac(n-1);
    }
    


    Yes, I know that the factorial is the standard school example of recursion, and also the worst possible example since it is so trivial to make iteratively. However, with a non-reentrant multiplication operation, the above would be non-reentrant code if changed to a loop too.

  • 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.

  • "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?)