Difference between revisions of "reentrant"

From SEGGER Wiki
Jump to: navigation, search
m
m
Line 11: Line 11:
 
Calling conventions of most modern processors store parameters in registers and on the stack, which is basically required for a routine to be reentrant.
 
Calling conventions of most modern processors store parameters in registers and on the stack, which is basically required for a routine to be reentrant.
 
Some compilers for older architectures (especially for 8-bit architectures such as [[8051]] and [[6502]]) do not produce reentrant code and use a static overlay scheme instead.
 
Some compilers for older architectures (especially for 8-bit architectures such as [[8051]] and [[6502]]) do not produce reentrant code and use a static overlay scheme instead.
  +
  +
===Bad example===
  +
The example below is a bad example, as it uses static variable data. If the code executes multiple times, both instances use the same table. Unfortunately, if the Polynomial parameter for the 2 instances is different, they require different tables. One or both invocations will produce an incorrect result.
  +
<syntaxhighlight lang="c">
  +
unsigned CalcCRC(unsigned crc, const unsigned char* pData, unsigned NumBytes, unsigned Polynomial) {
  +
static unsigned _Poly;
  +
static unsigned _aCRC[256];
  +
  +
//
  +
// Build CRC table if it has not already been built for this polynomial
  +
//
  +
if (Polynomial != _Poly) {
  +
_Poly = Polynomial;
  +
// ... More code to compute the static table. Code can be in subroutine.
  +
}
  +
while (NumBytes--) {
  +
// Use table to compute the actual crc
  +
}
  +
return crc;
  +
}
  +
</syntaxhighlight>

Revision as of 22:25, 5 June 2019

A subroutine is called reentrant if can be safely be called again ("re-entered") before the previous invocation has completed execution. This can happen in different ways:

Typically, this means that the routine does not use any static variables. Routines which use only parameters and local variables are reentrant. Note that re-entrancy is not the same as recursive calling. If a function is recursive, it calls itself, either directly (FuncA calls FuncA) or indirectly (FuncA calls FuncB calls FuncA).

Calling conventions of most modern processors store parameters in registers and on the stack, which is basically required for a routine to be reentrant. Some compilers for older architectures (especially for 8-bit architectures such as 8051 and 6502) do not produce reentrant code and use a static overlay scheme instead.

Bad example

The example below is a bad example, as it uses static variable data. If the code executes multiple times, both instances use the same table. Unfortunately, if the Polynomial parameter for the 2 instances is different, they require different tables. One or both invocations will produce an incorrect result.

unsigned CalcCRC(unsigned crc, const unsigned char* pData, unsigned NumBytes, unsigned Polynomial) {
  static unsigned _Poly;
  static unsigned _aCRC[256];

  //
  // Build CRC table if it has not already been built for this polynomial
  //
  if (Polynomial != _Poly) {
    _Poly = Polynomial;
    // ... More code to compute the static table. Code can be in subroutine.
  }
  while (NumBytes--) {
    // Use table to compute the actual crc
  }
  return crc;  
}