Actual source code: reg.c

  1: /*
  2:     Provides a general mechanism to allow one to register new routines in
  3:     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
  4: */
 5:  #include petsc.h
 6:  #include petscsys.h

 10: PetscErrorCode PetscFListGetPathAndFunction(const char name[],char *path[],char *function[])
 11: {
 13:   char work[PETSC_MAX_PATH_LEN],*lfunction;

 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: PetscErrorCode PetscInitialize_DynamicLibraries(void)
 43: {
 44:   char           *libname[32],libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN];
 46:   PetscInt       nmax,i;
 47:   PetscTruth     found;


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

 58:   PetscStrcpy(libs,PETSC_LIB_DIR);
 59:   PetscStrcat(libs,"/libpetsc");
 60:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,&found);
 61:   if (found) {
 62:     PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libs);
 63:   } else {
 64:     SETERRQ1(PETSC_ERR_FILE_OPEN,"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);
 65:   }

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

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

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

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

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

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

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

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

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

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

138:   return(0);
139: }

143: /*
144:      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
145: */
146: PetscErrorCode PetscFinalize_DynamicLibraries(void)
147: {
149:   PetscTruth     flg;

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

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

162: EXTERN PetscErrorCode PetscInitializePackage(char *);

166: PetscErrorCode PetscInitialize_DynamicLibraries(void)
167: {

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

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

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

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

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

210:      Not Collective

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:    To remove a registered routine, pass in a PETSC_NULL rname and fnc().

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

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

229:    Level: developer

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


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

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

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

290:   return(0);
291: }

295: /*@
296:     PetscFListDestroy - Destroys a list of registered routines.

298:     Input Parameter:
299: .   fl  - pointer to list

301:     Level: developer

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

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

313:   if (!dlallhead) {
314:     return(0);
315:   }

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

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

348: /*
349:    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
350: */
353: PetscErrorCode PetscFListDestroyAll(void)
354: {
355:   PetscFList     tmp2,tmp1 = dlallhead;

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

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

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

378:     Output Parameters:
379: .   r - the routine

381:     Level: developer

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

398:   *r = 0;
399:   PetscFListGetPathAndFunction(name,&path,&function);

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

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

431:     if (flg) {

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

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

465: #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
466:   /* Function never registered; try for it anyway */
467:   PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);
468:   PetscStrfree(path);
469:   if (*r) {
470:     PetscFListAdd(&fl,name,name,*r);
471:   }
472: #endif
473:   PetscFree(function);
474:   return(0);
475: }

479: /*@
480:    PetscFListView - prints out contents of an PetscFList

482:    Collective over MPI_Comm

484:    Input Parameters:
485: +  list - the list of functions
486: -  viewer - currently ignored

488:    Level: developer

490: .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
491: @*/
492: PetscErrorCode PetscFListView(PetscFList list,PetscViewer viewer)
493: {
495:   PetscTruth     iascii;

498:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
501: 
502:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
503:   if (!iascii) SETERRQ(PETSC_ERR_SUP,"Only ASCII viewer supported");

505:   while (list) {
506:     if (list->path) {
507:       PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);
508:     } else {
509:       PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);
510:     }
511:     list = list->next;
512:   }
513:   PetscViewerASCIIPrintf(viewer,"\n");
514:   return(0);
515: }

519: /*@
520:    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
521:          by help etc.

523:    Collective over MPI_Comm

525:    Input Parameter:
526: .  list   - list of types

528:    Output Parameter:
529: +  array - array of names
530: -  n - length of array

532:    Notes:
533:        This allocates the array so that must be freed. BUT the individual entries are
534:     not copied so should not be freed.

536:    Level: developer

538: .seealso: PetscFListAddDynamic(), PetscFList
539: @*/
540: PetscErrorCode PetscFListGet(PetscFList list,char ***array,int *n)
541: {
543:   PetscInt       count = 0;
544:   PetscFList     klist = list;

547:   while (list) {
548:     list = list->next;
549:     count++;
550:   }
551:   PetscMalloc((count+1)*sizeof(char *),array);
552:   count = 0;
553:   while (klist) {
554:     (*array)[count] = klist->name;
555:     klist = klist->next;
556:     count++;
557:   }
558:   (*array)[count] = 0;
559:   *n = count+1;

561:   return(0);
562: }


567: /*@C
568:    PetscFListPrintTypes - Prints the methods available.

570:    Collective over MPI_Comm

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

581:    Level: developer

583: .seealso: PetscFListAddDynamic(), PetscFList
584: @*/
585: PetscErrorCode PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list)
586: {
588:   PetscInt       count = 0;
589:   char           p[64];

592:   if (!fd) fd = stdout;

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

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

610: /*@
611:     PetscFListDuplicate - Creates a new list from a given object list.

613:     Input Parameters:
614: .   fl   - pointer to list

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

619:     Level: developer

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

623: @*/
624: PetscErrorCode PetscFListDuplicate(PetscFList fl,PetscFList *nl)
625: {
627:   char           path[PETSC_MAX_PATH_LEN];

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


648: /*
649:     PetscFListConcat - joins name of a libary, and the path where it is located
650:     into a single string.

652:     Input Parameters:
653: .   path   - path to the library name.
654: .   name   - name of the library

656:     Output Parameters:
657: .   fullname - the name that is the union of the path and the library name,
658:                delimited by a semicolon, i.e., path:name

660:     Notes:
661:     If the path is NULL, assumes that the name, specified also includes
662:     the path as path:name

664: */
665: PetscErrorCode PetscFListConcat(const char path[],const char name[],char fullname[])
666: {
669:   if (path) {
670:     PetscStrcpy(fullname,path);
671:     PetscStrcat(fullname,":");
672:     PetscStrcat(fullname,name);
673:   } else {
674:     PetscStrcpy(fullname,name);
675:   }
676:   return(0);
677: }