Actual source code: dl.c
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 _PetscDLLibraryList {
57: PetscDLLibraryList 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: PetscDLLibraryList 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: PetscDLLibraryGetInfo - Gets the text information from a PETSc
85: dynamic library
87: Not Collective
89: Input Parameters:
90: . handle - library handle returned by PetscDLLibraryOpen()
92: Level: developer
94: @*/
95: PetscErrorCode PetscDLLibraryGetInfo(void *handle,const char type[],const char *mess[])
96: {
97: PetscErrorCode ierr,(*sfunc)(const char *,const char*,const char *[]);
100: #if defined(PETSC_HAVE_DLSYM)
101: sfunc = (PetscErrorCode (*)(const char *,const char*,const char *[])) dlsym(handle,"PetscDLLibraryInfo");
102: #elif defined(PETSC_HAVE_GETPROCADDRESS)
103: sfunc = (PetscErrorCode (*)(const char *,const char*,const char *[])) GetProcAddress((HMODULE)handle,"PetscDLLibraryInfo");
104: #endif
105: if (!sfunc) {
106: *mess = "No library information in the file\n";
107: } else {
108: (*sfunc)(0,type,mess);
109: }
110: return(0);
111: }
115: /*@C
116: PetscDLLibraryRetrieve - Copies a PETSc dynamic library from a remote location
117: (if it is remote), indicates if it exits and its local name.
119: Collective on MPI_Comm
121: Input Parameters:
122: + comm - processors that are opening the library
123: - libname - name of the library, can be relative or absolute
125: Output Parameter:
126: . handle - library handle
128: Level: developer
130: Notes:
131: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
133: ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${BOPT}, or ${any environmental variable}
134: occuring in directoryname and filename will be replaced with appropriate values.
135: @*/
136: PetscErrorCode PetscDLLibraryRetrieve(MPI_Comm comm,const char libname[],char *lname,int llen,PetscTruth *found)
137: {
138: char *par2,buff[10],*en,*gz;
140: size_t len1,len2,len;
141: PetscTruth tflg,flg;
145: /*
146: make copy of library name and replace $PETSC_ARCH and $BOPT and
147: so we can add to the end of it to look for something like .so.1.0 etc.
148: */
149: PetscStrlen(libname,&len);
150: len = PetscMax(4*len,PETSC_MAX_PATH_LEN);
151: PetscMalloc(len*sizeof(char),&par2);
152: PetscStrreplace(comm,libname,par2,len);
154: /*
155: Remove any file: header
156: */
157: PetscStrncmp(par2,"file:",5,&tflg);
158: if (tflg) {
159: PetscStrcpy(par2,par2+5);
160: }
162: /* strip out .a from it if user put it in by mistake */
163: PetscStrlen(par2,&len);
164: if (par2[len-1] == 'a' && par2[len-2] == '.') par2[len-2] = 0;
166: /* remove .gz if it ends library name */
167: PetscStrstr(par2,".gz",&gz);
168: if (gz) {
169: PetscStrlen(gz,&len);
170: if (len == 3) {
171: *gz = 0;
172: }
173: }
175: /* see if library name does already not have suffix attached */
176: PetscStrcpy(buff,".");
177: PetscStrcat(buff,PETSC_SLSUFFIX);
178: PetscStrstr(par2,buff,&en);
179: if (en) {
180: PetscStrlen(en,&len1);
181: PetscStrlen(PETSC_SLSUFFIX,&len2);
182: flg = (PetscTruth) (len1 != 1 + len2);
183: } else {
184: flg = PETSC_TRUE;
185: }
186: if (flg) {
187: PetscStrcat(par2,".");
188: PetscStrcat(par2,PETSC_SLSUFFIX);
189: }
191: /* put the .gz back on if it was there */
192: if (gz) {
193: PetscStrcat(par2,".gz");
194: }
196: PetscFileRetrieve(comm,par2,lname,llen,found);
197: PetscFree(par2);
198: return(0);
199: }
204: /*@C
205: PetscDLLibraryOpen - Opens a dynamic link library
207: Collective on MPI_Comm
209: Input Parameters:
210: + comm - processors that are opening the library
211: - libname - name of the library, can be relative or absolute
213: Output Parameter:
214: . handle - library handle
216: Level: developer
218: Notes:
219: [[<http,ftp>://hostname]/directoryname/]filename[.so.1.0]
221: ${PETSC_ARCH} and ${BOPT} occuring in directoryname and filename
222: will be replaced with appropriate values.
223: @*/
224: PetscErrorCode PetscDLLibraryOpen(MPI_Comm comm,const char libname[],void **handle)
225: {
227: char *par2;
228: PetscTruth foundlibrary;
229: PetscErrorCode (*func)(const char*);
233: PetscMalloc(PETSC_MAX_PATH_LEN*sizeof(char),&par2);
234: PetscDLLibraryRetrieve(comm,libname,par2,PETSC_MAX_PATH_LEN,&foundlibrary);
235: if (!foundlibrary) {
236: SETERRQ1(PETSC_ERR_FILE_OPEN,"Unable to locate dynamic library:\n %s\n",libname);
237: }
239: #if !defined(PETSC_USE_NONEXECUTABLE_SO)
240: PetscTestFile(par2,'x',&foundlibrary);
241: if (!foundlibrary) {
242: SETERRQ2(PETSC_ERR_FILE_OPEN,"Dynamic library is not executable:\n %s\n %s\n",libname,par2);
243: }
244: #endif
246: /*
247: Mode indicates symbols required by symbol loaded with dlsym()
248: are only loaded when required (not all together) also indicates
249: symbols required can be contained in other libraries also opened
250: with dlopen()
251: */
252: PetscLogInfo(0,"PetscDLLibraryOpen:Opening %s\n",libname);
253: #if defined(PETSC_HAVE_DLOPEN)
254: #if defined(PETSC_HAVE_RTLD_GLOBAL)
255: *handle = dlopen(par2,RTLD_LAZY | RTLD_GLOBAL);
256: #else
257: *handle = dlopen(par2,RTLD_LAZY);
258: #endif
259: #elif defined(PETSC_HAVE_LOADLIBRARY)
260: *handle = LoadLibrary(par2);
261: #endif
262: if (!*handle) {
263: #if defined(PETSC_HAVE_DLERROR)
264: SETERRQ3(PETSC_ERR_FILE_OPEN,"Unable to open dynamic library:\n %s\n %s\n Error message from dlopen() %s\n",libname,par2,dlerror());
265: #elif defined(PETSC_HAVE_GETLASTERROR)
266: {
267: DWORD erc;
268: char *buff;
269: erc = GetLastError();
270: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
271: NULL,
272: erc,
273: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
274: (LPSTR)&buff,
275: 0,
276: NULL);
277: PetscError(__LINE__,__FUNCT__,__FILE__,__SDIR__,PETSC_ERR_FILE_OPEN,1,
278: "Unable to open dynamic library:\n %s\n %s\n Error message from LoadLibrary() %s\n",
279: libname,par2,buff);
280: LocalFree(buff);
281: return(ierr);
282: }
283: #endif
284: }
285: /* run the function PetscFListAddDynamic() if it is in the library */
286: #if defined(PETSC_HAVE_DLSYM)
287: func = (PetscErrorCode (*)(const char *)) dlsym(*handle,"PetscDLLibraryRegister");
288: #elif defined(PETSC_HAVE_GETPROCADDRESS)
289: func = (PetscErrorCode (*)(const char *)) GetProcAddress((HMODULE)*handle,"PetscDLLibraryRegister");
290: #endif
291: if (func) {
292: (*func)(libname);
293: PetscLogInfo(0,"PetscDLLibraryOpen:Loading registered routines from %s\n",libname);
294: }
295: if (PetscLogPrintInfo) {
296: PetscErrorCode (*sfunc)(const char *,const char*,char **);
297: char *mess;
299: #if defined(PETSC_HAVE_DLSYM)
300: sfunc = (PetscErrorCode (*)(const char *,const char*,char **)) dlsym(*handle,"PetscDLLibraryInfo");
301: #elif defined(PETSC_HAVE_GETPROCADDRESS)
302: sfunc = (PetscErrorCode (*)(const char *,const char*,char **)) GetProcAddress((HMODULE)*handle,"PetscDLLibraryInfo");
303: #endif
304: if (sfunc) {
305: (*sfunc)(libname,"Contents",&mess);
306: if (mess) {
307: PetscLogInfo(0,"Contents:\n %s",mess);
308: }
309: (*sfunc)(libname,"Authors",&mess);
310: if (mess) {
311: PetscLogInfo(0,"Authors:\n %s",mess);
312: }
313: (*sfunc)(libname,"Version",&mess);
314: if (mess) {
315: PetscLogInfo(0,"Version:\n %s\n",mess);
316: }
317: }
318: }
320: PetscFree(par2);
321: return(0);
322: }
326: /*@C
327: PetscDLLibrarySym - Load a symbol from the dynamic link libraries.
329: Collective on MPI_Comm
331: Input Parameter:
332: + path - optional complete library name
333: - insymbol - name of symbol
335: Output Parameter:
336: . value
338: Level: developer
340: Notes: Symbol can be of the form
341: [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional
343: Will attempt to (retrieve and) open the library if it is not yet been opened.
345: @*/
346: PetscErrorCode PetscDLLibrarySym(MPI_Comm comm,PetscDLLibraryList *inlist,const char path[],const char insymbol[],void **value)
347: {
348: char *par1,*symbol;
350: size_t len;
351: PetscDLLibraryList nlist,prev,list;
354: if (inlist) list = *inlist; else list = PETSC_NULL;
355: *value = 0;
357: /* make copy of symbol so we can edit it in place */
358: PetscStrlen(insymbol,&len);
359: PetscMalloc((len+1)*sizeof(char),&symbol);
360: PetscStrcpy(symbol,insymbol);
362: /*
363: If symbol contains () then replace with a NULL, to support functionname()
364: */
365: PetscStrchr(symbol,'(',&par1);
366: if (par1) *par1 = 0;
369: /*
370: Function name does include library
371: -------------------------------------
372: */
373: if (path && path[0] != '\0') {
374: void *handle;
375:
376: /*
377: Look if library is already opened and in path
378: */
379: nlist = list;
380: prev = 0;
381: while (nlist) {
382: PetscTruth match;
384: PetscStrcmp(nlist->libname,path,&match);
385: if (match) {
386: handle = nlist->handle;
387: goto done;
388: }
389: prev = nlist;
390: nlist = nlist->next;
391: }
392: PetscDLLibraryOpen(comm,path,&handle);
394: PetscNew(struct _PetscDLLibraryList,&nlist);
395: nlist->next = 0;
396: nlist->handle = handle;
397: PetscStrcpy(nlist->libname,path);
399: if (prev) {
400: prev->next = nlist;
401: } else {
402: if (inlist) *inlist = nlist;
403: else {PetscDLLibraryClose(nlist);}
404: }
405: PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search path\n",path);
407: done:;
408: #if defined(PETSC_HAVE_DLSYM)
409: *value = dlsym(handle,symbol);
410: #elif defined(PETSC_HAVE_GETPROCADDRESS)
411: *value = GetProcAddress((HMODULE)handle,symbol);
412: #endif
413: if (!*value) {
414: SETERRQ2(PETSC_ERR_PLIB,"Unable to locate function %s in dynamic library %s",insymbol,path);
415: }
416: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %s\n",insymbol,path);
418: /*
419: Function name does not include library so search path
420: -----------------------------------------------------
421: */
422: } else {
423: while (list) {
424: #if defined(PETSC_HAVE_DLSYM)
425: *value = dlsym(list->handle,symbol);
426: #elif defined(PETSC_HAVE_GETPROCADDRESS)
427: *value = GetProcAddress((HMODULE)list->handle,symbol);
428: #endif
429: if (*value) {
430: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from dynamic library %s\n",symbol,list->libname);
431: break;
432: }
433: list = list->next;
434: }
435: if (!*value) {
436: #if defined(PETSC_HAVE_DLSYM)
437: *value = dlsym(0,symbol);
438: #elif defined(PETSC_HAVE_GETPROCADDRESS)
439: *value = GetProcAddress(GetCurrentProcess(),symbol);
440: #endif
441: if (*value) {
442: PetscLogInfo(0,"PetscDLLibrarySym:Loading function %s from object code\n",symbol);
443: }
444: }
445: }
447: PetscFree(symbol);
448: return(0);
449: }
453: /*@C
454: PetscDLLibraryAppend - Appends another dynamic link library to the seach list, to the end
455: of the search path.
457: Collective on MPI_Comm
459: Input Parameters:
460: + comm - MPI communicator
461: - libname - name of the library
463: Output Parameter:
464: . outlist - list of libraries
466: Level: developer
468: Notes: if library is already in path will not add it.
469: @*/
470: PetscErrorCode PetscDLLibraryAppend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
471: {
472: PetscDLLibraryList list,prev;
473: void* handle;
475: size_t len;
476: PetscTruth match,dir;
477: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
478: PetscToken *token;
482: /* is libname a directory? */
483: PetscTestDirectory(libname,'r',&dir);
484: if (dir) {
485: PetscLogInfo(0,"Checking directory %s for dynamic libraries\n",libname);
486: PetscStrcpy(program,libname);
487: PetscStrlen(program,&len);
488: if (program[len-1] == '/') {
489: PetscStrcat(program,"*.");
490: } else {
491: PetscStrcat(program,"/*.");
492: }
493: PetscStrcat(program,PETSC_SLSUFFIX);
495: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
496: if (!dir) return(0);
497: found = buf;
498: } else {
499: found = (char*)libname;
500: }
501: PetscStrcpy(suffix,".");
502: PetscStrcat(suffix,PETSC_SLSUFFIX);
504: PetscTokenCreate(found,'\n',&token);
505: PetscTokenFind(token,&libname1);
506: PetscStrstr(libname1,suffix,&s);
507: if (s) s[0] = 0;
508: while (libname1) {
510: /* see if library was already open then we are done */
511: list = prev = *outlist;
512: match = PETSC_FALSE;
513: while (list) {
515: PetscStrcmp(list->libname,libname1,&match);
516: if (match) break;
517: prev = list;
518: list = list->next;
519: }
520: if (!match) {
522: PetscDLLibraryOpen(comm,libname1,&handle);
524: PetscNew(struct _PetscDLLibraryList,&list);
525: list->next = 0;
526: list->handle = handle;
527: PetscStrcpy(list->libname,libname1);
529: if (!*outlist) {
530: *outlist = list;
531: } else {
532: prev->next = list;
533: }
534: PetscLogInfo(0,"PetscDLLibraryAppend:Appending %s to dynamic library search path\n",libname1);
535: }
536: PetscTokenFind(token,&libname1);
537: if (libname1) {
538: PetscStrstr(libname1,suffix,&s);
539: if (s) s[0] = 0;
540: }
541: }
542: PetscTokenDestroy(token);
543: return(0);
544: }
548: /*@C
549: PetscDLLibraryPrepend - Add another dynamic library to search for symbols to the beginning of
550: the search path.
552: Collective on MPI_Comm
554: Input Parameters:
555: + comm - MPI communicator
556: - libname - name of the library
558: Output Parameter:
559: . outlist - list of libraries
561: Level: developer
563: Notes: If library is already in path will remove old reference.
565: @*/
566: PetscErrorCode PetscDLLibraryPrepend(MPI_Comm comm,PetscDLLibraryList *outlist,const char libname[])
567: {
568: PetscDLLibraryList list,prev;
569: void* handle;
571: size_t len;
572: PetscTruth match,dir;
573: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*found,*libname1,suffix[16],*s;
574: PetscToken *token;
577:
578: /* is libname a directory? */
579: PetscTestDirectory(libname,'r',&dir);
580: if (dir) {
581: PetscLogInfo(0,"Checking directory %s for dynamic libraries\n",libname);
582: PetscStrcpy(program,libname);
583: PetscStrlen(program,&len);
584: if (program[len-1] == '/') {
585: PetscStrcat(program,"*.");
586: } else {
587: PetscStrcat(program,"/*.");
588: }
589: PetscStrcat(program,PETSC_SLSUFFIX);
591: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
592: if (!dir) return(0);
593: found = buf;
594: } else {
595: found = (char*)libname;
596: }
598: PetscStrcpy(suffix,".");
599: PetscStrcat(suffix,PETSC_SLSUFFIX);
601: PetscTokenCreate(found,'\n',&token);
602: PetscTokenFind(token,&libname1);
603: PetscStrstr(libname1,suffix,&s);
604: if (s) s[0] = 0;
605: while (libname1) {
606: /* see if library was already open and move it to the front */
607: list = *outlist;
608: prev = 0;
609: match = PETSC_FALSE;
610: while (list) {
612: PetscStrcmp(list->libname,libname1,&match);
613: if (match) {
614: if (prev) prev->next = list->next;
615: list->next = *outlist;
616: *outlist = list;
617: break;
618: }
619: prev = list;
620: list = list->next;
621: }
622: if (!match) {
623: /* open the library and add to front of list */
624: PetscDLLibraryOpen(comm,libname1,&handle);
625:
626: PetscLogInfo(0,"PetscDLLibraryPrepend:Prepending %s to dynamic library search path\n",libname1);
628: PetscNew(struct _PetscDLLibraryList,&list);
629: list->handle = handle;
630: list->next = *outlist;
631: PetscStrcpy(list->libname,libname1);
632: *outlist = list;
633: }
634: PetscTokenFind(token,&libname1);
635: if (libname1) {
636: PetscStrstr(libname1,suffix,&s);
637: if (s) s[0] = 0;
638: }
639: }
640: PetscTokenDestroy(token);
641: return(0);
642: }
646: /*@C
647: PetscDLLibraryClose - Destroys the search path of dynamic libraries and closes the libraries.
649: Collective on PetscDLLibrary
651: Input Parameter:
652: . next - library list
654: Level: developer
656: @*/
657: PetscErrorCode PetscDLLibraryClose(PetscDLLibraryList next)
658: {
659: PetscDLLibraryList prev;
664: while (next) {
665: prev = next;
666: next = next->next;
667: /* free the space in the prev data-structure */
668: PetscFree(prev);
669: }
670: return(0);
671: }
675: /*@C
676: PetscDLLibraryCCAAppend - Appends another CCA dynamic link library to the seach list, to the end
677: of the search path.
679: Collective on MPI_Comm
681: Input Parameters:
682: + comm - MPI communicator
683: - libname - name of directory to check
685: Output Parameter:
686: . outlist - list of libraries
688: Level: developer
690: Notes: if library is already in path will not add it.
691: @*/
692: PetscErrorCode PetscDLLibraryCCAAppend(MPI_Comm comm,PetscDLLibraryList *outlist,const char dirname[])
693: {
695: size_t l;
696: PetscTruth dir;
697: char program[PETSC_MAX_PATH_LEN],buf[8*PETSC_MAX_PATH_LEN],*libname1,fbuf[PETSC_MAX_PATH_LEN],*found,suffix[16],*f2;
698: char *func,*funcname,libname[PETSC_MAX_PATH_LEN],*lib;
699: FILE *fp;
700: PetscToken *token1,*token2;
704: /* is dirname a directory? */
705: PetscTestDirectory(dirname,'r',&dir);
706: if (!dir) return(0);
708: PetscLogInfo(0,"Checking directory %s for CCA components\n",dirname);
709: PetscStrcpy(program,dirname);
710: PetscStrcat(program,"/*.cca");
712: PetscLs(comm,program,buf,8*PETSC_MAX_PATH_LEN,&dir);
713: if (!dir) return(0);
715: PetscStrcpy(suffix,".");
716: PetscStrcat(suffix,PETSC_SLSUFFIX);
717: PetscTokenCreate(buf,'\n',&token1);
718: PetscTokenFind(token1,&libname1);
719: while (libname1) {
720: fp = fopen(libname1,"r"); if (!fp) continue;
721: while ((found = fgets(fbuf,PETSC_MAX_PATH_LEN,fp))) {
722: if (found[0] == '!') continue;
723: PetscStrstr(found,suffix,&f2);
724: if (f2) { /* found library name */
725: if (found[0] == '/') {
726: lib = found;
727: } else {
728: PetscStrcpy(libname,dirname);
729: PetscStrlen(libname,&l);
730: if (libname[l-1] != '/') {PetscStrcat(libname,"/");}
731: PetscStrcat(libname,found);
732: lib = libname;
733: }
734: PetscDLLibraryAppend(comm,outlist,lib);
735: } else {
736: PetscLogInfo(0,"CCA Component function and name: %s from %s\n",found,libname1);
737: PetscTokenCreate(found,' ',&token2);
738: PetscTokenFind(token2,&func);
739: PetscTokenFind(token2,&funcname);
740: PetscFListAdd(&CCAList,funcname,func,PETSC_NULL);
741: PetscTokenDestroy(token2);
742: }
743: }
744: fclose(fp);
745: PetscTokenFind(token1,&libname1);
746: }
747: PetscTokenDestroy(token1);
748: return(0);
749: }
752: #endif