I recently had the fun job of making some complex legacy C code (200,000+ lines) thread safe. Of course there were globals spread through the code so finding them all turned into a massive easter egg hunt. The initial problem was how to track them all down. If you ever have this fun job here are the steps I used.
1. I searched for the word “global”. If the person who wrote the code took care then all the global variables will have been commented as such (ha ha). Maybe surprisingly this did managed to find around 50% of the globals – while not perfect, it was a good start. I also found a few more unlabelled globals by searching for “thread-safe” and “thread” since some of the non-thread safe code was actually commented as being not thread-safe (I wish it all had been).
2. I next opened the .map file (generated by Visual Studio in debug mode) and looked for any “common” class variables (these are found down towards the bottom of the .map file). This process managed to shake out another 40% of the globals.
3. The last 5% of globals I found by doing a manual search through the entire code base for the “static” keyword. I of course then had to then trawl through several thousand static function declarations, but the last of the globals were in here too.
The most interesting thing about this painful exercise is how often people use globals when they are not really needed. 90% of the globals were being used only two or three times and were able to be made thread safe with very little code change. Of course the last 10% were used in more than 100 locations spread throughout the entire code base so the whole thread safe conversion exercise was not easy.
To keep the required code change to a minimum (I am very reluctant to make major structural changes to complex code even if I have written it) I solved the problem by just packaging up the difficult globals into a thread-safe strut declared in the main entry function and passed the pointer to this strut into each of the functions that were using the globals. While not a trivial job, this approach avoided disturbing code I knew was working well and which would have taken months to re-write.