A computer program or routine is described as reentrant if it can be safely called again before its previous invocation has been completed (i.e it can be safely executed concurrently). Reentrant function is one that can be interrupted (typically during thread context-switching), and re-entered by another thread without any ill-effect. To be reentrant, a computer program or routine:

  1. Must not use global and static data. Though there are no restrictions, but it is generally not advised because the interrupt may change certain global values and resuming the course of action of the reentrant function with the new data may give undesired results.
  2. Must work only on the data provided to it by the caller.
  3. Must not rely on locks to singleton resources.
  4. Must not modify its own code (unless executing in its own unique thread storage). This is important because the course of action of the function should remain the same throughout the code.
    // Self-modifying code is code that alters its own instructions while it is executing, 
    // usually to reduce the instruction path length and improve performance or simply to 
    // reduce otherwise repetitively similar code, thus simplifying maintenance.
    // Self modifying code example
    #include <windows.h>
     
    __declspec(noinline) void hello()
    {
        volatile int flag = 0;
     
        if (flag) {
            printf("shouldn't print\n");
        }
        else {
            printf("should print\n");
        }
    }
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        // Get address of code, as byte (char) pointer.
        char * fn = &hello;
     
        // Change protection.
        DWORD ignore;
        VirtualProtect(fn, 128, PAGE_EXECUTE_READWRITE, &ignore);
     
        // Find JZ instruction.
        while (*fn != 0x74) {
            fn++;
        }
     
        // Replace by NOP.
        fn[0] = fn[1] = 0x90;
     
        // Call.
        hello();
     
        return 0;
    }
    
    // Output
    shouldn't print
  5. Must not call non-reentrant computer programs or routines.

One typical situation is with interrupts, where you may be in the middle of a function when an interrupt occurs, then the interrupt service routine calls that function as part of its workload.

A recursive function calls itself, clearly it must be reentrant to avoid trashing its variables. So all recursive functions must be reentrant, but not all reentrant functions are recursive.


Thread safety and Reentrant functions

Reentrancy is distinct from, but closely related to, thread-safety. A function can be thread-safe and still not reentrant. For example, a function could be wrapped all around with a mutex (which avoids problems in multithreading environments), but if that function is used in an interrupt service routine, it could starve waiting for the first execution to release the mutex.