millfork

Millfork: a middle-level programming language targeting 6502- and Z80-based microcomputers and home consoles

This project is maintained by KarolS

< back to index

Reentrancy

A function is called reentrant, when its execution can be interrupted and the function can be then safely called again.

When programming in Millfork, you need to distinguish conceptually three kinds of reentrant functions:

As Millfork is a middle-level language, it leaves taking care of those issues to the programmer.

Nesting safety

Nesting occurs when a function is called when calculating parameters for another call of the same function:

f(f(4))
f(0, f(1,1))
f(g(f(5))
f(g()) // where g calls f, directly or indirectly

Since parameters are passed via global variables, calling a function while preparing parameters for another call to the same function may cause undefined behaviour.

For that reason, a function is considered nesting-safe if it has maximum one parameter.

It is possible to make a safe nested call to a non-nesting safe function, provided two conditions are met:

In all other cases, the nested call may cause undefined behaviour. In such cases, it’s recommended to introduce a temporary variable:

tmp_f11 = f(1,1)
f(0, tmp_f11)

Recursion safety

A function is recursive if it calls itself, either directly or indirectly.

Since most automatic variables will be overwritten by the inner call, the function is recursive-safe if:

In all other cases, the recursive call may cause undefined behaviour.

The easiest, but suboptimal way to make a function recursion-safe is to make all local variables stack-allocated and assign all parameters to variables as soon as possible. This is slow though, so don’t do it unless really necessary.

Example:

word fibonacci(byte i) {
   if i < 2 { return 1 }
   stack byte j
   j = i
   return fibonacci(j-1) + fibonacci(j-2)
}

Interrupt safety

A function is interrupt-safe if it can be safely called, either directly or indirectly, simultaneously by the main code and by an interrupt routine.

The only way to make a function interrupt-safe is:

The size limit on the parameter and the return type depends on architecture:

All built-in functions and operators are designed to be interrupt-safe.

Reentrancy safety violations

Each of the following things is a violation of reentrancy safety rules and will cause undefined behaviour with high probability: