A function is referred to as reentrant if it can be safely (and without side effects) invoked in the middle of its execution.
Some single-threaded applications can work with non-reentrant functions. Because most applications don’t handle signals or have recursive, callback functions at all. It would be challenging to debug the code if you load it to Linux Kernel as a module or in an embedded system.
In this code, the calculate
function is a non-reentrant function. Because the calculate
function can be invoked immediately after the calculation is done (line number 7) and sets the value of thesum
variable. It doesn't appear to be possible in this code, though. So, even with the non-reentrant function, this code is still viable.
Let’s run it:
Let’s handle a Linux Signal, SIGINT in the code:
Every time SIGINT (Ctrl + C) is sent to this code, the signal_handler
function will be invoked. Notice that the signal_handler
function creates a variable called sum_internal
Let’s run it:
It seems to be working fine.
I will modify the signal_handler
function. The signal_handler
function modifies the global variable sum
:
Let’s test it:
Since the sum
variable is global, when the SIGINT signal is sent, the signal_handler
function modifies it. We represent I/O intensive function call in the calculate
function.
First, the calculate
function is called by the main
function (3 + 5). By the way, I sent a SIGINT signal to the program. The global sum
variable has been changed. Therefore, we see the following line for a moment:
Result from main: 110
The problem is that the calculate
function is a non-reentrant function. We can fix the code like this:
It seems okay:
Sometimes, it is not possible to modify the reentrant functions. Because they are a part of glibc or a part of a third-party library. You may want to block the signal while executing the reentrant function and unblock the signal when you are done with the reentrant function:
Let’s run it:
We managed to fix the problem as it was a simple code. Imagine the compiler warns you when you try to modify a global variable.
Let’s try to write the same non-reentrant code in Rust:
Rust will force you to use global variables in the unsafe
block. You can understand that something is suspicious here.
Why are malloc() and printf() non-reentrant functions?
https://stackoverflow.com/questions/3941271/why-are-malloc-and-printf-said-as-non-reentrant
Which functions can I use safely?
https://manpages.ubuntu.com/manpages/bionic/man7/signal-safety.7.html
P.S.: strtok
used to be a non-reentrant function. Therefore, strtok_r
was added to glibc. However, as of this commit, strtok is a wrapper for strtok_r