1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-27 19:30:04 +00:00
millfork/doc/lang/reentrancy.md

70 lines
2.6 KiB
Markdown
Raw Normal View History

2018-01-04 00:15:04 +00:00
# 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:
* nesting-safe
* recursion-safe
* interrupt-safe
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:
* the function cannot modify its parameters
* the non-nested parameters have to have the same values in all co-occuring calls: `f(5, f(5, 6, 7), 7)`
In all other cases, the nested call may cause undefined behaviour.
## 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:
* parameters are no longer read after the recursive call is made
* an automatic variable is not read from without reinitialization after each recursive call
* all the other variables are stack variables
In all other cases, the recursive call may cause undefined behaviour.
The easiest, but unoptimal way to make a function recursion-safe is to make all local variables stack-allocated
and assigning all parameters to variables as soon as possible. This is slow though, so don't do it unless really necessary.
## 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 to have no parameters and make all local variables stack-allocated.
# Reentrancy safety violations
Each of the following things is a violation of reentrancy safety rules and will cause undefined behaviour with high probability:
* calling a non-nesting-safe function without extra precautions as above while preparing another call to that function
* calling a non-recursion-safe function from within itself recursively
* calling a non-interrupt-safe function from both the main code and an interrupt