backend-loader.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2008 Maciej Sobczak with contributions from Artyom Tonkikh
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 
8 #define SOCI_SOURCE
9 #include "backend-loader.h"
10 #include "error.h"
11 #include <cassert>
12 #include <cstdlib>
13 #include <map>
14 #include <string>
15 #include <vector>
16 #ifndef _MSC_VER
17 #include <stdint.h>
18 #endif
19 
20 #include "soci_backends_config.h"
21 
22 using namespace soci;
23 using namespace soci::dynamic_backends;
24 
25 #ifdef _WIN32
26 
27 #include <windows.h>
28 
29 typedef CRITICAL_SECTION soci_mutex_t;
30 typedef HMODULE soci_handler_t;
31 
32 #define LOCK(x) EnterCriticalSection(x)
33 #define UNLOCK(x) LeaveCriticalSection(x)
34 #define MUTEX_INIT(x) InitializeCriticalSection(x)
35 #define MUTEX_DEST(x) DeleteCriticalSection(x)
36 #ifdef _UNICODE
37 #define DLOPEN(x) LoadLibraryA(x)
38 #else
39 #define DLOPEN(x) LoadLibrary(x)
40 #endif
41 #define DLCLOSE(x) FreeLibrary(x)
42 #define DLSYM(x, y) GetProcAddress(x, y)
43 
44 #ifdef SOCI_ABI_VERSION
45 #define LIBNAME(x) (SOCI_LIB_PREFIX + x + "_" SOCI_ABI_VERSION SOCI_LIB_SUFFIX)
46 #else
47 #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX)
48 #endif // SOCI_ABI_VERSION
49 
50 #else
51 
52 #include <pthread.h>
53 #include <dlfcn.h>
54 
55 typedef pthread_mutex_t soci_mutex_t;
56 typedef void * soci_handler_t;
57 
58 #define LOCK(x) pthread_mutex_lock(x)
59 #define UNLOCK(x) pthread_mutex_unlock(x)
60 #define MUTEX_INIT(x) pthread_mutex_init(x, NULL)
61 #define MUTEX_DEST(x) pthread_mutex_destroy(x)
62 #define DLOPEN(x) dlopen(x, RTLD_LAZY)
63 #define DLCLOSE(x) dlclose(x)
64 #define DLSYM(x, y) dlsym(x, y)
65 
66 #ifdef SOCI_ABI_VERSION
67 
68 #ifdef __APPLE__
69 #define LIBNAME(x) (SOCI_LIB_PREFIX + x + "." SOCI_ABI_VERSION SOCI_LIB_SUFFIX)
70 #else
71 #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX "." SOCI_ABI_VERSION)
72 #endif
73 
74 #else
75 #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX)
76 #endif // SOCI_ABI_VERSION
77 
78 #endif // _WIN32
79 
80 
81 namespace // unnamed
82 {
83 
84 struct info
85 {
86  soci_handler_t handler_;
87  backend_factory const * factory_;
88  info() : handler_(0), factory_(0) {}
89 };
90 
91 typedef std::map<std::string, info> factory_map;
92 factory_map factories_;
93 
94 std::vector<std::string> search_paths_;
95 
96 soci_mutex_t mutex_;
97 
98 std::vector<std::string> get_default_paths()
99 {
100  std::vector<std::string> paths;
101 
102  // TODO: may be problem with finding getenv in std namespace in Visual C++ --mloskot
103  char const* const penv = std::getenv("SOCI_BACKENDS_PATH");
104  if (0 == penv)
105  {
106  paths.push_back(".");
107  paths.push_back(DEFAULT_BACKENDS_PATH);
108  return paths;
109  }
110 
111  std::string const env = penv;
112  if (env.empty())
113  {
114  paths.push_back(".");
115  paths.push_back(DEFAULT_BACKENDS_PATH);
116  return paths;
117  }
118 
119  std::string::size_type searchFrom = 0;
120  while (searchFrom != env.size())
121  {
122  std::string::size_type const found = env.find(":", searchFrom);
123  if (found == searchFrom)
124  {
125  ++searchFrom;
126  }
127  else if (std::string::npos != found)
128  {
129  std::string const path(env.substr(searchFrom, found - searchFrom));
130  paths.push_back(path);
131 
132  searchFrom = found + 1;
133  }
134  else // found == npos
135  {
136  std::string const path = env.substr(searchFrom);
137  paths.push_back(path);
138 
139  searchFrom = env.size();
140  }
141  }
142 
143  return paths;
144 }
145 
146 // used to automatically initialize the global state
147 struct static_state_mgr
148 {
149  static_state_mgr()
150  {
151  MUTEX_INIT(&mutex_);
152 
153  search_paths_ = get_default_paths();
154  }
155 
156  ~static_state_mgr()
157  {
158  unload_all();
159 
160  MUTEX_DEST(&mutex_);
161  }
162 } static_state_mgr_;
163 
164 class scoped_lock
165 {
166 public:
167  scoped_lock(soci_mutex_t * m) : mptr(m) { LOCK(m); };
168  ~scoped_lock() { UNLOCK(mptr); };
169 private:
170  soci_mutex_t * mptr;
171 };
172 
173 // non-synchronized helper for the other functions
174 void do_unload(std::string const & name)
175 {
176  factory_map::iterator i = factories_.find(name);
177 
178  if (i != factories_.end())
179  {
180  soci_handler_t h = i->second.handler_;
181  if (h != NULL)
182  {
183  DLCLOSE(h);
184  }
185 
186  factories_.erase(i);
187  }
188 }
189 
190 // non-synchronized helper
191 void do_register_backend(std::string const & name, std::string const & shared_object)
192 {
193  // The rules for backend search are as follows:
194  // - if the shared_object is given,
195  // it names the library file and the search paths are not used
196  // - otherwise (shared_object not provided or empty):
197  // - file named libsoci_NAME.so.SOVERSION is searched in the list of search paths
198 
199  soci_handler_t h = 0;
200  if (shared_object.empty() == false)
201  {
202  h = DLOPEN(shared_object.c_str());
203  }
204  else
205  {
206  // try system paths
207  h = DLOPEN(LIBNAME(name).c_str());
208  if (0 == h)
209  {
210  // try all search paths
211  for (std::size_t i = 0; i != search_paths_.size(); ++i)
212  {
213  std::string const fullFileName(search_paths_[i] + "/" + LIBNAME(name));
214  h = DLOPEN(fullFileName.c_str());
215  if (0 != h)
216  {
217  // already found
218  break;
219  }
220  }
221  }
222  }
223 
224  if (0 == h)
225  {
226  throw soci_error("Failed to find shared library for backend " + name);
227  }
228 
229  std::string symbol = "factory_" + name;
230 
231  typedef backend_factory const * bfc_ptr;
232  typedef bfc_ptr (*get_t)(void);
233  get_t entry;
234  entry = reinterpret_cast<get_t>(
235  reinterpret_cast<uintptr_t>(DLSYM(h, symbol.c_str())));
236 
237  if (0 == entry)
238  {
239  DLCLOSE(h);
240  throw soci_error("Failed to resolve dynamic symbol: " + symbol);
241  }
242 
243  // unload the existing handler if it's already loaded
244 
245  do_unload(name);
246 
247  backend_factory const* f = entry();
248 
249  info new_entry;
250  new_entry.factory_ = f;
251  new_entry.handler_ = h;
252 
253  factories_[name] = new_entry;
254 }
255 
256 } // unnamed namespace
257 
258 backend_factory const& dynamic_backends::get(std::string const& name)
259 {
260  scoped_lock lock(&mutex_);
261 
262  factory_map::iterator i = factories_.find(name);
263 
264  if (i != factories_.end())
265  {
266  return *(i->second.factory_);
267  }
268 
269  // no backend found with this name, try to register it first
270 
271  do_register_backend(name, std::string());
272 
273  // second attempt, must succeed (the backend is already loaded)
274 
275  i = factories_.find(name);
276 
277  assert(i != factories_.end());
278 
279  return *(i->second.factory_);
280 }
281 
282 SOCI_DECL std::vector<std::string>& search_paths()
283 {
284  return search_paths_;
285 }
286 
288  std::string const& name, std::string const& shared_object)
289 {
290  scoped_lock lock(&mutex_);
291 
292  do_register_backend(name, shared_object);
293 }
294 
296  std::string const& name, backend_factory const& factory)
297 {
298  scoped_lock lock(&mutex_);
299 
300  // unload the existing handler if it's already loaded
301 
302  do_unload(name);
303 
304  info new_entry;
305  new_entry.factory_ = &factory;
306 
307  factories_[name] = new_entry;
308 }
309 
310 SOCI_DECL std::vector<std::string> dynamic_backends::list_all()
311 {
312  scoped_lock lock(&mutex_);
313 
314  std::vector<std::string> ret;
315  ret.reserve(factories_.size());
316 
317  for (factory_map::iterator i = factories_.begin(); i != factories_.end(); ++i)
318  {
319  std::string const& name = i->first;
320  ret.push_back(name);
321  }
322 
323  return ret;
324 }
325 
326 SOCI_DECL void dynamic_backends::unload(std::string const& name)
327 {
328  scoped_lock lock(&mutex_);
329 
330  do_unload(name);
331 }
332 
334 {
335  scoped_lock lock(&mutex_);
336 
337  for (factory_map::iterator i = factories_.begin(); i != factories_.end(); ++i)
338  {
339  soci_handler_t h = i->second.handler_;
340  if (0 != h)
341  {
342  DLCLOSE(h);
343  }
344  }
345 
346  factories_.clear();
347 }
SOCI_DECL std::vector< std::string > list_all()
#define MUTEX_DEST(x)
SOCI_DECL std::vector< std::string > & search_paths()
#define LIBNAME(x)
pthread_mutex_t soci_mutex_t
SOCI_DECL void register_backend(std::string const &name, std::string const &shared_object=std::string())
#define MUTEX_INIT(x)
#define SOCI_DECL
Definition: soci-config.h:31
#define DLOPEN(x)
#define DLSYM(x, y)
#define DLCLOSE(x)
void * soci_handler_t
backend_factory const & get(std::string const &name)
#define UNLOCK(x)
#define LOCK(x)
SOCI_DECL void unload(std::string const &name)
SOCI_DECL void unload_all()


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:40