views:

96

answers:

3

I'm writing a tracing library that is available as a DLL. It is consumed by basically every component in my system. One tricky requirement is that the tracing functions need to be invoked very early in the process lifetime, even before main() runs.

Consumers of this library include executables, statically linked DLLs, delay-loaded DLLs and dynamically loaded DLLs. All the variations.

Some tracing features do no play well with static initialization but others are fine. Ideally, I'd like to be able to offer consumers minimal safe functionality during init time and then full functionality after init is complete.

Asking consumers to make an explicit "I'm done init" call themselves doesn't work because of the fact that certain consumers are DLLs themselves and have no control over the executable hosting them. The same problem just moves one level up the chain.

What I'm hoping is that there is some way for me to ask the runtime whether or I'm currently running in static initialization or whether that stage is complete. Is such a thing possible?

To complicate matters further, I need to run on 5 platforms. I don't need a write-once solution but I do need to get it working somehow on all platforms.

+1  A: 

Global variable? Something like:

bool initTime = true;

in your DLL and then

int main()
{
  initTime = false;
  // your main code comes here
}

in your executable.

Tomek
that only works for one source file. if you're using it in a header, the initTime variable *itself* becomes part of the global initialization, and i'm not entirely sure you can force the compiler to initialize that variable first... which would make this not entirely reliable..
ianmac45
@ianmac45: No. As initTime is builtin type it is properly initialized by loader (it will have correct value BEFORE any static non-builtin types are initialized). But the fact that we are talking DLL here complicates things and it is very likely to be platform dependent. I would expect (no guarantees here) it to work on Linux but for Windows I have doubts as they seem to share DLL's data between applications.
Tomek
Unfortunately, I don't have control over the executable so nothing can be added to main().
Scott Cameron
A: 

You write that

Some tracing features do no play well with static initialization but others are fine.

However, most of the time the problem lies not in the static initialization phase of the executable (the process), but in the static initialization phase of the/a DLL. You must be aware that every DLL has it's own static initialization phase for it's static C++ object. Specifically your tracing DLL has too, and so has any other DLL that might use your DLL.

To sum up: Probably you do not care if the static initialization phase of the executable has finished but you do care if a) your own DLL has finished initializing and b) if while calling into your DLL the Loader Lock is currently held.

As to a) If your DLL is finished initializing is only a problem inside your code as noone can call into your DLL before it's initialized.

As to b) It does seem that there is no (portable, documented) way to determine from code if the loader lock is currently being held. I do not know any other way than to clearly document which functions must not be called while the Loader Lock is being held.

Martin
A: 

You may have to rewrite (well, modify) and then link with your rewritten crt0.o. That's obviously going to have to be different for each platform.

mpez0
That would also require control over the executable code, which I unfortunately don't have. The solution (if it were to exist) would need to be something contained within my DLL (or at least within the relationship between my DLL and the runtime system).
Scott Cameron
Here's another possibility: move your existing main() to, say, real_start(). Write a main() that does your initialization then calls real_start(argc, argv, envp). Depending on exactly what you're looking to initialize, that may work for you.
mpez0