Actual source code: reg.c


  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/private/petscimpl.h>
  7: #include <petscviewer.h>

  9: /*
 10:     This is the default list used by PETSc with the PetscDLLibrary register routines
 11: */
 12: PetscDLLibrary PetscDLLibrariesLoaded = NULL;

 14: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)

 16: static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
 17: {
 18:   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];

 20:   PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs));
 21:   PetscStrlcat(libs, name, sizeof(libs));
 22:   PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found);
 23:   if (*found) {
 24:     PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib);
 25:   } else {
 26:     PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs));
 27:     PetscStrlcat(libs, name, sizeof(libs));
 28:     PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found);
 29:     if (*found) PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib);
 30:   }
 31:   return 0;
 32: }
 33: #endif

 35: #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
 36: PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
 37: PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
 38:   #if !defined(PETSC_USE_COMPLEX)
 39: PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
 40:   #endif
 41: PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
 42: PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
 43: PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
 44: PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
 45: PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
 46: PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
 47: PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
 48: PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
 49: PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
 50: #endif
 51: #if defined(PETSC_HAVE_THREADSAFETY)
 52: static MPI_Comm PETSC_COMM_WORLD_INNER = 0, PETSC_COMM_SELF_INNER = 0;
 53: #endif

 55: /*
 56:     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
 57:     search path.
 58: */
 59: PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
 60: {
 61:   char     *libname[32];
 62:   PetscInt  nmax, i;
 63:   PetscBool preload = PETSC_FALSE;
 64: #if defined(PETSC_HAVE_ELEMENTAL)
 65:   PetscBool PetscInitialized = PetscInitializeCalled;
 66: #endif

 68: #if defined(PETSC_HAVE_THREADSAFETY)
 69:   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
 70:   preload = PETSC_TRUE;
 71: #endif

 73:   nmax = 32;
 74:   PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL);
 75:   for (i = 0; i < nmax; i++) {
 76:     PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]);
 77:     PetscFree(libname[i]);
 78:   }

 80:   PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL);
 81:   if (!preload) {
 82:     PetscSysInitializePackage();
 83:   } else {
 84: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
 85:     PetscBool found;
 86:   #if defined(PETSC_USE_SINGLE_LIBRARY)
 87:     PetscLoadDynamicLibrary("", &found);
 89:   #else
 90:     PetscLoadDynamicLibrary("sys", &found);
 92:     PetscLoadDynamicLibrary("vec", &found);
 94:     PetscLoadDynamicLibrary("mat", &found);
 96:     PetscLoadDynamicLibrary("dm", &found);
 98:     PetscLoadDynamicLibrary("ksp", &found);
100:     PetscLoadDynamicLibrary("snes", &found);
102:     PetscLoadDynamicLibrary("ts", &found);
104:     PetscLoadDynamicLibrary("tao", &found);
106:   #endif
107: #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
108:   #if defined(PETSC_USE_SINGLE_LIBRARY)
109:     AOInitializePackage();
110:     PetscSFInitializePackage();
111:     #if !defined(PETSC_USE_COMPLEX)
112:     CharacteristicInitializePackage();
113:     #endif
114:     ISInitializePackage();
115:     VecInitializePackage();
116:     MatInitializePackage();
117:     DMInitializePackage();
118:     PCInitializePackage();
119:     KSPInitializePackage();
120:     SNESInitializePackage();
121:     TSInitializePackage();
122:     TaoInitializePackage();
123:   #else
124:     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
125:   #endif
126: #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
127:   }

129: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
130:   {
131:     PetscBool found;
132:     PetscLoadDynamicLibrary("bamg", &found);
134:   }
135: #endif

137:   nmax = 32;
138:   PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL);
139:   for (i = 0; i < nmax; i++) {
140:     PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]);
141:     PetscFree(libname[i]);
142:   }

144: #if defined(PETSC_HAVE_THREADSAFETY)
145:   PetscCommDuplicate(PETSC_COMM_SELF, &PETSC_COMM_SELF_INNER, NULL);
146:   PetscCommDuplicate(PETSC_COMM_WORLD, &PETSC_COMM_WORLD_INNER, NULL);
147: #endif
148: #if defined(PETSC_HAVE_ELEMENTAL)
149:   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
150:   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
151:   PetscInitializeCalled = PETSC_TRUE;
152:   PetscElementalInitializePackage();
153:   PetscInitializeCalled = PetscInitialized;
154: #endif
155:   return 0;
156: }

158: /*
159:      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
160: */
161: PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
162: {
163:   PetscBool flg = PETSC_FALSE;

165:   PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL);
166:   if (flg) PetscDLLibraryPrintPath(PetscDLLibrariesLoaded);
167:   PetscDLLibraryClose(PetscDLLibrariesLoaded);

169: #if defined(PETSC_HAVE_THREADSAFETY)
170:   PetscCommDestroy(&PETSC_COMM_SELF_INNER);
171:   PetscCommDestroy(&PETSC_COMM_WORLD_INNER);
172: #endif

174:   PetscDLLibrariesLoaded = NULL;
175:   return 0;
176: }

178: /* ------------------------------------------------------------------------------*/
179: struct _n_PetscFunctionList {
180:   void (*routine)(void);       /* the routine */
181:   char             *name;      /* string to identify routine */
182:   PetscFunctionList next;      /* next pointer */
183:   PetscFunctionList next_list; /* used to maintain list of all lists for freeing */
184: };

186: /*
187:      Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones.
188: */
189: static PetscFunctionList dlallhead = NULL;

191: static PetscErrorCode PetscFunctionListCreateNode_Private(PetscFunctionList *entry, const char name[], void (*func)(void))
192: {
193:   PetscNew(entry);
194:   PetscStrallocpy(name, &(*entry)->name);
195:   (*entry)->routine = func;
196:   (*entry)->next    = NULL;
197:   return 0;
198: }

200: /*MC
201:    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
202:    specified registry.

204:    Synopsis:
205: #include <petscsys.h>
206:    PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))

208:    Not Collective

210:    Input Parameters:
211: +  flist - pointer to function list object
212: .  name - string to identify routine
213: -  fptr - function pointer

215:    Notes:
216:    To remove a registered routine, pass in a NULL fptr.

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

223:     Level: developer

225: .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,
226:           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
227: M*/
228: PETSC_EXTERN PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], void (*fnc)(void))
229: {
233:   if (*fl) {
234:     /* search list to see if it is already there */
235:     PetscFunctionList empty_node = NULL;
236:     PetscFunctionList ne         = *fl;

238:     while (1) {
239:       PetscBool founddup;

241:       PetscStrcmp(ne->name, name, &founddup);
242:       if (founddup) {
243:         /* found duplicate, clear it */
244:         ne->routine = fnc;
245:         if (!fnc) PetscFree(ne->name);
246:         return 0;
247:       }

249:       if (!empty_node && !ne->routine && !ne->name) {
250:         /* save the empty node for later */
251:         empty_node = ne;
252:       }

254:       if (!ne->next) break; /* end of list */
255:       ne = ne->next;
256:     }

258:     /* there was an empty entry we could grab, fill it and bail */
259:     if (empty_node) {
260:       empty_node->routine = fnc;
261:       PetscStrallocpy(name, &empty_node->name);
262:     } else {
263:       /* create new entry at the end of list */
264:       PetscFunctionListCreateNode_Private(&ne->next, name, fnc);
265:     }
266:     return 0;
267:   }

269:   /* we didn't have a list */
270:   PetscFunctionListCreateNode_Private(fl, name, fnc);
271:   if (PetscDefined(USE_DEBUG)) {
272:     const PetscFunctionList head = dlallhead;

274:     /* add this new list to list of all lists */
275:     dlallhead        = *fl;
276:     (*fl)->next_list = head;
277:   }
278:   return 0;
279: }

281: /*@
282:     PetscFunctionListDestroy - Destroys a list of registered routines.

284:     Input Parameter:
285: .   fl  - pointer to list

287:     Level: developer

289: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
290: @*/
291: PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
292: {
293:   PetscFunctionList next, entry, tmp = dlallhead;

295:   if (!*fl) return 0;

297:   /*
298:        Remove this entry from the main DL list (if it is in it)
299:   */
300:   if (dlallhead == *fl) {
301:     if (dlallhead->next_list) dlallhead = dlallhead->next_list;
302:     else dlallhead = NULL;
303:   } else if (tmp) {
304:     while (tmp->next_list != *fl) {
305:       tmp = tmp->next_list;
306:       if (!tmp->next_list) break;
307:     }
308:     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
309:   }

311:   /* free this list */
312:   entry = *fl;
313:   while (entry) {
314:     next = entry->next;
315:     PetscFree(entry->name);
316:     PetscFree(entry);
317:     entry = next;
318:   }
319:   *fl = NULL;
320:   return 0;
321: }

323: /*@
324:   PetscFunctionListClear - Clear a `PetscFunctionList`

326:   Not Collective

328:   Input Parameter:
329: . fl - The `PetscFunctionList` to clear

331:   Notes:
332:   This clears the contents of `fl` but does not deallocate the entries themselves.

334:   Level: developer

336: .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
337: @*/
338: PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
339: {
340:   /* free the names and clear the routine but don't deallocate the node */
341:   while (fl) {
342:     PetscFree(fl->name);
343:     fl->routine = NULL;
344:     fl          = fl->next;
345:   }
346:   return 0;
347: }

349: /*
350:    Print registered PetscFunctionLists
351: */
352: PetscErrorCode PetscFunctionListPrintAll(void)
353: {
354:   PetscFunctionList tmp = dlallhead;

356:   if (tmp) PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank);
357:   while (tmp) {
358:     PetscPrintf(PETSC_COMM_SELF, "[%d]   %s\n", PetscGlobalRank, tmp->name);
359:     tmp = tmp->next_list;
360:   }
361:   return 0;
362: }

364: /*MC
365:     PetscFunctionListNonEmpty - Print composed names for non null function pointers

367:     Input Parameter:
368: .   flist   - pointer to list

370:     Level: developer

372: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
373: M*/
374: PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
375: {
376:   while (fl) {
377:     PetscFunctionList next = fl->next;
378:     if (fl->routine) PetscPrintf(PETSC_COMM_SELF, "[%d] function name: %s\n", PetscGlobalRank, fl->name);
379:     fl = next;
380:   }
381:   return 0;
382: }

384: /*MC
385:     PetscFunctionListFind - Find function registered under given name

387:     Synopsis:
388: #include <petscsys.h>
389:     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))

391:     Input Parameters:
392: +   flist   - pointer to list
393: -   name - name registered for the function

395:     Output Parameters:
396: .   fptr - the function pointer if name was found, else NULL

398:     Level: developer

400: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
401: M*/
402: PETSC_EXTERN PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], void (**r)(void))
403: {
404:   PetscFunctionList entry = fl;

408:   while (entry) {
409:     PetscBool flg;

411:     PetscStrcmp(name, entry->name, &flg);
412:     if (flg) {
413:       *r = entry->routine;
414:       return 0;
415:     }
416:     entry = entry->next;
417:   }
418:   *r = NULL;
419:   return 0;
420: }

422: /*@
423:    PetscFunctionListView - prints out contents of an PetscFunctionList

425:    Collective over viewer

427:    Input Parameters:
428: +  list - the list of functions
429: -  viewer - currently ignored

431:    Level: developer

433: .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
434: @*/
435: PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
436: {
437:   PetscBool iascii;

439:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;

443:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);

446:   while (list) {
447:     PetscViewerASCIIPrintf(viewer, " %s\n", list->name);
448:     list = list->next;
449:   }
450:   PetscViewerASCIIPrintf(viewer, "\n");
451:   return 0;
452: }

454: /*@C
455:    PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
456:          by help etc.

458:    Not Collective

460:    Input Parameter:
461: .  list   - list of types

463:    Output Parameters:
464: +  array - array of names
465: -  n - length of array

467:    Note:
468:        This allocates the array so that must be freed. BUT the individual entries are
469:     not copied so should not be freed.

471:    Level: developer

473: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
474: @*/
475: PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
476: {
477:   PetscInt          count = 0;
478:   PetscFunctionList klist = list;

480:   while (list) {
481:     list = list->next;
482:     count++;
483:   }
484:   PetscMalloc1(count + 1, (char ***)array);
485:   count = 0;
486:   while (klist) {
487:     (*array)[count] = klist->name;
488:     klist           = klist->next;
489:     count++;
490:   }
491:   (*array)[count] = NULL;
492:   *n              = count + 1;
493:   return 0;
494: }

496: /*@C
497:    PetscFunctionListPrintTypes - Prints the methods available in a list of functions

499:    Collective over MPI_Comm

501:    Input Parameters:
502: +  comm   - the communicator (usually `MPI_COMM_WORLD`)
503: .  fd     - file to print to, usually stdout
504: .  prefix - prefix to prepend to name (optional)
505: .  name   - option string (for example, "-ksp_type")
506: .  text - short description of the object (for example, "Krylov solvers")
507: .  man - name of manual page that discusses the object (for example, "KSPCreate")
508: .  list   - list of types
509: .  def - default (current) value
510: -  newv - new value

512:    Level: developer

514: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
515: @*/
516: PetscErrorCode PetscFunctionListPrintTypes(MPI_Comm comm, FILE *fd, const char prefix[], const char name[], const char text[], const char man[], PetscFunctionList list, const char def[], const char newv[])
517: {
518:   char p[64];

520:   if (!fd) fd = PETSC_STDOUT;

522:   PetscStrncpy(p, "-", sizeof(p));
523:   if (prefix) PetscStrlcat(p, prefix, sizeof(p));
524:   PetscFPrintf(comm, fd, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text);

526:   while (list) {
527:     PetscFPrintf(comm, fd, " %s", list->name);
528:     list = list->next;
529:   }
530:   PetscFPrintf(comm, fd, " (%s)\n", man);
531:   return 0;
532: }

534: /*@
535:     PetscFunctionListDuplicate - Creates a new list from a given object list.

537:     Input Parameters:
538: .   fl   - pointer to list

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

543:     Level: developer

545: .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
546: @*/
547: PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
548: {
549:   while (fl) {
550:     PetscFunctionListAdd(nl, fl->name, fl->routine);
551:     fl = fl->next;
552:   }
553:   return 0;
554: }