Actual source code: dl.c
1: #define PETSC_DLL
2: /*
3: Routines for opening dynamic link libraries (DLLs), keeping a searchable
4: path of DLLs, obtaining remote DLLs via a URL and opening them locally.
5: */
7: #include petsc.h
8: #include petscsys.h
9: #include "petscfix.h"
11: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
13: #if defined(PETSC_HAVE_PWD_H)
14: #include <pwd.h>
15: #endif
16: #include <ctype.h>
17: #include <sys/types.h>
18: #include <sys/stat.h>
19: #if defined(PETSC_HAVE_UNISTD_H)
20: #include <unistd.h>
21: #endif
22: #if defined(PETSC_HAVE_STDLIB_H)
23: #include <stdlib.h>
24: #endif
25: #if defined(PETSC_HAVE_SYS_UTSNAME_H)
26: #include <sys/utsname.h>
27: #endif
28: #if defined(PETSC_HAVE_WINDOWS_H)
29: #include <windows.h>
30: #endif
31: #include <fcntl.h>
32: #include <time.h>
33: #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
34: #include <sys/systeminfo.h>
35: #endif
37: #endif
39: #include "petscfix.h"
42: /*
43: Contains the list of registered CCA components
44: */
45: PetscFList CCAList = 0;
48: /* ------------------------------------------------------------------------------*/
49: /*
50: Code to maintain a list of opened dynamic libraries and load symbols
51: */
52: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
53: #if defined(PETSC_HAVE_DLFCN_H)
54: #include <dlfcn.h>
55: #endif
56: struct _n_PetscDLLibrary {
57: PetscDLLibrary next;
58: void *handle;
59: char libname[PETSC_MAX_PATH_LEN];
60: };
63: EXTERN PetscErrorCode Petsc_DelTag(MPI_Comm,int,void*,void*);
68: PetscErrorCode PetscDLLibraryPrintPath(void)
69: {
70: PetscDLLibrary libs;
73: libs = DLLibrariesLoaded;
74: while (libs) {
75: PetscErrorPrintf(" %s\n",libs->libname);
76: libs = libs->next;
77: }
78: return(0);
79: }
83: /*@C
84: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
85: (if it is remote), indicates if it exits and its local name.
87: Collective on MPI_Comm
89: Input Parameters:
90: + comm - processors that are opening the library
91: - libname - name of the library, can be relative or absolute
93: Output Parameter:
94: . handle - library handle
96: Level: developer
98: Notes:
99: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
101: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
102: occuring in directoryname and filename will be replaced with appropriate values.
103: @*/
104: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,int llen,PetscTruth *found)
105: {
106: char *par2,buff[10],*en,*gz;
108: size_t len1,len2,len;
109: PetscTruth tflg,flg;
112: /*
113: make copy of library name and replace $PETSC_ARCH and and
114: so we can add to the end of it to look for something like .so.1.0 etc.
115: */
116: PetscStrlen(libname,&len);
117: len = PetscMax(4*len,PETSC_MAX_PATH_LEN);
118: PetscMalloc(len*sizeof(char),&par2);
119: PetscStrreplace(comm,libname,par2,len);
121: /*
122: Remove any file: header
123: */
124: PetscStrncmp(par2,"file:",5,&tflg);
125: if (tflg) {
126: PetscStrcpy(par2,par2+5);
127: }
129: /* strip out .a from it if user put it in by mistake */
130: PetscStrlen(par2,&len);
131: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
133: /* remove .gz if it ends library name */
134: PetscStrstr(par2,".gz",&gz);
135: if (gz) {
136: PetscStrlen(gz,&len);
137: if (len == 3) {
138: *gz = 0;
139: }
140: }
142: /* see if library name does already not have suffix attached */
143: PetscStrcpy(buff,".");
144: PetscStrcat(buff,PETSC_SLSUFFIX);
145: PetscStrstr(par2,buff,&en);
146: if (en) {
147: PetscStrlen(en,&len1);
148: PetscStrlen(PETSC_SLSUFFIX,&len2);
149: flg = (PetscTruth) (len1 != 1 + len2);
150: } else {
151: flg = PETSC_TRUE;
152: }
153: if (flg) {
154: PetscStrcat(par2,".");
155: PetscStrcat(par2,PETSC_SLSUFFIX);
156: }
158: /* put the .gz back on if it was there */
159: if (gz) {
160: PetscStrcat(par2,".gz");
161: }
163: PetscFileRetrieve(comm,par2,lname,llen,found);
164: PetscFree(par2);
165: return(0);
166: }
171: /*@C
172: PetscDLLibraryOpen - Opens a dynamic link library
174: Collective on MPI_Comm
176: Input Parameters:
177: + comm - processors that are opening the library
178: - libname - name of the library, can be relative or absolute
180: Output Parameter:
181: . handle - library handle
183: Level: developer
185: Notes:
186: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
188: ${PETSC_ARCH} occuring in directoryname and filename
189: will be replaced with the appropriate value.
190: @*/
191: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char libname[],void **handle)
192: {
194: char *par2,registername[128],*ptr,*ptrp;
195: PetscTruth foundlibrary;
196: PetscErrorCode (*func)(const char*) = NULL;
197: size_t len;
200: *handle = NULL;
201: PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&par2);
202: PetscDLLibraryRetrieve(comm,libname,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
203: if (!foundlibrary) {
204: SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",libname);
205: }
207: /* Eventually config/configure.py should determine if the system needs an executable dynamic library */
208: #define PETSC_USE_NONEXECUTABLE_SO
209: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
210: PetscTestFile(par2,'x',&foundlibrary);
211: if (!foundlibrary) {
212: SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",libname,par2);
213: }
214: #endif
216: /*
217: Mode indicates symbols required by symbol loaded with dlsym()
218: are only loaded when required (not all together) also indicates
219: symbols required can be contained in other libraries also opened
220: with dlopen()
221: */
222: PetscInfo1(0,"Opening %s\n",libname);
223: #if defined(PETSC_HAVE_LOADLIBRARY)
224: *handle = LoadLibrary(par2);
225: #else
226: #if defined(PETSC_HAVE_RTLD_GLOBAL)
227: *handle = dlopen(par2,RTLD_LAZY | RTLD_GLOBAL);
228: #else
229: *handle = dlopen(par2,RTLD_LAZY);
230: #endif
231: #endif
232: if (!*handle) {
233: #if defined(PETSC_HAVE_DLERROR)
234: SETERRQ3(PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n %s\n Error message from dlopen() %s\n",libname,par2,dlerror());
235: #elif defined(PETSC_HAVE_GETLASTERROR)
236: {
237: DWORD erc;
238: char *buff;
239: erc = GetLastError();
240: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
241: NULL,erc,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&buff,0,NULL);
242: PetscError(__LINE__,__FUNCT__,__FILE__,__SDIR__,PETSC_ERR_FILE_OPEN,1,
243: "Unable to open dynamic library:\n %s\n %s\n Error message from LoadLibrary() %s\n",libname,par2,buff);
244: LocalFree(buff);
245: return(ierr);
246: }
247: #endif
248: }
250: /* build name of symbol to look for based on libname */
251: PetscStrcpy(registername,"PetscDLLibraryRegister_");
252: /* look for libXXXXX.YYY and extract out the XXXXXX */
253: PetscStrrstr(libname,"lib",&ptr);
254: if (!ptr) SETERRQ1(PETSC_ERR_ARG_WRONG,"Dynamic library name must have lib prefix:%s",libname);
255: PetscStrchr(ptr+3,'.',&ptrp);
256: if (ptrp) {
257: len = ptrp - ptr - 3;
258: } else {
259: PetscStrlen(ptr+3,&len);
260: }
261: PetscStrncat(registername,ptr+3,len);
263: #if defined(PETSC_HAVE_GETPROCADDRESS)
264: func = (PetscErrorCode (*)(const char *)) GetProcAddress((HMODULE)*handle,registername);
265: #else
266: func = (PetscErrorCode (*)(const char *)) dlsym(*handle,registername);
267: #endif
268: if (func) {
269: (*func)(libname);
270: PetscInfo1(0,"Loading registered routines from %s\n",libname);
271: } else {
272: SETERRQ2(PETSC_ERR_FILE_UNEXPECTED,"Able to locate dynamic library %s, but cannot load symbol %s\n",libname,registername);
273: }
274: PetscFree(par2);
275: return(0);
276: }
280: /*@C
281: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
283: Collective on MPI_Comm
285: Input Parameter:
286: + comm - communicator that will open the library
287: . inlist - list of already open libraries that may contain symbol (checks here before path)
288: . path - optional complete library name
289: - insymbol - name of symbol
291: Output Parameter:
292: . value
294: Level: developer
296: Notes: Symbol can be of the form
297: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
299: Will attempt to (retrieve and) open the library if it is not yet been opened.
301: @*/
302: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibrary *inlist,const char path[],const char insymbol[],void **value)
303: {
304: char *par1,*symbol;
306: size_t len;
307: PetscDLLibrary nlist,prev,list;
310: if (inlist) list = *inlist; else list = PETSC_NULL;
311: *value = 0;
313: /* make copy of symbol so we can edit it in place */
314: PetscStrlen(insymbol,&len);
315: PetscMalloc((len+1)*sizeof(char),&symbol);
316: PetscStrcpy(symbol,insymbol);
318: /*
319: If symbol contains () then replace with a NULL, to support functionname()
320: */
321: PetscStrchr(symbol,'(',&par1);
322: if (par1) *par1 = 0;
325: /*
326: Function name does include library
327: -------------------------------------
328: */
329: if (path && path[0] != '\0') {
330: void *handle;
331:
332: /*
333: Look if library is already opened and in path
334: */
335: nlist = list;
336: prev = 0;
337: while (nlist) {
338: PetscTruth match;
340: PetscStrcmp(nlist->libname,path,&match);
341: if (match) {
342: handle = nlist->handle;
343: goto done;
344: }
345: prev = nlist;
346: nlist = nlist->next;
347: }
348: PetscDLLibraryOpen(comm,path,&handle);
350: PetscNew(struct _n_PetscDLLibrary,&nlist);
351: nlist->next = 0;
352: nlist->handle = handle;
353: PetscStrcpy(nlist->libname,path);
355: if (prev) {
356: prev->next = nlist;
357: } else {
358: if (inlist) *inlist = nlist;
359: else {PetscDLLibraryClose(nlist);}
360: }
361: PetscInfo1(0,"Appending %s to dynamic library search path\n",path);
363: done:;
364: #if defined(PETSC_HAVE_GETPROCADDRESS)
365: *value = GetProcAddress((HMODULE)handle,symbol);
366: #else
367: *value = dlsym(handle,symbol);
368: #endif
369: if (!*value) {
370: SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
371: }
372: PetscInfo2(0,"Loading function %s from dynamic library %s\n",insymbol,path);
374: /*
375: Function name does not include library so search path
376: -----------------------------------------------------
377: */
378: } else {
379: while (list) {
380: #if defined(PETSC_HAVE_GETPROCADDRESS)
381: *value = GetProcAddress((HMODULE)list->handle,symbol);
382: #else
383: *value = dlsym(list->handle,symbol);
384: #endif
385: if (*value) {
386: PetscInfo2(0,"Loading function %s from dynamic library %s\n",symbol,list->libname);
387: break;
388: }
389: list = list->next;
390: }
391: if (!*value) {
392: #if defined(PETSC_HAVE_GETPROCADDRESS)
393: *value = GetProcAddress(GetCurrentProcess(),symbol);
394: #else
395: *value = dlsym(0,symbol);
396: #endif
397: if (*value) {
398: PetscInfo1(0,"Loading function %s from object code\n",symbol);
399: }
400: }
401: }
403: PetscFree(symbol);
404: return(0);
405: }
409: /*@C
410: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
411: of the search path.
413: Collective on MPI_Comm
415: Input Parameters:
416: + comm - MPI communicator
417: - libname - name of the library
419: Output Parameter:
420: . outlist - list of libraries
422: Level: developer
424: Notes: if library is already in path will not add it.
425: @*/
426: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
427: {
428: PetscDLLibrary list,prev;
429: void* handle;
431: size_t len;
432: PetscTruth match,dir;
433: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
434: PetscToken *token;
438: /* is libname a directory? */
439: PetscTestDirectory(libname,'r',&dir);
440: if (dir) {
441: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);
442: PetscStrcpy(program,libname);
443: PetscStrlen(program,&len);
444: if (program[len-1] == '/') {
445: PetscStrcat(program,"*.");
446: } else {
447: PetscStrcat(program,"/*.");
448: }
449: PetscStrcat(program,PETSC_SLSUFFIX);
451: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
452: if (!dir) return(0);
453: found = buf;
454: } else {
455: found = (char*)libname;
456: }
457: PetscStrcpy(suffix,".");
458: PetscStrcat(suffix,PETSC_SLSUFFIX);
460: PetscTokenCreate(found,'\n',&token);
461: PetscTokenFind(token,&libname1);
462: PetscStrstr(libname1,suffix,&s);
463: if (s) s[0] = 0;
464: while (libname1) {
466: /* see if library was already open then we are done */
467: list = prev = *outlist;
468: match = PETSC_FALSE;
469: while (list) {
471: PetscStrcmp(list->libname,libname1,&match);
472: if (match) break;
473: prev = list;
474: list = list->next;
475: }
476: if (!match) {
478: PetscDLLibraryOpen(comm,libname1,&handle);
480: PetscNew(struct _n_PetscDLLibrary,&list);
481: list->next = 0;
482: list->handle = handle;
483: PetscStrcpy(list->libname,libname1);
485: if (!*outlist) {
486: *outlist = list;
487: } else {
488: prev->next = list;
489: }
490: PetscInfo1(0,"Appending %s to dynamic library search path\n",libname1);
491: }
492: PetscTokenFind(token,&libname1);
493: if (libname1) {
494: PetscStrstr(libname1,suffix,&s);
495: if (s) s[0] = 0;
496: }
497: }
498: PetscTokenDestroy(token);
499: return(0);
500: }
504: /*@C
505: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
506: the search path.
508: Collective on MPI_Comm
510: Input Parameters:
511: + comm - MPI communicator
512: - libname - name of the library
514: Output Parameter:
515: . outlist - list of libraries
517: Level: developer
519: Notes: If library is already in path will remove old reference.
521: @*/
522: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibrary *outlist,const char libname[])
523: {
524: PetscDLLibrary list,prev;
525: void* handle;
527: size_t len;
528: PetscTruth match,dir;
529: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
530: PetscToken *token;
533:
534: /* is libname a directory? */
535: PetscTestDirectory(libname,'r',&dir);
536: if (dir) {
537: PetscInfo1(0,"Checking directory %s for dynamic libraries\n",libname);
538: PetscStrcpy(program,libname);
539: PetscStrlen(program,&len);
540: if (program[len-1] == '/') {
541: PetscStrcat(program,"*.");
542: } else {
543: PetscStrcat(program,"/*.");
544: }
545: PetscStrcat(program,PETSC_SLSUFFIX);
547: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
548: if (!dir) return(0);
549: found = buf;
550: } else {
551: found = (char*)libname;
552: }
554: PetscStrcpy(suffix,".");
555: PetscStrcat(suffix,PETSC_SLSUFFIX);
557: PetscTokenCreate(found,'\n',&token);
558: PetscTokenFind(token,&libname1);
559: PetscStrstr(libname1,suffix,&s);
560: if (s) s[0] = 0;
561: while (libname1) {
562: /* see if library was already open and move it to the front */
563: list = *outlist;
564: prev = 0;
565: match = PETSC_FALSE;
566: while (list) {
568: PetscStrcmp(list->libname,libname1,&match);
569: if (match) {
570: if (prev) prev->next = list->next;
571: list->next = *outlist;
572: *outlist = list;
573: break;
574: }
575: prev = list;
576: list = list->next;
577: }
578: if (!match) {
579: /* open the library and add to front of list */
580: PetscDLLibraryOpen(comm,libname1,&handle);
581:
582: PetscInfo1(0,"Prepending %s to dynamic library search path\n",libname1);
584: PetscNew(struct _n_PetscDLLibrary,&list);
585: list->handle = handle;
586: list->next = *outlist;
587: PetscStrcpy(list->libname,libname1);
588: *outlist = list;
589: }
590: PetscTokenFind(token,&libname1);
591: if (libname1) {
592: PetscStrstr(libname1,suffix,&s);
593: if (s) s[0] = 0;
594: }
595: }
596: PetscTokenDestroy(token);
597: return(0);
598: }
602: /*@C
603: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
605: Collective on PetscDLLibrary
607: Input Parameter:
608: . next - library list
610: Level: developer
612: @*/
613: PetscErrorCode PetscDLLibraryClose(PetscDLLibrary next)
614: {
615: PetscDLLibrary prev;
620: while (next) {
621: prev = next;
622: next = next->next;
623: /* free the space in the prev data-structure */
624: PetscFree(prev);
625: }
626: return(0);
627: }
631: /*@C
632: PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
633: of the search path.
635: Collective on MPI_Comm
637: Input Parameters:
638: + comm - MPI communicator
639: - libname - name of directory to check
641: Output Parameter:
642: . outlist - list of libraries
644: Level: developer
646: Notes: if library is already in path will not add it.
647: @*/
648: PetscErrorCode PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibrary *outlist,const char dirname[])
649: {
651: size_t l;
652: PetscTruth dir;
653: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
654: char *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
655: FILE *fp;
656: PetscToken *token1,*token2;
660: /* is dirname a directory? */
661: PetscTestDirectory(dirname,'r',&dir);
662: if (!dir) return(0);
664: PetscInfo1(0,"Checking directory %s for CCA components\n",dirname);
665: PetscStrcpy(program,dirname);
666: PetscStrcat(program,"/*.cca");
668: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
669: if (!dir) return(0);
671: PetscStrcpy(suffix,".");
672: PetscStrcat(suffix,PETSC_SLSUFFIX);
673: PetscTokenCreate(buf,'\n',&token1);
674: PetscTokenFind(token1,&libname1);
675: while (libname1) {
676: fp = fopen(libname1,"r"); if (!fp) continue;
677: while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
678: if (found[0] == '!') continue;
679: PetscStrstr(found,suffix,&f2);
680: if (f2) { /* found library name */
681: if (found[0] == '/') {
682: lib = found;
683: } else {
684: PetscStrcpy(libname,dirname);
685: PetscStrlen(libname,&l);
686: if (libname[l-1] != '/') {PetscStrcat(libname,"/");}
687: PetscStrcat(libname,found);
688: lib = libname;
689: }
690: PetscDLLibraryAppend(comm,outlist,lib);
691: } else {
692: PetscInfo2(0,"CCA Component function and name: %s from %s\n",found,libname1);
693: PetscTokenCreate(found,' ',&token2);
694: PetscTokenFind(token2,&func);
695: PetscTokenFind(token2,&funcname);
696: PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);
697: PetscTokenDestroy(token2);
698: }
699: }
700: fclose(fp);
701: PetscTokenFind(token1,&libname1);
702: }
703: PetscTokenDestroy(token1);
704: return(0);
705: }
708: #endif