OpenWalnut  1.3.1
WSharedLib.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <cassert>
27 #include <string>
28 
29 #ifdef _WIN32
30  #include <iostream>
31  #include <windows.h> // NOLINT
32 #endif
33 
34 #include <boost/filesystem.hpp>
35 
36 #include "exceptions/WLibraryFetchFailed.h"
37 #include "exceptions/WLibraryLoadFailed.h"
38 #include "WSharedLib.h"
39 
40 #ifdef _WIN32
41 
42 /**
43  * Simple class holding an opened library.
44  */
45 struct WSharedLib::data
46 {
47  /**
48  * Path of lib.
49  */
50  const std::string m_path;
51 
52  /**
53  * Handle describing the loaded lib.
54  */
55  HMODULE m_hDLL;
56 
57  /**
58  * Constructor. Opens and loads the library.
59  *
60  * \see WSharedLib::WSharedLib for details.
61  *
62  * \param path the lib to open
63  */
64  explicit data( const std::string& path ):
65  m_path( path ),
66  m_hDLL( LoadLibrary( path.c_str() ) )
67  {
68  if( !m_hDLL )
69  {
70  throw WLibraryLoadFailed( std::string( "Could not load library \"" + m_path + "\" due to the error: " + errmsg() ) );
71  }
72  }
73 
74  /**
75  * Destructor. Closes the previously opened library handle.
76  */
77  ~data()
78  {
79  FreeLibrary( m_hDLL );
80  }
81 
82  /**
83  * Searches the lib for the specified function symbol and returns it.
84  *
85  * \param name the name of the function
86  *
87  * \return the pointer to the requested function
88  *
89  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
90  */
91  func_ptr_type findFunction( const std::string& name )
92  {
93  func_ptr_type func_ptr = reinterpret_cast< func_ptr_type >( GetProcAddress( m_hDLL, name.c_str() ) );
94  if( !func_ptr )
95  {
96  throw WLibraryFetchFailed( std::string( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + errmsg() ) );
97  }
98  return func_ptr;
99  }
100 
101  /**
102  * Searches the lib for the specified function symbol and returns it.
103  *
104  * \param name the name of the function
105  *
106  * \return the pointer to the requested function
107  *
108  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
109  */
110  void* findVariable( const std::string& name )
111  {
112  return reinterpret_cast< void* >( findFunction( name ) );
113  }
114 
115  /**
116  * Constructs a nice looking error message for the last error occurred.
117  *
118  * \return the last error message
119  */
120  static std::string errmsg()
121  {
122  std::string msg;
123  LPTSTR lpMsgBuf = 0;
124  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0,
125  reinterpret_cast< LPTSTR >( &lpMsgBuf ), 0, 0 );
126  LPTSTR p = lpMsgBuf;
127  while( *p )
128  {
129  msg.push_back( *p++ );
130  }
131  LocalFree( lpMsgBuf );
132  return msg;
133  }
134 };
135 #else
136 #include <dlfcn.h> // NOLINT
137 #include <pthread.h> // NOLINT
138 
139 namespace
140 {
141  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
142  struct auto_lock
143  {
144  auto_lock()
145  {
146  pthread_mutex_lock( &mutex );
147  }
148  ~auto_lock()
149  {
150  pthread_mutex_unlock( &mutex );
151  }
152  };
153 }
154 
155 /**
156  * Simple class holding an opened library.
157  */
159 {
160  /**
161  * Path of lib.
162  */
163  const std::string m_path;
164 
165  /**
166  * Handle describing the loaded lib.
167  */
168  void* m_dl;
169 
170  /**
171  * Destructor. Closes the previously opened library handle.
172  */
174  {
175  assert( dlclose( m_dl ) == 0 );
176  }
177 
178  /**
179  * Constructor. Opens and loads the library.
180  *
181  * \see WSharedLib::WSharedLib for details.
182  *
183  * \param path the lib to open
184  */
185  explicit data( const std::string& path )
186  : m_path( path ), m_dl( 0 )
187  {
188  auto_lock lock;
189  m_dl = dlopen( m_path.c_str(), RTLD_LAZY );
190  if( !m_dl )
191  {
192  throw WLibraryLoadFailed( std::string( "Could not load library \"" + m_path + "\" due to the error: " + dlerror() ) );
193  }
194  }
195 
196  /**
197  * Searches the lib for the specified function symbol and returns it.
198  *
199  * \param name the name of the function
200  *
201  * \return the pointer to the requested function
202  *
203  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
204  */
205  func_ptr_type findFunction( const std::string& name )
206  {
207  // This cast is supposed to throw a warning because the cast
208  // of void* to function pointers is not defined or required
209  // in ISO C. Nevertheless, it works on most current compilers.
210  //
211  // man dlsym talks about introducing a new function to circumvent
212  // this problem.
213  return reinterpret_cast< func_ptr_type >( findVariable( name ) );
214  }
215 
216  /**
217  * Searches the lib for the specified symbol and returns it.
218  *
219  * \param name the name of the symbol to search.
220  *
221  * \return pointer to the symbol.
222  *
223  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
224  *
225  */
226  void* findVariable( const std::string& name )
227  {
228  auto_lock lock;
229  dlerror();
230  void* variable_ptr = dlsym( m_dl, name.c_str() );
231  const char *err = dlerror();
232  if( err )
233  {
234  throw WLibraryFetchFailed( std::string( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + err ) );
235  }
236  return variable_ptr;
237  }
238 };
239 #endif
240 
241 WSharedLib::WSharedLib( boost::filesystem::path lib ):
242  m_data( new data( lib.string() ) )
243 {
244 }
245 
247  m_data( new data( rhs.m_data->m_path ) )
248 {
249 }
250 
252 {
253  delete m_data;
254 }
255 
257 {
258  WSharedLib o( rhs );
259  swap( *this, o );
260  return *this;
261 }
262 
263 void swap( WSharedLib& lhs, WSharedLib& rhs )
264 {
265  std::swap( lhs.m_data, rhs.m_data );
266 }
267 
268 WSharedLib::func_ptr_type WSharedLib::findFunction( const std::string& name ) const
269 {
270  return m_data->findFunction( name );
271 }
272 
273 void* WSharedLib::findVariable( const std::string& name ) const
274 {
275  return m_data->findVariable( name );
276 }
277 
279 {
280  return W_LIB_PREFIX;
281 }
282 
284 {
285  return W_LIB_SUFFIX;
286 }
287 
289 {
290  return "../lib";
291 }
292