0

Is there a good way to check for OS version (in this case Windows Vista+ or not) and decide at runtime what version of a function is going to be used.

Concretely I am talking about implementing pthreads in Win32 threads. In my ideal case, the pthreads library would determine at program startup which OS is running. If it is Vista+, all function calls will be redirected to the cool new and fast functions, otherwise, the old emulation layer will be used.

So in effect, the library will have two version of each function, one new and one old. And a one-time runtime check would determine at runtime, before the program enters main so to speak, which version it's going to use. I know there's libraries that detect CPU features like SSE at runtime, and use the relevant functions, but I think they check at each function call. That would be too expensive to do in a low-level threading library IMO.

Is this possible? Can function calls be "relinked"/redirected at runtime so speak?

EDIT: crazy things like custom crt startup code would be possible for this (I'm talking about winpthreads for mingw-w64, which provides its own startup code)

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • 2
    See [this question](http://stackoverflow.com/questions/1963992/check-windows-version) and put the two versions of your library in separate DLLs, then let a third stump DLL (or static library) decide which one to load in its initalization function. – Fred Foo Jun 13 '11 at 16:27
  • @larsmans: OK, is there an analogue for static libraries? – rubenvb Jun 13 '11 at 16:31
  • @ruvenvb: you can check in an initializer function what the OS version is, then construct appropriate dispatch tables for your threading primitives and implement the rest of the library in terms of those. The overhead is similar to the cost of dynamic polymorphism (`virtual`) in C++, but the client will have to call the initializer. – Fred Foo Jun 13 '11 at 16:38
  • Rather than testing Windows version, it's generally better to check for the existence of the required API, for example by calling GetProcAddress to see if a particular function exists. – David Heffernan Jun 13 '11 at 16:40
  • @David: Except for those unfortunate cases where new behavior was added to an existing API. – Ben Voigt Jun 13 '11 at 17:13

1 Answers1

1

The simple answer? Define and build a dispatch table/structure for your library. Something like this:

// Define function pointers and dispatch structure.
typedef void( *PFN_pthread_exit )( void *value_ptr );
typedef struct tag_PTHREAD_IMPL
{
    PFN_pthread_create ptr_pthread_exit;
    // Add the rest rest here.
} PTHREAD_IMPL;

// Define your various implementations dispatcher structures.
static PTHREAD_IMPL legacy_impl = { 
    &legacy_pthread_exit_impl
};
static PTHREAD_IMPL latest_andgreatest_impl = { 
    &pthread_exit_impl
};
static PTHREAD_IMPL* s_pImpl = NULL;

Next, your library's initialize function should contain something like this:

int StaticInitialize( )
{
    // Initalize dispatcher
    if( latest and greatest OS version )
        s_pImpl = &latest_andgreatest_impl
    else
        s_pImpl = &legacy_impl;
}

Finally, your libraries exported functions should look something like this:

int pthread_exit( void *value_ptr )
{
    ASSERT( s_pImpl );
    ASSERT( s_pImpl->ptr_pthread_exit );
    return s_pImpl->ptr_pthread_exit( value_ptr );
}

Naturally, you'll need to ensure that your modern implementations utilize runtime binding for exports that don't exist on legacy platforms.

Have fun!

Bukes
  • 3,668
  • 1
  • 18
  • 20