Skip to content

Commit

Permalink
Factor out loadable module handling from PluginManager.
Browse files Browse the repository at this point in the history
Behavior is mostly unchanged, with one major exception: when a module is
requested, the previously loaded version (if any) is always used, instead of
searching the paths anew. This prevents different files from being loaded for
the same module name (unless the module is first unloaded) in the case where
the search paths or the files within them have changed. (It probably also
speeds up device loading.)

git-svn-id: https://valelab.ucsf.edu/svn/micromanager2/trunk@12462 d0ab736e-dc22-4aeb-8dc9-08def0aa14fd
  • Loading branch information
mark committed Dec 24, 2013
1 parent f68d749 commit 73efc9b
Show file tree
Hide file tree
Showing 18 changed files with 436 additions and 202 deletions.
14 changes: 14 additions & 0 deletions MMCore/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ CMMError::CMMError(const char* msg, Code code, const CMMError& underlyingError)
{}


CMMError::CMMError(const std::string& msg, const CMMError& underlyingError) :
message_(msg),
code_(MMERR_GENERIC),
underlying_(new CMMError(underlyingError))
{}


CMMError::CMMError(const char* msg, const CMMError& underlyingError) :
message_(msg ? msg : "(null message)"),
code_(MMERR_GENERIC),
underlying_(new CMMError(underlyingError))
{}


CMMError::CMMError(const CMMError& other) :
message_(other.message_),
code_(other.code_),
Expand Down
20 changes: 18 additions & 2 deletions MMCore/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class CMMError : public std::exception
*/
explicit CMMError(const char* msg, Code code = MMERR_GENERIC);

/// Construct with an underlying (chained/wrapped) error.
/// Construct with an error code and underlying (chained/wrapped) error.
/**
* Use this form of the constructor when adding information and rethrowing
* the exception.
Expand All @@ -91,7 +91,7 @@ class CMMError : public std::exception
*/
CMMError(const std::string& msg, Code code, const CMMError& underlyingError);

/// Construct with an underlying (chained/wrapped) error.
/// Construct with an error code and underlying (chained/wrapped) error.
/**
* Use this form of the constructor when adding information and rethrowing
* the exception.
Expand All @@ -100,6 +100,22 @@ class CMMError : public std::exception
*/
CMMError(const char* msg, Code code, const CMMError& underlyingError);

/// Construct with an underlying (chained/wrapped) error.
/**
* Use this form of the constructor when adding information and rethrowing
* the exception.
*/
CMMError(const std::string& msg, const CMMError& underlyingError);

/// Construct with an underlying (chained/wrapped) error.
/**
* Use this form of the constructor when adding information and rethrowing
* the exception.
*
* msg should not be null.
*/
CMMError(const char* msg, const CMMError& underlyingError);

/// Copy constructor (perform a deep copy).
CMMError(const CMMError& other);

Expand Down
54 changes: 54 additions & 0 deletions MMCore/LoadableModules/LoadedModule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "LoadedModule.h"

#include "LoadedModuleImpl.h"
#include "../CoreUtils.h"
#include "../Error.h"


LoadedModule::LoadedModule(const std::string& filename) :
filename_(filename)
{
try
{
pImpl_ = LoadedModuleImpl::NewPlatformImpl(filename_);
}
catch (const CMMError& e)
{
throw CMMError("Failed to load module " + ToQuotedString(filename_), e);
}
}


LoadedModule::~LoadedModule()
{
delete pImpl_;
}


void
LoadedModule::Unload()
{
try
{
pImpl_->Unload();
}
catch (const CMMError& e)
{
throw CMMError("Cannot unload module " + ToQuotedString(filename_), e);
}
}


void*
LoadedModule::GetFunction(const char* funcName)
{
try
{
return pImpl_->GetFunction(funcName);
}
catch (const CMMError& e)
{
throw CMMError("Cannot find function " + ToString(funcName) + "() in module " +
ToQuotedString(filename_), e);
}
}
21 changes: 21 additions & 0 deletions MMCore/LoadableModules/LoadedModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>


class LoadedModuleImpl;

class LoadedModule /* final */ : boost::noncopyable
{
public:
explicit LoadedModule(const std::string& filename);
~LoadedModule();

void Unload(); // For developer use only
void* GetFunction(const char* funcName);

private:
LoadedModuleImpl* pImpl_;
const std::string filename_;
};
16 changes: 16 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "LoadedModuleImpl.h"

#ifdef WIN32
# include "LoadedModuleImplWindows.h"
typedef LoadedModuleImplWindows PlatformLoadedModuleImpl;
#else
# include "LoadedModuleImplUnix.h"
typedef LoadedModuleImplUnix PlatformLoadedModuleImpl;
#endif


LoadedModuleImpl*
LoadedModuleImpl::NewPlatformImpl(const std::string& filename)
{
return new PlatformLoadedModuleImpl(filename);
}
19 changes: 19 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "LoadedModule.h"

#include <boost/utility.hpp>

class LoadedModuleImpl : boost::noncopyable
{
public:
static LoadedModuleImpl* NewPlatformImpl(const std::string& filename);

virtual ~LoadedModuleImpl() {}

virtual void Unload() = 0;
virtual void* GetFunction(const char* funcName) = 0;

protected:
LoadedModuleImpl() {}
};
57 changes: 57 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImplUnix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "LoadedModuleImplUnix.h"

#include "../Error.h"

#include <dlfcn.h>


static void __attribute__((noreturn))
ThrowDlError()
{
const char* errorText = dlerror();
if (!errorText)
errorText = "Operating system error message not available";
throw CMMError(errorText);
}


LoadedModuleImplUnix::LoadedModuleImplUnix(const std::string& filename)
{
int mode = RTLD_NOW | RTLD_LOCAL;

// Hack to make Andor adapter on Linux work
// TODO Check if this is still necessary, and if so, why. If it is
// necessary, add a more generic 'enable-lazy' mechanism.
if (filename.find("libmmgr_dal_Andor.so") != std::string::npos)
mode = RTLD_LAZY | RTLD_LOCAL;

handle_ = dlopen(filename.c_str(), mode);
if (!handle_)
ThrowDlError();
}


void
LoadedModuleImplUnix::Unload()
{
if (!handle_)
return;

int err = dlclose(handle_);
handle_ = 0;
if (err)
ThrowDlError();
}


void*
LoadedModuleImplUnix::GetFunction(const char* funcName)
{
if (!handle_)
throw CMMError("Cannot get function from unloaded module");

void* proc = dlsym(handle_, funcName);
if (!proc)
ThrowDlError();
return proc;
}
14 changes: 14 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImplUnix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "LoadedModuleImpl.h"


class LoadedModuleImplUnix : public LoadedModuleImpl
{
public:
explicit LoadedModuleImplUnix(const std::string& filename);
virtual void Unload();

virtual void* GetFunction(const char* funcName);

private:
void* handle_;
};
83 changes: 83 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImplWindows.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "LoadedModuleImplWindows.h"

#include "../Error.h"

#include <boost/algorithm/string.hpp>


static void __declspec(noreturn)
ThrowLastError()
{
std::string errorText;

DWORD err = GetLastError();
LPSTR pMsgBuf(0);
if (FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&pMsgBuf,
0,
NULL) && pMsgBuf)
{
errorText = pMsgBuf;

// Windows error messages sometimes have trailing newlines
boost::algorithm::trim(errorText);

// This particular message can be rather misleading.
if (errorText == "The specified module could not be found.") {
errorText = "The module, or a module it depends upon, could not be found "
"(Windows error: " + errorText + ")";
}
}
if (pMsgBuf)
{
LocalFree(pMsgBuf);
}

if (errorText.empty()) {
errorText = "Operating system error message not available";
}

throw CMMError(errorText);
}


LoadedModuleImplWindows::LoadedModuleImplWindows(const std::string& filename)
{
int saveErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
handle_ = LoadLibrary(filename.c_str());
SetErrorMode(saveErrorMode);
if (!handle_)
ThrowLastError();
}


void
LoadedModuleImplWindows::Unload()
{
if (!handle_)
return;

BOOL ok = FreeLibrary(handle_);
handle_ = 0;
if (!ok)
ThrowLastError();
}


void*
LoadedModuleImplWindows::GetFunction(const char* funcName)
{
if (!handle_)
throw CMMError("Cannot get function from unloaded module");

void* proc = GetProcAddress(handle_, funcName);
if (!proc)
ThrowLastError();
return proc;
}
18 changes: 18 additions & 0 deletions MMCore/LoadableModules/LoadedModuleImplWindows.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "LoadedModuleImpl.h"

#include <windows.h>


class LoadedModuleImplWindows: public LoadedModuleImpl
{
public:
explicit LoadedModuleImplWindows(const std::string& filename);
virtual void Unload();

virtual void* GetFunction(const char* funcName);

private:
HMODULE handle_;
};
8 changes: 7 additions & 1 deletion MMCore/MMCore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@
<ClCompile Include="FastLogger.cpp" />
<ClCompile Include="Host.cpp" />
<ClCompile Include="..\MMDevice\ImgBuffer.cpp" />
<ClCompile Include="LoadableModules\LoadedModule.cpp" />
<ClCompile Include="LoadableModules\LoadedModuleImpl.cpp" />
<ClCompile Include="LoadableModules\LoadedModuleImplWindows.cpp" />
<ClCompile Include="MMCore.cpp" />
<ClCompile Include="PluginManager.cpp" />
</ItemGroup>
Expand All @@ -175,6 +178,9 @@
<ClInclude Include="..\MMDevice\ImageMetadata.h" />
<ClInclude Include="..\MMDevice\ImgBuffer.h" />
<ClInclude Include="IMMLogger.h" />
<ClInclude Include="LoadableModules\LoadedModule.h" />
<ClInclude Include="LoadableModules\LoadedModuleImpl.h" />
<ClInclude Include="LoadableModules\LoadedModuleImplWindows.h" />
<ClInclude Include="MMCore.h" />
<ClInclude Include="..\MMDevice\MMDevice.h" />
<ClInclude Include="MMEventCallback.h" />
Expand All @@ -183,4 +189,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
Loading

0 comments on commit 73efc9b

Please sign in to comment.