Commit 32946009 authored by Peter Eastman's avatar Peter Eastman
Browse files

Changed how plugin initialization is done to avoid initialization order problems

parent 61eed805
......@@ -229,6 +229,11 @@ private:
std::map<std::string, KernelFactory*> kernelFactories;
std::map<std::string, std::string> defaultProperties;
static std::vector<Platform*>& getPlatforms();
#ifdef WIN32
static std::vector<HMODULE>& getPlugins();
#else
static std::vector<void*>& getPlugins();
#endif
};
} // namespace OpenMM
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008 Stanford University and the Authors. *
* Portions copyright (c) 2009 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -33,27 +33,28 @@
* -------------------------------------------------------------------------- */
/**
* This file should be included once in each dynamic library that contains an OpenMM
* plugin. The library should define a function with the signature
*
* extern "C" void initOpenMMPlugin();
*
* that registers any Platforms and KernelFactories it contains. Including this file
* will cause that function to be invoked when the library is loaded.
* This file contains declarations for initialization functions that may be defined
* by plugins, and that are invoked after the plugins have been loaded. There are
* two such functions: one for registering new Platforms, and one for adding new
* KernelFactories to existing Platforms. Each of these functions is optional; most
* plugins implement one or the other of them, but not both.
*/
#if defined(OPENMM_BUILDING_SHARED_LIBRARY)
#if defined(WIN32)
#include <windows.h>
extern "C" void initOpenMMPlugin();
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
initOpenMMPlugin();
return TRUE;
}
#else
extern "C" void __attribute__((constructor)) initOpenMMPlugin();
#endif
#endif
/**
* If a plugin defines a new Platform, it should define this function. It will be
* invoked after the plugin is loaded, and should register the new Platform by
* calling Platform::registerPlatform().
*/
extern "C" void registerPlatforms();
/**
* If a plugin defines a new KernelFactory for an existing Platform, it should define
* this function. It will be invoked after the plugin is loaded, and should register
* the new factory by calling registerKernelFactory() on the appropriate Platform object.
* It is not invoked until after registerPlatforms() has been called on every plugin,
* thus avoiding initialization order problems when one plugin adds a KernelFactory
* to a Platform defined by another plugin.
*/
extern "C" void registerKernelFactories();
#endif /*OPENMM_PLUGININITIALIZER_H_*/
......@@ -115,10 +115,57 @@ Kernel Platform::createKernel(const string& name, ContextImpl& context) const {
}
vector<Platform*>& Platform::getPlatforms() {
if (getPlugins().size() > 0) {
// Initialize plugins before returning the list of platforms.
#ifdef WIN32
vector<HMODULE> plugins = getPlugins();
getPlugins().clear();
for (int i = 0; i < (int) plugins.size(); i++) {
void (*init)();
*(void **)(&init) = GetProcAddress(plugins[i], "registerPlatforms");
if (init != NULL)
(*init)();
}
for (int i = 0; i < (int) plugins.size(); i++) {
void (*init)();
*(void **)(&init) = GetProcAddress(plugins[i], "registerKernelFactories");
if (init != NULL)
(*init)();
}
#else
vector<void*> plugins = getPlugins();
getPlugins().clear();
for (int i = 0; i < (int) plugins.size(); i++) {
void (*init)();
*(void **)(&init) = dlsym(plugins[i], "registerPlatforms");
if (init != NULL)
(*init)();
}
for (int i = 0; i < (int) plugins.size(); i++) {
void (*init)();
*(void **)(&init) = dlsym(plugins[i], "registerKernelFactories");
if (init != NULL)
(*init)();
}
#endif
}
static vector<Platform*> platforms;
return platforms;
}
#ifdef WIN32
vector<HMODULE>& Platform::getPlugins() {
static vector<HMODULE> plugins;
return plugins;
}
#else
vector<void*>& Platform::getPlugins() {
static vector<void*> plugins;
return plugins;
}
#endif
void Platform::registerPlatform(Platform* platform) {
getPlatforms().push_back(platform);
}
......@@ -159,16 +206,17 @@ void Platform::loadPluginLibrary(const string& file) {
const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
HMODULE handle = LoadLibrary(file.c_str());
SetErrorMode(oldErrorMode); // Restore previous error mode.
if (handle == NULL) {
string message;
stringstream(message) << "Error loading library " << file << ": " << GetLastError();
if (handle == NULL) {
string message;
stringstream(message) << "Error loading library " << file << ": " << GetLastError();
throw OpenMMException(message);
}
}
#else
void *handle = dlopen(file.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if (handle == NULL)
throw OpenMMException("Error loading library "+file+": "+dlerror());
#endif
getPlugins().push_back(handle);
}
vector<string> Platform::loadPluginsFromDirectory(const string& directory) {
......
......@@ -27,7 +27,6 @@
#include "CudaPlatform.h"
#include "CudaKernelFactory.h"
#include "CudaKernels.h"
#include "openmm/PluginInitializer.h"
#include "openmm/internal/ContextImpl.h"
#include "kernels/gputypes.h"
#include "openmm/Context.h"
......@@ -39,7 +38,7 @@ using std::map;
using std::string;
using std::stringstream;
extern "C" void initOpenMMPlugin() {
extern "C" void registerPlatforms() {
if (gpuIsAvailable())
Platform::registerPlatform(new CudaPlatform());
}
......
......@@ -28,7 +28,6 @@
#include "OpenCLPlatform.h"
#include "OpenCLKernelFactory.h"
#include "OpenCLKernels.h"
#include "openmm/PluginInitializer.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/Context.h"
#include "openmm/System.h"
......@@ -39,7 +38,7 @@ using std::map;
using std::string;
using std::stringstream;
extern "C" void initOpenMMPlugin() {
extern "C" void registerPlatforms() {
Platform::registerPlatform(new OpenCLPlatform());
}
......
......@@ -36,24 +36,7 @@
using namespace OpenMM;
// using PluginInitializer.h and initOpenMMPlugin() does not seem to work
//#include "openmm/PluginInitializer.h"
#if defined(OPENMM_BUILDING_SHARED_LIBRARY)
#if defined(WIN32)
#include <windows.h>
extern "C" void initOpenMMReferenceFreeEnergyPlugin();
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
initOpenMMReferenceFreeEnergyPlugin();
return TRUE;
}
#else
extern "C" void __attribute__((constructor)) initOpenMMReferenceFreeEnergyPlugin();
#endif
#endif
extern "C" void initOpenMMReferenceFreeEnergyPlugin() {
extern "C" void registerKernelFactories() {
for( int ii = 0; ii < Platform::getNumPlatforms(); ii++ ){
Platform& platform = Platform::getPlatform(ii);
if( platform.getName().compare( "Reference" ) == 0 ){
......
......@@ -36,7 +36,7 @@
using namespace OpenMM;
using namespace std;
extern "C" void initOpenMMPlugin() {
extern "C" void registerKernelFactories() {
cout << "Initializing Normal Mode Langevin OpenMM plugin..." << endl;
// for (int p = 0; p < Platform::getNumPlatforms(); ++p) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment