I'd do 2 things to check your code. Thorough group code-review (with the goal of finding reentrance mistakes only, not style or other errors). Secondly, a practical attack on problems.
For example:
int myfunction(int x, int y) {
REENTRANCE_CHECK;
... body of function
}
Now you can #define REENTRANCE_CHECK to be either be empty (for production) or some code that checks the function is never re-entered. Run your tests (if you don't have tests, then run it on your device with the debugger attached) with these checks enabled, and see if anything drops off.
Similarly, you can add debug logic to detect incorrect updates to global state. Write code that uses locks (which assert if they're acquired when already held.
Something like this:
int my_global;
DEFINE_GLOBAL_LOCK(my_global);
void my_dangerous_function() {
...
LOCK_GLOBAL(my_global);
.. some critical section of code that uses my_global.
UNLOCK_GLOBAL(my_global);
...
}
Again, DECLARE_GLOBAL_LOCK, LOCK_GLOBAL and UNLOCK_GLOBAL can be either #defined to be real locking code (which of course you'll have to write) for testing, and for production they can be #defined to nothing.
This approach only works if you find and wrap all accesses to your global state, but that's easy with a search.