There might have been new modules loaded by another thread between the `SymInitialize` and `EnumProcessModules` calls.
Since we register the enumerated modules into the cache, we need to make sure that symbols for this module are loaded.
The only way to do that is to call `SymLoadModuleEx`, just like we do when finding new modules after `InitCallstack`.
DecodeCallstackPtrFast() may be called outside the symbol processing thread,
for example in the crash handler. Using the less-capable dladdr functionality
doesn't have a big impact here. Callstack decoding in this context is used to
remove the uninteresting top part of the callstack, so that the callstack ends
at the crashing function, and not in the crash handler. Even if this
functionality would be impacted by this change, the damage done is close to
none.
The other alternative is to use locking each time a libbacktrace is to be
used, which does not seem to be worthy to do, considering that the problem
only occurs in a very rare code path.
NB everything was working when it was first implemented, because back then the
callstack decoding was still performed on the main thread, and not on a
separate, dedicated one.
Initializing structures for callstack processing (building memory map of the
process, gathering kernel symbols, etc) takes some time, which in some cases
may be significant.
Callstack queries are now handled on a separate thread. In such setup it no
longer makes sense to block main thread execution with this lengthy init
process.
All the heavy initialization phase has been now moved to this separate
processing thread. Some initial callstack queries may now not produce
responses as promptly as before, but this is only because the main thread is
able to start working earlier.
Some parts of the initialization process may be critical to do in the main
thread, for example because the function responsible for gathering callstacks
must be loaded first. This is done still on the main thread, in a new function
InitCallstackCritical().