blob: abefa6288357f8226078e11e424718f910c02200 [file] [log] [blame]
/*
Copyright 2005-2010 Intel Corporation. All Rights Reserved.
This file is part of Threading Building Blocks.
Threading Building Blocks is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Threading Building Blocks is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Threading Building Blocks; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
As a special exception, you may use this file as part of a free software
library without restriction. Specifically, if other files instantiate
templates or use macros or inline functions from this file, or you compile
this file and link it with other files to produce an executable, this
file does not by itself cause the resulting executable to be covered by
the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
#include "dynamic_link.h"
#ifndef LIBRARY_ASSERT
#include "tbb/tbb_stddef.h"
#define LIBRARY_ASSERT(x,y) __TBB_ASSERT(x,y)
#endif /* LIBRARY_ASSERT */
#if _WIN32||_WIN64
#include <malloc.h> /* alloca */
#else
#include <dlfcn.h>
#if __FreeBSD__
#include <stdlib.h> /* alloca */
#else
#include <alloca.h>
#endif
#endif
OPEN_INTERNAL_NAMESPACE
#if __TBB_WEAK_SYMBOLS
bool dynamic_link( void*, const dynamic_link_descriptor descriptors[], size_t n, size_t required )
{
if ( required == ~(size_t)0 )
required = n;
LIBRARY_ASSERT( required<=n, "Number of required entry points exceeds their total number" );
size_t k = 0;
// Check if the first required entries are present in what was loaded into our process
while ( k < required && descriptors[k].ptr )
++k;
if ( k < required )
return false;
// Commit all the entry points.
for ( k = 0; k < n; ++k )
*descriptors[k].handler = (pointer_to_handler) descriptors[k].ptr;
return true;
}
#else /* !__TBB_WEAK_SYMBOLS */
bool dynamic_link( void* module, const dynamic_link_descriptor descriptors[], size_t n, size_t required )
{
pointer_to_handler *h = (pointer_to_handler*)alloca(n * sizeof(pointer_to_handler));
if ( required == ~(size_t)0 )
required = n;
LIBRARY_ASSERT( required<=n, "Number of required entry points exceeds their total number" );
size_t k = 0;
for ( ; k < n; ++k ) {
#if _WIN32||_WIN64
h[k] = pointer_to_handler(GetProcAddress( (HMODULE)module, descriptors[k].name ));
#else
// Lvalue casting is used; this way icc -strict-ansi does not warn about nonstandard pointer conversion
(void *&)h[k] = dlsym( module, descriptors[k].name );
#endif /* _WIN32||_WIN64 */
if ( !h[k] && k < required )
return false;
}
LIBRARY_ASSERT( k == n, "if required entries are initialized, all entries are expected to be walked");
// Commit the entry points.
// Cannot use memset here, because the writes must be atomic.
for( k = 0; k < n; ++k )
*descriptors[k].handler = h[k];
return true;
}
#endif /* !__TBB_WEAK_SYMBOLS */
bool dynamic_link( const char* library, const dynamic_link_descriptor descriptors[], size_t n, size_t required, dynamic_link_handle* handle )
{
#if _WIN32||_WIN64
// Interpret non-NULL handle parameter as request to really link against another library.
if ( !handle && dynamic_link( GetModuleHandle(NULL), descriptors, n, required ) )
// Target library was statically linked into this executable
return true;
// Prevent Windows from displaying silly message boxes if it fails to load library
// (e.g. because of MS runtime problems - one of those crazy manifest related ones)
#if _XBOX
dynamic_link_handle module = LoadLibrary (library);
#else
UINT prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
dynamic_link_handle module = LoadLibrary (library);
SetErrorMode (prev_mode);
#endif /* _XBOX */
#else
dynamic_link_handle module = dlopen( library, RTLD_LAZY );
#endif /* _WIN32||_WIN64 */
if( module ) {
if( !dynamic_link( module, descriptors, n, required ) ) {
// Return true if the library is there and it contains all the expected entry points.
dynamic_unlink(module);
module = NULL;
}
}
if( handle )
*handle = module;
return module!=NULL;
}
void dynamic_unlink( dynamic_link_handle handle ) {
if( handle ) {
#if _WIN32||_WIN64
FreeLibrary( handle );
#else
dlclose( handle );
#endif /* _WIN32||_WIN64 */
}
}
CLOSE_INTERNAL_NAMESPACE