/[ascend]/trunk/base/generic/utilities/ascDynaLoad.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/ascDynaLoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 478 - (show annotations) (download) (as text)
Mon Apr 17 08:10:48 2006 UTC (14 years, 2 months ago) by johnpye
File MIME type: text/x-csrc
File size: 14603 byte(s)
Fixing build for SWIG 1.3.24 (no -O flag)
Adding more debug info to loading output in PyGTK interface/config.py.in
Adding SWIGVERSION flag to SCons env.
Commenting in ascDynaLoad.c and ascParse.y
Adding VERSION to config.py
1 /* ASCEND modelling environment
2 Copyright (C) 2006 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 */
19 /*
20 This file *should* support unix/linux-style systems (dlfcn.h)
21 and Windows.
22
23 Note that under many systems, profiling does not work
24 with dynamic libraries!
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include "ascConfig.h"
31 #include "error.h"
32 #include "ascPrint.h"
33 #include "ascPanic.h"
34 #include "ascMalloc.h"
35 #include "ascDynaLoad.h"
36
37 #include <compiler/instance_enum.h>
38 #include <general/list.h>
39 #include <compiler/compiler.h>
40 #include <compiler/extfunc.h>
41
42 typedef int (*ExternalLibraryRegister_fptr_t)(void);
43
44 /*--------------------------------------
45 GENERIC STUFF
46 */
47
48 struct ascend_dlrecord {
49 char *path; /* library name */
50 void *dlreturn; /* return from dlopen */
51 struct ascend_dlrecord *next;
52 };
53
54 /* Linked list of library names & dlopen() return values. */
55 static
56 struct ascend_dlrecord *g_ascend_dllist = NULL;
57
58 /*
59 * Adds a record of the path and handle to the list.
60 * If it fails to do this, returns 1, else 0.
61 */
62 static
63 int AscAddRecord(void *dlreturn, CONST char *path)
64 {
65 struct ascend_dlrecord *new;
66 char *keeppath;
67 if (dlreturn == NULL || path == NULL) {
68 return 1;
69 }
70 keeppath = ascstrdup((char *)path);
71 if (keeppath==NULL) return 1;
72 new = (struct ascend_dlrecord *)ascmalloc(sizeof(struct ascend_dlrecord));
73 if (new==NULL) {
74 ascfree(keeppath);
75 return 1;
76 }
77 new->next = g_ascend_dllist; /* insert at head */
78 g_ascend_dllist = new;
79 new->path = keeppath;
80 new->dlreturn = dlreturn;
81 return 0;
82 }
83
84 /*
85 * Finds a record of the path given and returns the associated handle.
86 * If it fails to do this, returns NULL.
87 */
88 static
89 void *AscFindDLRecord(CONST char *path)
90 {
91 struct ascend_dlrecord *new;
92 if (path == NULL) {
93 return NULL;
94 }
95 new = g_ascend_dllist;
96 while (new != NULL && strcmp(new->path,path) != 0) {
97 /* advance new until no more new or new with path found */
98 new = new->next;
99 }
100 return (new != NULL) ? new->dlreturn : NULL;
101 }
102
103 /*
104 * Finds and returns the handle to path, if one matches, and
105 * deletes the record from the list. Returns NULL if not found.
106 */
107 static
108 void *AscDeleteRecord(CONST char *path)
109 {
110 struct ascend_dlrecord *nextptr, *lastptr, *old;
111 void *dlreturn = NULL;
112
113 if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL;
114
115 if (strcmp(path,g_ascend_dllist->path)==0) {
116 /* head case */
117 old = g_ascend_dllist;
118 g_ascend_dllist = old->next;
119 dlreturn = old->dlreturn;
120 ascfree(old->path);
121 ascfree(old);
122 } else {
123 lastptr = g_ascend_dllist;
124 nextptr = lastptr->next;
125 while (nextptr != NULL && strcmp(nextptr->path,path) != 0) {
126 lastptr = nextptr;
127 nextptr = nextptr->next;
128 }
129 /* so either nextptr is NULL and not in list, or nextptr is
130 * what we want to delete and lastptr is the link to it.
131 */
132 if (nextptr != NULL) {
133 old = nextptr;
134 lastptr->next = nextptr->next;
135 dlreturn = old->dlreturn;
136 ascfree(old->path);
137 ascfree(old);
138 }
139 }
140 return dlreturn;
141 }
142
143 /*
144 * Checks the list for a conflicting handle so we can issue
145 * a more helpful warning, if need be, than the standard message.
146 */
147 static
148 void AscCheckDuplicateLoad(CONST char *path)
149 {
150 struct ascend_dlrecord *r;
151
152 if (NULL == path) {
153 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Null path in AscCheckDuplicateLoad.");
154 return;
155 }
156
157 r = g_ascend_dllist;
158 while (r != NULL) {
159 if (strcmp(path,r->path)==0) {
160 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Attempt to load already loaded '%s'.",path);
161 return;
162 }
163 r = r->next;
164 }
165 }
166
167 /*-----------------------------------------------
168 WINDOWS
169 */
170 #if defined(__WIN32__)
171 # include <windows.h>
172
173 int DLEXPORT Asc_DynamicLoad(CONST char *path, CONST char *initFun)
174 {
175 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
176 HINSTANCE xlib;
177 ExternalLibraryRegister_fptr_t install = NULL;
178
179 if (NULL == path) {
180 FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
181 return 1;
182 }
183
184 AscCheckDuplicateLoad(path); /* whine if we've see it before */
185 /*
186 * If the named library does not exist, if it's not loadable or if
187 * it does not define the named install proc, report an error
188 */
189
190 xlib = LoadLibrary(path);
191 if (xlib == NULL) {
192 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: LoadLibrary failed\n");
193 return 1;
194 }
195 if (NULL != initFun) {
196 install = (int (*)())GetProcAddress(xlib,initFun);
197 if (install == NULL) {
198 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: Required function %s not found\n", initFun);
199 (void)FreeLibrary(xlib);
200 return 1;
201 }else{
202 FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install);
203 }
204 }
205 if (0 != AscAddRecord(xlib,path)) {
206 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
207 }
208 return (install == NULL) ? 0 : (*install)();
209 }
210
211 # define UNLOAD FreeLibrary
212 # define DLLSYM GetProcAddress
213 # define DLL_CAST (HINSTANCE)
214 # define ASC_DLERRSTRING "unknown"
215 # define UNLOAD_SUCCESS TRUE
216
217 #endif /* __WIN32__ */
218
219 /*-----------------------------------------------
220 UNIX/LINUX
221 */
222 /*
223 SOLARIS and LINUX
224 */
225 /* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */
226 /*
227 From a quick Google, it appears that AIX 5.1 now provides dlfcn.h,
228 so I'll remove the code that was emulating it here. -- johnpye
229 */
230 #if (defined(sun) || defined(linux) || defined(__unix__) || defined(solaris) || defined(_AIX) || defined(_SGI_SOURCE))
231 # ifndef MACH
232 # include <dlfcn.h>
233 # else
234 # error "MACH unsupported"
235 # endif /* mach */
236
237 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
238 {
239 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
240 void *xlib;
241 ExternalLibraryRegister_fptr_t install = NULL;
242
243 if (NULL == path) {
244 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
245 return 1;
246 }
247
248 AscCheckDuplicateLoad(path); /* whine if we've see it before */
249
250 /*
251 * If the named library does not exist, if it's not loadable or if
252 * it does not define the named install proc, report an error
253 */
254 xlib = dlopen(path, 1);
255 if (xlib == NULL) {
256 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
257 return 1;
258 }
259 if (NULL != initFun) {
260 install = (int (*)())dlsym(xlib, initFun);
261 if (install == NULL) {
262 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
263 dlclose(xlib);
264 return 1;
265 }
266 }
267
268 if (0 != AscAddRecord(xlib,path)) {
269 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
270 }
271 return (install == NULL) ? 0 : (*install)();
272 }
273
274 # define UNLOAD dlclose
275 # define DLLSYM dlsym
276 # define DLL_CAST (void *)
277 # define ASC_DLERRSTRING dlerror()
278 # define UNLOAD_SUCCESS 0
279
280 #endif /* posix: linux, unix, solaris,sgi */
281
282 /*-----------------------------------------------
283 HPUX
284 */
285 #ifdef __hpux
286 /*
287 Kirk Abbott last fiddled with the following, which was
288 originally put in place my Michael Moore for an
289 HP/UX 9.X Operating Sys back in 1993. Arrr. No idea if
290 it still works.
291 */
292
293 # include <dl.h>
294 # include <errno.h>
295
296 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
297 {
298 # define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
299 shl_t xlib;
300 ExternalLibraryRegister_fptr_t install = NULL;
301 int i;
302
303 if (NULL == path) {
304 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
305 return 1;
306 }
307
308 AscCheckDuplicateLoad(path); /* whine if we've see it before */
309
310 /*
311 * If the named library does not exist, if it's not loadable or if
312 * it does not define the named install proc, report an error
313 */
314 xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
315 if (xlib == (shl_t) NULL) {
316 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to load shared library : %s\n",strerror(errno));
317 return 1;
318 }
319 if (NULL != initFun) {
320 i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
321 if (i == -1) {
322 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to find needed symbol %s %s\n",
323 initFun, strerror(errno));
324 shl_unload(xlib); /* baa */
325 return 1;
326 }
327 if (install == NULL) {
328 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to find needed symbol %s\n",initFun);
329 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type unknown\n");
330 shl_unload(xlib); /* baa */
331 return 1;
332 }
333 }
334 if (0 != AscAddRecord(xlib,path)) {
335 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
336 }
337 return (install == NULL) ? 0 : (*install)();
338 }
339
340 # define UNLOAD shl_unload
341 # define DLL_CAST (shl_t)
342 # define ASC_DLERRSTRING "NULL definition"
343 # define UNLOAD_SUCCESS 0
344
345 #endif /* __hpux */
346
347 /*-----------------------------------------------
348 Did we get something from the above?
349 */
350
351 #ifndef ASCDL_OK
352 # error "Unable to define an Asc_DynamicLoad function. Check your compiler options and installed system libraries."
353 #endif
354
355 /**-----------------------------------------------
356 DYNAMIC UNLOADING
357 */
358
359 int Asc_DynamicUnLoad(CONST char *path)
360 {
361 void *dlreturn;
362 int retval;
363
364 if (NULL == path) {
365 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad failed: Null path\n");
366 return -3;
367 }
368
369 dlreturn = AscDeleteRecord(path);
370 if (dlreturn == NULL) {
371 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad: unable to remember or unload %s\n", path);
372 return -3;
373 }
374 CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s \n", path);
375 /*
376 * dlclose() returns 0 on success, FreeLibrary() returns TRUE.
377 * A uniform convention is preferable, so trap and return 0 on success.
378 */
379 retval = UNLOAD(DLL_CAST dlreturn);
380 return (retval == UNLOAD_SUCCESS) ? 0 : retval;
381 }
382
383 /**-----------------------------------------------
384 DYNAMIC VARIABLE LINKING
385 */
386 void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol)
387 {
388 void *dlreturn;
389 void *symreturn;
390 #ifdef __hpux
391 int i;
392 #endif
393
394 if (libname == NULL) {
395 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null libname\n");
396 return NULL;
397 }
398 if (symbol == NULL) {
399 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null symbol\n");
400 return NULL;
401 }
402
403 dlreturn = AscFindDLRecord(libname);
404 if (dlreturn == NULL) {
405 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested library %s\n", libname);
406 return NULL;
407 }
408 #ifdef __hpux
409 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
410 if (i == -1) {
411 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested symbol %s in %s (%s)\n",
412 symbol, libname, strerror(errno));
413 symreturn = NULL;
414 }
415 #elif defined(__WIN32__)
416 /*
417 * Here's a bit of possibly-misdirected casting horror.
418 * ISO C forbids casting between function and data pointers, so, naturally,
419 * we cast between function and data pointers. Well, we don't have much
420 * choice. GetProcAddress() returns a function pointer for both functions
421 * and variables so we have to do the cast for variables. This is ok on
422 * 32 bit Windows since the pointers are compatible. Then, to avoid
423 * being reminded by the compiler that we're doing something illegal,
424 * we apply convoluted casting to shut it up.
425 * Oh, the crap you can find on the internet... JDS
426 */
427 *(FARPROC*)(&symreturn) = GetProcAddress((HINSTANCE)dlreturn, symbol);
428 #else
429 /* no problem on POSIX systems - dlsym() returns a void *. */
430 symreturn = dlsym(dlreturn, symbol);
431 #endif
432 if (symreturn == NULL) {
433 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested symbol %s in %s\n",symbol,libname);
434 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type %s\n",ASC_DLERRSTRING);
435 }
436 return symreturn;
437 }
438
439 /**-----------------------------------------------
440 DYNAMIC FUNCTION LINKING
441 */
442 DynamicF Asc_DynamicFunction(CONST char *libname, CONST char *symbol)
443 {
444 void *dlreturn;
445 DynamicF symreturn;
446 #ifdef __hpux
447 int i;
448 #endif
449
450 if (libname == NULL) {
451 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null library name\n");
452 return NULL;
453 }
454 if (symbol == NULL) {
455 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null function name\n");
456 return NULL;
457 }
458
459 dlreturn = AscFindDLRecord(libname);
460 if (dlreturn == NULL) {
461 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested library %s\n", libname);
462 return NULL;
463 }
464 #ifdef __hpux
465 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
466 if (i == -1) {
467 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested function %s in %s (%s)\n",
468 symbol, libname, strerror(errno));
469 symreturn = NULL;
470 }
471 #elif defined(__WIN32__)
472 /* no problem on Windows - GetProcAddress() returns a function pointer. */
473 symreturn = (DynamicF)GetProcAddress((HINSTANCE)dlreturn, symbol);
474 #else
475 /*
476 * Here's the corresponding bit of possibly-misdirected casting horror.
477 * ISO C forbids casting between function and data pointers, so, naturally,
478 * we cast between function and data pointers. Well, we don't have much
479 * choice. dlsym() returns a void* for both variables and functions so we
480 * have to do the cast for functions. This is ok on POSIX systems since the
481 * pointer types are compatible. Then, to avoid being reminded by the
482 * compiler that we're doing something illegal, we apply convoluted casting
483 * to shut it up. Oh, the crap you can find on the internet... JDS
484 */
485 *(void**)(&symreturn) = dlsym(dlreturn, symbol);
486 #endif
487 if (symreturn == NULL) {
488 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested function %s in %s\n",symbol,libname);
489 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type %s\n",ASC_DLERRSTRING);
490 }
491 return symreturn;
492 }
493

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22