Actual source code: reg.c

  1: /*$Id: reg.c,v 1.77 2001/09/07 20:08:26 bsmith Exp $*/
  2: /*
  3:     Provides a general mechanism to allow one to register new routines in
  4:     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
  5: */
 6:  #include petsc.h
 7:  #include petscsys.h

 11: int PetscFListGetPathAndFunction(const char name[],char *path[],char *function[])
 12: {
 13:   char work[256],*lfunction,ierr;

 16:   PetscStrncpy(work,name,256);
 17:   PetscStrchr(work,':',&lfunction);
 18:   if (lfunction != work && lfunction && lfunction[1] != ':') {
 19:     lfunction[0] = 0;
 20:     PetscStrallocpy(work,path);
 21:     PetscStrallocpy(lfunction+1,function);
 22:   } else {
 23:     *path = 0;
 24:     PetscStrallocpy(name,function);
 25:   }
 26:   return(0);
 27: }

 29: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)

 31: /*
 32:     This is the list used by the DLRegister routines
 33: */
 34: PetscDLLibraryList DLLibrariesLoaded = 0;

 38: /*
 39:     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the 
 40:     search path.
 41: */
 42: int PetscInitialize_DynamicLibraries(void)
 43: {
 44:   char       *libname[32],libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN];
 45:   int        nmax,i,ierr;
 46:   PetscTruth found;


 50:   nmax = 32;
 51:   PetscOptionsGetStringArray(PETSC_NULL,"-dll_prepend",libname,&nmax,PETSC_NULL);
 52:   for (i=0; i<nmax; i++) {
 53:     PetscDLLibraryPrepend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);
 54:     PetscFree(libname[i]);
 55:   }

 57:   PetscStrcpy(libs,PETSC_LIB_DIR);
 58:   PetscStrcat(libs,"/libpetsc");
 59:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 60:   if (found) {
 61:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 62:   } else {
 63:     SETERRQ1(1,"Unable to locate PETSc dynamic library %s \n You cannot move the dynamic libraries!\n or remove USE_DYNAMIC_LIBRARIES from ${PETSC_DIR}/bmake/$PETSC_ARCH/petscconf.h\n and rebuild libraries before moving",libs);
 64:   }

 66:   PetscStrcpy(libs,PETSC_LIB_DIR);
 67:   PetscStrcat(libs,"/libpetscvec");
 68:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 69:   if (found) {
 70:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 71:   }

 73:   PetscStrcpy(libs,PETSC_LIB_DIR);
 74:   PetscStrcat(libs,"/libpetscmat");
 75:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 76:   if (found) {
 77:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 78:   }

 80:   PetscStrcpy(libs,PETSC_LIB_DIR);
 81:   PetscStrcat(libs,"/libpetscdm");
 82:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 83:   if (found) {
 84:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 85:   }

 87:   PetscStrcpy(libs,PETSC_LIB_DIR);
 88:   PetscStrcat(libs,"/libpetscksp");
 89:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 90:   if (found) {
 91:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 92:   }

 94:   PetscStrcpy(libs,PETSC_LIB_DIR);
 95:   PetscStrcat(libs,"/libpetscsnes");
 96:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 97:   if (found) {
 98:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 99:   }

101:   PetscStrcpy(libs,PETSC_LIB_DIR);
102:   PetscStrcat(libs,"/libpetscts");
103:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
104:   if (found) {
105:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
106:   }

108:   PetscStrcpy(libs,PETSC_LIB_DIR);
109:   PetscStrcat(libs,"/libpetscdm");
110:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
111:   if (found) {
112:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
113:   }

115:   PetscStrcpy(libs,PETSC_LIB_DIR);
116:   PetscStrcat(libs,"/libpetscmesh");
117:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
118:   if (found) {
119:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
120:   }

122:   PetscStrcpy(libs,PETSC_LIB_DIR);
123:   PetscStrcat(libs,"/libpetscgrid");
124:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
125:   if (found) {
126:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
127:   }

129:   nmax = 32;
130:   PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);
131:   for (i=0; i<nmax; i++) {
132:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);
133:     PetscDLLibraryCCAAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);
134:     PetscFree(libname[i]);
135:   }

137:   return(0);
138: }

142: /*
143:      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
144: */
145: int PetscFinalize_DynamicLibraries(void)
146: {
147:   int        ierr;
148:   PetscTruth flg;

151:   PetscOptionsHasName(PETSC_NULL,"-dll_view",&flg);
152:   if (flg) {
153:     PetscDLLibraryPrintPath();
154:   }
155:   PetscDLLibraryClose(DLLibrariesLoaded);
156:   return(0);
157: }

159: #else /* not using dynamic libraries */

161: EXTERN int PetscInitializePackage(char *);

165: int PetscInitialize_DynamicLibraries(void)
166: {

170:   /*
171:       This just initializes the draw and viewer methods, since those
172:     are ALWAYS available. The other classes are initialized the first
173:     time an XXSetType() is called.
174:   */
175:   PetscInitializePackage(PETSC_NULL);
176:   return(0);
177: }
180: int PetscFinalize_DynamicLibraries(void)
181: {

184:   return(0);
185: }
186: #endif

188: /* ------------------------------------------------------------------------------*/
189: struct _PetscFList {
190:   void        (*routine)(void);   /* the routine */
191:   char        *path;              /* path of link library containing routine */
192:   char        *name;              /* string to identify routine */
193:   char        *rname;             /* routine name in dynamic library */
194:   PetscFList  next;               /* next pointer */
195:   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
196: };

198: /*
199:      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
200: */
201: static PetscFList   dlallhead = 0;

205: /*@C
206:    PetscFListAddDynamic - Given a routine and a string id, saves that routine in the
207:    specified registry.

209:    Synopsis:
210:    int PetscFListAddDynamic(PetscFList *fl,char *name,char *rname,int (*fnc)(void *))

212:    Input Parameters:
213: +  fl    - pointer registry
214: .  name  - string to identify routine
215: .  rname - routine name in dynamic library
216: -  fnc   - function pointer (optional if using dynamic libraries)

218:    Notes:
219:    Users who wish to register new methods for use by a particular PETSc
220:    component (e.g., SNES) should generally call the registration routine
221:    for that particular component (e.g., SNESRegisterDynamic()) instead of
222:    calling PetscFListAddDynamic() directly.

224:    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, ${BOPT}, or ${any environmental variable}
225:   occuring in pathname will be replaced with appropriate values.

227:    Level: developer

229: .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
230:           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
231: @*/
232: int PetscFListAdd(PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
233: {
234:   PetscFList entry,ne;
235:   int        ierr;
236:   char       *fpath,*fname;


240:   if (!*fl) {
241:     PetscNew(struct _PetscFList,&entry);
242:     PetscStrallocpy(name,&entry->name);
243:     PetscFListGetPathAndFunction(rname,&fpath,&fname);
244:     entry->path    = fpath;
245:     entry->rname   = fname;
246:     entry->routine = fnc;
247:     entry->next    = 0;
248:     *fl = entry;

250:     /* add this new list to list of all lists */
251:     if (!dlallhead) {
252:       dlallhead        = *fl;
253:       (*fl)->next_list = 0;
254:     } else {
255:       ne               = dlallhead;
256:       dlallhead        = *fl;
257:       (*fl)->next_list = ne;
258:     }
259:   } else {
260:     /* search list to see if it is already there */
261:     ne = *fl;
262:     while (ne) {
263:       PetscTruth founddup;

265:       PetscStrcmp(ne->name,name,&founddup);
266:       if (founddup) { /* found duplicate */
267:         PetscFListGetPathAndFunction(rname,&fpath,&fname);
268:         PetscStrfree(ne->path);
269:         PetscStrfree(ne->rname);
270:         ne->path    = fpath;
271:         ne->rname   = fname;
272:         ne->routine = fnc;
273:         return(0);
274:       }
275:       if (ne->next) ne = ne->next; else break;
276:     }
277:     /* create new entry and add to end of list */
278:     PetscNew(struct _PetscFList,&entry);
279:     PetscStrallocpy(name,&entry->name);
280:     PetscFListGetPathAndFunction(rname,&fpath,&fname);
281:     entry->path    = fpath;
282:     entry->rname   = fname;
283:     entry->routine = fnc;
284:     entry->next    = 0;
285:     ne->next       = entry;
286:   }

288:   return(0);
289: }

293: /*@
294:     PetscFListDestroy - Destroys a list of registered routines.

296:     Input Parameter:
297: .   fl  - pointer to list

299:     Level: developer

301: .seealso: PetscFListAddDynamic(), PetscFList
302: @*/
303: int PetscFListDestroy(PetscFList *fl)
304: {
305:   PetscFList next,entry,tmp = dlallhead;
306:   int        ierr;

309:   if (!*fl) return(0);

311:   if (!dlallhead) {
312:     return(0);
313:   }

315:   /*
316:        Remove this entry from the master DL list (if it is in it)
317:   */
318:   if (dlallhead == *fl) {
319:     if (dlallhead->next_list) {
320:       dlallhead = dlallhead->next_list;
321:     } else {
322:       dlallhead = 0;
323:     }
324:   } else {
325:     while (tmp->next_list != *fl) {
326:       tmp = tmp->next_list;
327:       if (!tmp->next_list) break;
328:     }
329:     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
330:   }

332:   /* free this list */
333:   entry = *fl;
334:   while (entry) {
335:     next = entry->next;
336:     PetscStrfree(entry->path);
337:     PetscFree(entry->name);
338:     PetscFree(entry->rname);
339:     PetscFree(entry);
340:     entry = next;
341:   }
342:   *fl = 0;
343:   return(0);
344: }

346: /*
347:    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
348: */
351: int PetscFListDestroyAll(void)
352: {
353:   PetscFList tmp2,tmp1 = dlallhead;
354:   int        ierr;

357:   while (tmp1) {
358:     tmp2 = tmp1->next_list;
359:     PetscFListDestroy(&tmp1);
360:     tmp1 = tmp2;
361:   }
362:   dlallhead = 0;
363:   return(0);
364: }

368: /*@C
369:     PetscFListFind - Given a name, finds the matching routine.

371:     Input Parameters:
372: +   comm - processors looking for routine
373: .   fl   - pointer to list
374: -   name - name string

376:     Output Parameters:
377: .   r - the routine

379:     Level: developer

381: .seealso: PetscFListAddDynamic(), PetscFList
382: @*/
383: int PetscFListFind(MPI_Comm comm,PetscFList fl,const char name[],void (**r)(void))
384: {
385:   PetscFList   entry = fl;
386:   int          ierr;
387:   char         *function,*path;
388: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
389:   char         *newpath;
390: #endif
391:   PetscTruth   flg,f1,f2,f3;
392: 
394:   if (!name) SETERRQ(1,"Trying to find routine with null name");

396:   *r = 0;
397:   PetscFListGetPathAndFunction(name,&path,&function);

399:   /*
400:         If path then append it to search libraries
401:   */
402: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
403:   if (path) {
404:     PetscDLLibraryAppend(comm,&DLLibrariesLoaded,path);
405:   }
406: #endif

408:   while (entry) {
409:     flg = PETSC_FALSE;
410:     if (path && entry->path) {
411:       PetscStrcmp(path,entry->path,&f1);
412:       PetscStrcmp(function,entry->rname,&f2);
413:       PetscStrcmp(function,entry->name,&f3);
414:       flg =  (PetscTruth) ((f1 && f2) || (f1 && f3));
415:     } else if (!path) {
416:       PetscStrcmp(function,entry->name,&f1);
417:       PetscStrcmp(function,entry->rname,&f2);
418:       flg =  (PetscTruth) (f1 || f2);
419:     } else {
420:       PetscStrcmp(function,entry->name,&flg);
421:       if (flg) {
422:         PetscFree(function);
423:         PetscStrallocpy(entry->rname,&function);
424:       } else {
425:         PetscStrcmp(function,entry->rname,&flg);
426:       }
427:     }

429:     if (flg) {

431:       if (entry->routine) {
432:         *r   = entry->routine;
433:         PetscStrfree(path);
434:         PetscFree(function);
435:         return(0);
436:       }
437: 
438:       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
439:         PetscFree(function);
440:         PetscStrallocpy(entry->rname,&function);
441:       }

443:       /* it is not yet in memory so load from dynamic library */
444: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
445:       newpath = path;
446:       if (!path) newpath = entry->path;
447:       PetscDLLibrarySym(comm,&DLLibrariesLoaded,newpath,entry->rname,(void **)r);
448:       if (*r) {
449:         entry->routine = *r;
450:         PetscStrfree(path);
451:         PetscFree(function);
452:         return(0);
453:       } else {
454:         PetscErrorPrintf("Unable to find function. Search path:\n");
455:         PetscDLLibraryPrintPath();
456:         SETERRQ1(1,"Unable to find function:%s: either it is mis-spelled or dynamic library is not in path",entry->rname);
457:       }
458: #endif
459:     }
460:     entry = entry->next;
461:   }

463: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
464:   /* Function never registered; try for it anyway */
465:   PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);
466:   PetscStrfree(path);
467:   if (*r) {
468:     PetscFListAdd(&fl,name,name,*r);
469:   }
470: #endif

472:   /*
473:        Do not generate error, just end
474:   PetscErrorPrintf("Function name: %s\n",function);
475:   PetscDLLibraryPrintPath();
476:   SETERRQ(1,"Unable to find function: either it is mis-spelled or dynamic library is not in path");
477:   */

479:   PetscFree(function);
480:   return(0);
481: }

485: /*@
486:    PetscFListView - prints out contents of an PetscFList

488:    Collective over MPI_Comm

490:    Input Parameters:
491: +  list - the list of functions
492: -  viewer - currently ignored

494:    Level: developer

496: .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
497: @*/
498: int PetscFListView(PetscFList list,PetscViewer viewer)
499: {
500:   int        ierr;
501:   PetscTruth isascii;

504:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
507: 
508:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
509:   if (!isascii) SETERRQ(1,"Only ASCII viewer supported");

511:   while (list) {
512:     if (list->path) {
513:       PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);
514:     } else {
515:       PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);
516:     }
517:     list = list->next;
518:   }
519:   PetscViewerASCIIPrintf(viewer,"\n");
520:   return(0);
521: }

525: /*@
526:    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
527:          by help etc.

529:    Collective over MPI_Comm

531:    Input Parameter:
532: .  list   - list of types

534:    Output Parameter:
535: +  array - array of names
536: -  n - length of array

538:    Notes:
539:        This allocates the array so that must be freed. BUT the individual entries are
540:     not copied so should not be freed.

542:    Level: developer

544: .seealso: PetscFListAddDynamic(), PetscFList
545: @*/
546: int PetscFListGet(PetscFList list,char ***array,int *n)
547: {
548:   int        count = 0,ierr;
549:   PetscFList klist = list;

552:   while (list) {
553:     list = list->next;
554:     count++;
555:   }
556:   PetscMalloc((count+1)*sizeof(char *),array);
557:   count = 0;
558:   while (klist) {
559:     (*array)[count] = klist->name;
560:     klist = klist->next;
561:     count++;
562:   }
563:   (*array)[count] = 0;
564:   *n = count+1;

566:   return(0);
567: }


572: /*@C
573:    PetscFListPrintTypes - Prints the methods available.

575:    Collective over MPI_Comm

577:    Input Parameters:
578: +  comm   - the communicator (usually MPI_COMM_WORLD)
579: .  fd     - file to print to, usually stdout
580: .  prefix - prefix to prepend to name (optional)
581: .  name   - option string (for example, "-ksp_type")
582: .  text - short description of the object (for example, "Krylov solvers")
583: .  man - name of manual page that discusses the object (for example, "KSPCreate")
584: -  list   - list of types

586:    Level: developer

588: .seealso: PetscFListAddDynamic(), PetscFList
589: @*/
590: int PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list)
591: {
592:   int      ierr,count = 0;
593:   char     p[64];

596:   if (!fd) fd = stdout;

598:   PetscStrcpy(p,"-");
599:   if (prefix) {PetscStrcat(p,prefix);}
600:   PetscFPrintf(comm,fd,"  %s%s %s:(one of)",p,name+1,text);

602:   while (list) {
603:     PetscFPrintf(comm,fd," %s",list->name);
604:     list = list->next;
605:     count++;
606:     if (count == 8) {PetscFPrintf(comm,fd,"\n     ");}
607:   }
608:   PetscFPrintf(comm,fd," (%s)\n",man);
609:   return(0);
610: }

614: /*@
615:     PetscFListDuplicate - Creates a new list from a given object list.

617:     Input Parameters:
618: .   fl   - pointer to list

620:     Output Parameters:
621: .   nl - the new list (should point to 0 to start, otherwise appends)

623:     Level: developer

625: .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy()

627: @*/
628: int PetscFListDuplicate(PetscFList fl,PetscFList *nl)
629: {
630:   int  ierr;
631:   char path[PETSC_MAX_PATH_LEN];

634:   while (fl) {
635:     /* this is silly, rebuild the complete pathname */
636:     if (fl->path) {
637:       PetscStrcpy(path,fl->path);
638:       PetscStrcat(path,":");
639:       PetscStrcat(path,fl->name);
640:     } else {
641:       PetscStrcpy(path,fl->name);
642:     }
643:     PetscFListAdd(nl,path,fl->rname,fl->routine);
644:     fl   = fl->next;
645:   }
646:   return(0);
647: }


652: /*
653:     PetscFListConcat - joins name of a libary, and the path where it is located
654:     into a single string.

656:     Input Parameters:
657: .   path   - path to the library name.
658: .   name   - name of the library

660:     Output Parameters:
661: .   fullname - the name that is the union of the path and the library name,
662:                delimited by a semicolon, i.e., path:name

664:     Notes:
665:     If the path is NULL, assumes that the name, specified also includes
666:     the path as path:name

668: */
669: int PetscFListConcat(const char path[],const char name[],char fullname[])
670: {
673:   if (path) {
674:     PetscStrcpy(fullname,path);
675:     PetscStrcat(fullname,":");
676:     PetscStrcat(fullname,name);
677:   } else {
678:     PetscStrcpy(fullname,name);
679:   }
680:   return(0);
681: }