xref: /petsc/src/sys/dll/dlimpl.c (revision 022afb99c29b2dbe6df8bc6699739c6dd2eaaddc)
1 
2 /*
3    Low-level routines for managing dynamic link libraries (DLLs).
4 */
5 
6 #include <petsc-private/petscimpl.h>
7 #include <petscvalgrind.h>
8 
9 /* XXX Should be done better !!!*/
10 #if !defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
11 #undef PETSC_HAVE_WINDOWS_H
12 #undef PETSC_HAVE_DLFCN_H
13 #endif
14 
15 #if defined(PETSC_HAVE_WINDOWS_H)
16 #include <windows.h>
17 #elif defined(PETSC_HAVE_DLFCN_H)
18 #include <dlfcn.h>
19 #endif
20 
21 #if defined(PETSC_HAVE_WINDOWS_H)
22 typedef HMODULE dlhandle_t;
23 typedef FARPROC dlsymbol_t;
24 #elif defined(PETSC_HAVE_DLFCN_H)
25 typedef void* dlhandle_t;
26 typedef void* dlsymbol_t;
27 #else
28 typedef void* dlhandle_t;
29 typedef void* dlsymbol_t;
30 #endif
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "PetscDLOpen"
34 /*@C
35    PetscDLOpen - opens dynamic library
36 
37    Not Collective
38 
39    Input Parameters:
40 +    name - name of library
41 -    mode - options on how to open library
42 
43    Output Parameter:
44 .    handle
45 
46    Level: developer
47 
48 @*/
49 PetscErrorCode  PetscDLOpen(const char name[],PetscDLMode mode,PetscDLHandle *handle)
50 {
51   PETSC_UNUSED int dlflags1,dlflags2; /* There are some preprocessor paths where these variables are set, but not used */
52   dlhandle_t       dlhandle;
53 
54   PetscFunctionBegin;
55   PetscValidCharPointer(name,1);
56   PetscValidPointer(handle,3);
57 
58   dlflags1 = 0;
59   dlflags2 = 0;
60   dlhandle = (dlhandle_t) 0;
61   *handle  = (PetscDLHandle) 0;
62 
63   /*
64      --- LoadLibrary ---
65   */
66 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_LOADLIBRARY)
67   dlhandle = LoadLibrary(name);
68   if (!dlhandle) {
69 #if defined(PETSC_HAVE_GETLASTERROR)
70     PetscErrorCode ierr;
71     DWORD          erc;
72     char           *buff = NULL;
73     erc = GetLastError();
74     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
75                   NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
76     ierr = PetscError(PETSC_COMM_SELF,__LINE__,__FUNCT__,__FILE__,PETSC_ERR_FILE_OPEN,PETSC_ERROR_REPEAT,
77                       "Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,buff);
78     LocalFree(buff);
79     PetscFunctionReturn(ierr);
80 #else
81     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from LoadLibrary() %s\n",name,"unavailable");
82 #endif
83   }
84 
85   /*
86      --- dlopen ---
87   */
88 #elif defined(PETSC_HAVE_DLFCN_H) && defined(PETSC_HAVE_DLOPEN)
89   /*
90       Mode indicates symbols required by symbol loaded with dlsym()
91      are only loaded when required (not all together) also indicates
92      symbols required can be contained in other libraries also opened
93      with dlopen()
94   */
95 #if defined(PETSC_HAVE_RTLD_LAZY)
96   dlflags1 = RTLD_LAZY;
97 #endif
98 #if defined(PETSC_HAVE_RTLD_NOW)
99   if (mode & PETSC_DL_NOW) dlflags1 = RTLD_NOW;
100 #endif
101 #if defined(PETSC_HAVE_RTLD_GLOBAL)
102   dlflags2 = RTLD_GLOBAL;
103 #endif
104 #if defined(PETSC_HAVE_RTLD_LOCAL)
105   if (mode & PETSC_DL_LOCAL) dlflags2 = RTLD_LOCAL;
106 #endif
107 #if defined(PETSC_HAVE_DLERROR)
108   dlerror(); /* clear any previous error */
109 #endif
110   dlhandle = dlopen(name,dlflags1|dlflags2);
111   if (!dlhandle) {
112 #if defined(PETSC_HAVE_DLERROR)
113     const char *errmsg = dlerror();
114 #else
115     const char *errmsg = "unavailable";
116 #endif
117     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n  %s\n  Error message from dlopen() %s\n",name,errmsg);
118   }
119 
120   /*
121      --- unimplemented ---
122   */
123 #else
124   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
125 #endif
126 
127   *handle = (PetscDLHandle) dlhandle;
128   PetscFunctionReturn(0);
129 }
130 
131 
132 #undef __FUNCT__
133 #define __FUNCT__ "PetscDLClose"
134 /*@C
135    PetscDLClose -  closes a dynamic library
136 
137    Not Collective
138 
139   Input Parameter:
140 .   handle - the handle for the library obtained with PetscDLOpen()
141 
142   Level: developer
143 @*/
144 PetscErrorCode  PetscDLClose(PetscDLHandle *handle)
145 {
146 
147   PetscFunctionBegin;
148   PetscValidPointer(handle,1);
149 
150   /*
151      --- FreeLibrary ---
152   */
153 #if defined(PETSC_HAVE_WINDOWS_H)
154 #if defined(PETSC_HAVE_FREELIBRARY)
155   if (FreeLibrary((dlhandle_t)*handle) == 0) {
156 #if defined(PETSC_HAVE_GETLASTERROR)
157     char  *buff = NULL;
158     DWORD erc   = GetLastError();
159     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
160     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n",buff);
161     LocalFree(buff);
162 #else
163     PetscErrorPrintf("Error closing dynamic library:\n  Error message from FreeLibrary() %s\n","unavailable");
164 #endif
165   }
166 #endif /* !PETSC_HAVE_FREELIBRARY */
167 
168   /*
169      --- dclose ---
170   */
171 #elif defined(PETSC_HAVE_DLFCN_H)
172 #if defined(PETSC_HAVE_DLCLOSE)
173 #if defined(PETSC_HAVE_DLERROR)
174   dlerror(); /* clear any previous error */
175 #endif
176   if (dlclose((dlhandle_t)*handle) < 0) {
177 #if defined(PETSC_HAVE_DLERROR)
178     const char *errmsg = dlerror();
179 #else
180     const char *errmsg = "unavailable";
181 #endif
182     PetscErrorPrintf("Error closing dynamic library:\n  Error message from dlclose() %s\n", errmsg);
183   }
184 #endif /* !PETSC_HAVE_DLCLOSE */
185 
186   /*
187      --- unimplemented ---
188   */
189 #else
190   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
191 #endif
192 
193   *handle = NULL;
194   PetscFunctionReturn(0);
195 }
196 
197 #undef __FUNCT__
198 #define __FUNCT__ "PetscDLSym"
199 /*@C
200    PetscDLSym - finds a symbol in a dynamic library
201 
202    Not Collective
203 
204    Input Parameters:
205 +   handle - obtained with PetscDLOpen() or NULL
206 -   symbol - name of symbol
207 
208    Output Parameter:
209 .   value - pointer to the function, NULL if not found
210 
211    Level: developer
212 
213   Notes:
214    If handle is NULL, the symbol is looked for in the main executable's dynamic symbol table.
215    In order to be dynamically loadable, the symbol has to be exported as such.  On many UNIX-like
216    systems this requires platform-specific linker flags.
217 
218 @*/
219 PetscErrorCode  PetscDLSym(PetscDLHandle handle,const char symbol[],void **value)
220 {
221   PETSC_UNUSED dlhandle_t dlhandle;
222   dlsymbol_t              dlsymbol;
223 
224   PetscValidCharPointer(symbol,2);
225   PetscValidPointer(value,3);
226 
227   dlhandle = (dlhandle_t) 0;
228   dlsymbol = (dlsymbol_t) 0;
229   *value   = (void*) 0;
230 
231   /*
232      --- GetProcAddress ---
233   */
234 #if defined(PETSC_HAVE_WINDOWS_H)
235 #if defined(PETSC_HAVE_GETPROCADDRESS)
236   if (handle) dlhandle = (dlhandle_t) handle;
237   else dlhandle = (dlhandle_t) GetCurrentProcess();
238   dlsymbol = (dlsymbol_t) GetProcAddress(dlhandle,symbol);
239 #if defined(PETSC_HAVE_SETLASTERROR)
240   SetLastError((DWORD)0); /* clear any previous error */
241 #endif
242 #endif /* !PETSC_HAVE_GETPROCADDRESS */
243 
244   /*
245      --- dlsym ---
246   */
247 #elif defined(PETSC_HAVE_DLFCN_H)
248 #if defined(PETSC_HAVE_DLSYM)
249   if (handle) dlhandle = (dlhandle_t) handle;
250   else {
251 
252 #if defined(PETSC_HAVE_DLOPEN) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES)
253     /* Attempt to retrieve the main executable's dlhandle. */
254     { int dlflags1 = 0, dlflags2 = 0;
255 #if defined(PETSC_HAVE_RTLD_LAZY)
256       dlflags1 = RTLD_LAZY;
257 #endif
258       if (!dlflags1) {
259 #if defined(PETSC_HAVE_RTLD_NOW)
260         dlflags1 = RTLD_NOW;
261 #endif
262       }
263 #if defined(PETSC_HAVE_RTLD_LOCAL)
264       dlflags2 = RTLD_LOCAL;
265 #endif
266       if (!dlflags2) {
267 #if defined(PETSC_HAVE_RTLD_GLOBAL)
268         dlflags2 = RTLD_GLOBAL;
269 #endif
270       }
271 #if defined(PETSC_HAVE_DLERROR)
272       if (!(PETSC_RUNNING_ON_VALGRIND)) {
273         dlerror(); /* clear any previous error; valgrind does not like this */
274       }
275 #endif
276       /* Attempt to open the main executable as a dynamic library. */
277 #if defined(PETSC_HAVE_RTDL_DEFAULT)
278       dlhandle = RTLD_DEFAULT;
279 #else
280       dlhandle = dlopen(0, dlflags1|dlflags2);
281 #if defined(PETSC_HAVE_DLERROR)
282       { const char *e = (const char*) dlerror();
283         if (e) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Error opening main executable as a dynamic library:\n  Error message from dlopen(): '%s'\n", e);
284       }
285 #endif
286 #endif
287     }
288 #endif
289 #endif /* PETSC_HAVE_DLOPEN && PETSC_HAVE_DYNAMIC_LIBRARIES */
290   }
291 #if defined(PETSC_HAVE_DLERROR)
292   dlerror(); /* clear any previous error */
293 #endif
294   dlsymbol = (dlsymbol_t) dlsym(dlhandle,symbol);
295   /*
296      --- unimplemented ---
297   */
298 #else
299   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS, "Cannot use dynamic libraries on this platform");
300 #endif
301 
302   *value = *((void**)&dlsymbol);
303 
304 #if defined(PETSC_SERIALIZE_FUNCTIONS)
305   if (*value) {
306     PetscErrorCode ierr;
307     ierr = PetscFPTAdd(*value,symbol);CHKERRQ(ierr);
308   }
309 #endif
310   return(0);
311 }
312