SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

backend-loader.cpp

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2008 Maciej Sobczak with contributions from Artyom Tonkikh
00003 // Distributed under the Boost Software License, Version 1.0.
00004 // (See accompanying file LICENSE_1_0.txt or copy at
00005 // http://www.boost.org/LICENSE_1_0.txt)
00006 //
00007 
00008 #define SOCI_SOURCE
00009 #include "backend-loader.h"
00010 #include "error.h"
00011 #include <map>
00012 #include <cassert>
00013 #include <cstdlib>
00014 //#include <cstddef>
00015 //#include <cstdio>
00016 #ifndef _MSC_VER
00017 #include <stdint.h>
00018 #endif
00019 
00020 using namespace soci;
00021 using namespace soci::dynamic_backends;
00022 
00023 #ifdef _WIN32
00024 
00025 #include <windows.h>
00026 
00027 typedef CRITICAL_SECTION soci_mutex_t;
00028 typedef HMODULE soci_handler_t;
00029 
00030 #define LOCK(x) EnterCriticalSection(x)
00031 #define UNLOCK(x) LeaveCriticalSection(x)
00032 #define MUTEX_INIT(x) InitializeCriticalSection(x)
00033 #define MUTEX_DEST(x) DeleteCriticalSection(x)
00034 #define DLOPEN(x) LoadLibrary(x)
00035 #define DLCLOSE(x) FreeLibrary(x)
00036 #define DLSYM(x, y) GetProcAddress(x, y)
00037 #define LIBNAME(x) ("libsoci_" + x + ".dll")
00038 
00039 #else
00040 
00041 #include <pthread.h>
00042 #include <dlfcn.h>
00043 
00044 typedef pthread_mutex_t soci_mutex_t;
00045 typedef void * soci_handler_t;
00046 
00047 #define LOCK(x) pthread_mutex_lock(x)
00048 #define UNLOCK(x) pthread_mutex_unlock(x)
00049 #define MUTEX_INIT(x) pthread_mutex_init(x, NULL)
00050 #define MUTEX_DEST(x) pthread_mutex_destroy(x)
00051 #define DLOPEN(x) dlopen(x, RTLD_LAZY)
00052 #define DLCLOSE(x) dlclose(x)
00053 #define DLSYM(x, y) dlsym(x, y)
00054 #define LIBNAME(x) ("libsoci_" + x + ".so")
00055 
00056 #endif // _WIN32
00057 
00058 
00059 namespace // unnamed
00060 {
00061 
00062 struct info
00063 {
00064     soci_handler_t handler_;
00065     backend_factory const * factory_;
00066     info() : handler_(NULL), factory_(NULL) {}
00067 };
00068 
00069 typedef std::map<std::string, info> factory_map;
00070 factory_map factories_;
00071 
00072 std::vector<std::string> search_paths_;
00073 
00074 soci_mutex_t mutex_;
00075 
00076 std::vector<std::string> get_default_paths()
00077 {
00078     std::vector<std::string> paths;
00079 
00080     char const * const penv = std::getenv("SOCI_BACKENDS_PATH");
00081     if (penv == NULL)
00082     {
00083         paths.push_back(".");
00084         return paths;
00085     }
00086 
00087     std::string const env = penv;
00088     if (env.empty())
00089     {
00090         paths.push_back(".");
00091         return paths;
00092     }
00093 
00094     std::string::size_type searchFrom = 0;
00095     while (searchFrom != env.size())
00096     {
00097         std::string::size_type const found = env.find(":", searchFrom);
00098         if (found == searchFrom)
00099         {
00100             ++searchFrom;
00101         }
00102         else if (found != std::string::npos)
00103         {
00104             std::string const path = env.substr(searchFrom, found - searchFrom);
00105             paths.push_back(path);
00106 
00107             searchFrom = found + 1;
00108         }
00109         else // found == npos
00110         {
00111             std::string const path = env.substr(searchFrom);
00112             paths.push_back(path);
00113 
00114             searchFrom = env.size();
00115         }
00116     }
00117 
00118     return paths;
00119 }
00120 
00121 // used to automatically initialize the global state
00122 struct static_state_mgr
00123 {
00124     static_state_mgr()
00125     {
00126         MUTEX_INIT(&mutex_);
00127 
00128         search_paths_ = get_default_paths();
00129     }
00130 
00131     ~static_state_mgr()
00132     {
00133         unload_all();
00134 
00135         MUTEX_DEST(&mutex_);
00136     }
00137 } static_state_mgr_;
00138 
00139 class scoped_lock
00140 {
00141 public:
00142     scoped_lock(soci_mutex_t * m) : mptr(m) { LOCK(m); };
00143     ~scoped_lock() { UNLOCK(mptr); };
00144 private:
00145     soci_mutex_t * mptr;
00146 };
00147 
00148 // non-synchronized helper for the other functions
00149 void do_unload(std::string const & name)
00150 {
00151     factory_map::iterator i = factories_.find(name);
00152 
00153     if (i != factories_.end())
00154     {
00155         soci_handler_t h = i->second.handler_;
00156         if (h != NULL)
00157         {
00158             DLCLOSE(h);
00159         }
00160 
00161         factories_.erase(i);
00162     }
00163 }
00164 
00165 // non-synchronized helper
00166 void do_register_backend(
00167     std::string const & name, std::string const & shared_object)
00168 {
00169     // The rules for backend search are as follows:
00170     // - if the shared_object is given,
00171     //   it names the library file and the search paths are not used
00172     // - otherwise (shared_object not provided or empty):
00173     //   - file named libsoci_NAME.so is searched in the list of search paths
00174 
00175     soci_handler_t h = NULL;
00176     if (shared_object.empty() == false)
00177     {
00178         h = DLOPEN(shared_object.c_str());
00179     }
00180     else
00181     {
00182         // try all search paths
00183         for (std::size_t i = 0; i != search_paths_.size(); ++i)
00184         {
00185             std::string const fullFileName = search_paths_[i] + "/" + LIBNAME(name);
00186             h = DLOPEN(fullFileName.c_str());
00187             if (h != NULL)
00188             {
00189                 // already found
00190                 break;
00191             }
00192         }
00193     }
00194 
00195     if (h == NULL)
00196     {
00197         throw soci_error("Failed to find shared library for backend " + name);
00198     }
00199 
00200     std::string symbol = "factory_" + name;
00201 
00202     typedef backend_factory const * bfc_ptr;
00203     typedef bfc_ptr (*get_t)(void);
00204     get_t entry;
00205     entry = reinterpret_cast<get_t>(reinterpret_cast<uintptr_t>(DLSYM(h, symbol.c_str())));
00206 
00207     if (entry == NULL)
00208     {
00209         DLCLOSE(h);
00210         throw soci_error("Failed to resolve dynamic symbol: " + symbol);
00211     }
00212 
00213     // unload the existing handler if it's already loaded
00214 
00215     do_unload(name);
00216     
00217     backend_factory const * f = entry();
00218 
00219     info new_entry;
00220     new_entry.factory_ = f;
00221     new_entry.handler_ = h;
00222 
00223     factories_[name] = new_entry;
00224 }
00225 
00226 } // unnamed namespace
00227 
00228 backend_factory const & dynamic_backends::get(std::string const & name)
00229 {
00230     scoped_lock lock(&mutex_);
00231 
00232     factory_map::iterator i = factories_.find(name);
00233 
00234     if (i != factories_.end())
00235     {
00236         return *(i->second.factory_);
00237     }
00238 
00239     // no backend found with this name, try to register it first
00240 
00241     do_register_backend(name, std::string());
00242 
00243     // second attempt, must succeed (the backend is already loaded)
00244 
00245     i = factories_.find(name);
00246 
00247     assert(i != factories_.end());
00248 
00249     return *(i->second.factory_);
00250 }
00251 
00252 std::vector<std::string> & search_paths()
00253 {
00254     return search_paths_;
00255 }
00256 
00257 void dynamic_backends::register_backend(
00258     std::string const & name, std::string const & shared_object)
00259 {
00260     scoped_lock lock(&mutex_);
00261 
00262     do_register_backend(name, shared_object);
00263 }
00264 
00265 void dynamic_backends::register_backend(
00266     std::string const & name, backend_factory const & factory)
00267 {
00268     scoped_lock lock(&mutex_);
00269 
00270     // unload the existing handler if it's already loaded
00271 
00272     do_unload(name);
00273     
00274     info new_entry;
00275     new_entry.factory_ = &factory;
00276 
00277     factories_[name] = new_entry;
00278 }
00279 
00280 std::vector<std::string> dynamic_backends::list_all()
00281 {
00282     scoped_lock lock(&mutex_);
00283 
00284     std::vector<std::string> ret;
00285     ret.reserve(factories_.size());
00286 
00287     factory_map::iterator i;
00288     for (i = factories_.begin(); i != factories_.end(); ++i)
00289     {
00290         std::string const & name = i->first;
00291         ret.push_back(name);
00292     }
00293 
00294     return ret;
00295 }
00296 
00297 void dynamic_backends::unload(std::string const & name)
00298 {
00299     scoped_lock lock(&mutex_);
00300 
00301     do_unload(name);
00302 }
00303 
00304 void dynamic_backends::unload_all()
00305 {
00306     scoped_lock lock(&mutex_);
00307 
00308     factory_map::iterator i;
00309     for (i = factories_.begin(); i != factories_.end(); ++i)
00310     {
00311         soci_handler_t h = i->second.handler_;
00312         if (h != NULL)
00313         {
00314             DLCLOSE(h);
00315         }
00316     }
00317 
00318     factories_.clear();
00319 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:17 for EXTRAS-SOCI by Doxygen 1.7.1