xref: /petsc/src/sys/dll/reg.c (revision 2ff79c18c26c94ed8cb599682f680f231dca6444)
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/private/petscimpl.h> /*I "petscsys.h" I*/
6 #include <petscviewer.h>
7 
8 #include <petsc/private/hashmap.h>
9 /*
10     This is the default list used by PETSc with the PetscDLLibrary register routines
11 */
12 PetscDLLibrary PetscDLLibrariesLoaded = NULL;
13 
14 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
15 
16 static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
17 {
18   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
19 
20   PetscFunctionBegin;
21   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
22   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
23   #if defined(PETSC_LIB_NAME_SUFFIX)
24   PetscCall(PetscStrlcat(libs, PETSC_LIB_NAME_SUFFIX, sizeof(libs)));
25   #endif
26   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
27   if (*found) {
28     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
29   } else {
30     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
31     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
32   #if defined(PETSC_LIB_NAME_SUFFIX)
33     PetscCall(PetscStrlcat(libs, PETSC_LIB_NAME_SUFFIX, sizeof(libs)));
34   #endif
35     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
36     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
37   }
38   PetscFunctionReturn(PETSC_SUCCESS);
39 }
40 #endif
41 
42 #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
43 PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
44 PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
45   #if !defined(PETSC_USE_COMPLEX)
46 PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
47   #endif
48 PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
49 PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
50 PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
51 PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
52 PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
53 PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
54 PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
55 PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
56 PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
57 #endif
58 
59 /*
60     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
61     search path.
62 */
63 PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
64 {
65   char     *libname[32];
66   PetscInt  nmax, i;
67   PetscBool preload = PETSC_FALSE;
68 #if defined(PETSC_HAVE_ELEMENTAL)
69   PetscBool PetscInitialized = PetscInitializeCalled;
70 #endif
71 
72   PetscFunctionBegin;
73 #if defined(PETSC_HAVE_THREADSAFETY)
74   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
75   preload = PETSC_TRUE;
76 #endif
77 
78   nmax = 32;
79   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
80   for (i = 0; i < nmax; i++) {
81     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
82     PetscCall(PetscFree(libname[i]));
83   }
84 
85   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
86   if (!preload) {
87     PetscCall(PetscSysInitializePackage());
88   } else {
89 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
90     PetscBool found;
91   #if defined(PETSC_USE_SINGLE_LIBRARY)
92     PetscCall(PetscLoadDynamicLibrary("", &found));
93     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library. You cannot move the dynamic libraries!");
94   #else
95     PetscCall(PetscLoadDynamicLibrary("sys", &found));
96     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Sys dynamic library. You cannot move the dynamic libraries!");
97     PetscCall(PetscLoadDynamicLibrary("vec", &found));
98     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library. You cannot move the dynamic libraries!");
99     PetscCall(PetscLoadDynamicLibrary("mat", &found));
100     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library. You cannot move the dynamic libraries!");
101     PetscCall(PetscLoadDynamicLibrary("dm", &found));
102     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library. You cannot move the dynamic libraries!");
103     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
104     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library. You cannot move the dynamic libraries!");
105     PetscCall(PetscLoadDynamicLibrary("snes", &found));
106     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library. You cannot move the dynamic libraries!");
107     PetscCall(PetscLoadDynamicLibrary("ts", &found));
108     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library. You cannot move the dynamic libraries!");
109     PetscCall(PetscLoadDynamicLibrary("tao", &found));
110     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library. You cannot move the dynamic libraries!");
111   #endif
112 #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
113   #if defined(PETSC_USE_SINGLE_LIBRARY)
114     PetscCall(AOInitializePackage());
115     PetscCall(PetscSFInitializePackage());
116     #if !defined(PETSC_USE_COMPLEX)
117     PetscCall(CharacteristicInitializePackage());
118     #endif
119     PetscCall(ISInitializePackage());
120     PetscCall(VecInitializePackage());
121     PetscCall(MatInitializePackage());
122     PetscCall(DMInitializePackage());
123     PetscCall(PCInitializePackage());
124     PetscCall(KSPInitializePackage());
125     PetscCall(SNESInitializePackage());
126     PetscCall(TSInitializePackage());
127     PetscCall(TaoInitializePackage());
128   #else
129     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
130   #endif
131 #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
132   }
133 
134 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
135   {
136     PetscBool found;
137     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
138     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library. You cannot move the dynamic libraries!");
139   }
140 #endif
141 
142   nmax = 32;
143   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
144   for (i = 0; i < nmax; i++) {
145     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
146     PetscCall(PetscFree(libname[i]));
147   }
148 
149 #if defined(PETSC_HAVE_ELEMENTAL)
150   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
151   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
152   PetscInitializeCalled = PETSC_TRUE;
153   PetscCall(PetscElementalInitializePackage());
154   PetscInitializeCalled = PetscInitialized;
155 #endif
156   PetscFunctionReturn(PETSC_SUCCESS);
157 }
158 
159 /*
160      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
161 */
162 PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
163 {
164   PetscBool flg = PETSC_FALSE;
165 
166   PetscFunctionBegin;
167   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
168   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
169   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
170   PetscDLLibrariesLoaded = NULL;
171   PetscFunctionReturn(PETSC_SUCCESS);
172 }
173 
174 PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFn *, kh_str_hash_func, kh_str_hash_equal, NULL)
175 
176 struct _n_PetscFunctionList {
177   PetscHMapFunc map;
178 };
179 
180 /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
181 typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
182 struct n_PetscFunctionListDLAll {
183   PetscFunctionList      data;
184   PetscFunctionListDLAll next;
185 };
186 
187 static PetscFunctionListDLAll dlallhead = NULL;
188 
189 static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
190 {
191   PetscFunctionBegin;
192   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
193     PetscFunctionListDLAll head;
194 
195     PetscCall(PetscNew(&head));
196     head->data = fl;
197     head->next = dlallhead;
198     dlallhead  = head;
199   }
200   PetscFunctionReturn(PETSC_SUCCESS);
201 }
202 
203 static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
204 {
205   PetscFunctionBegin;
206   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
207     PetscFunctionListDLAll current = dlallhead, prev = NULL;
208 
209     /* Remove this entry from the main DL list (if it is in it) */
210     while (current) {
211       const PetscFunctionListDLAll next = current->next;
212 
213       if (current->data == fl) {
214         if (prev) {
215           // somewhere in the middle (or end) of the list
216           prev->next = next;
217         } else {
218           // prev = NULL implies current = dlallhead, so front of list
219           dlallhead = next;
220         }
221         PetscCall(PetscFree(current));
222         break;
223       }
224       prev    = current;
225       current = next;
226     }
227   }
228   PetscFunctionReturn(PETSC_SUCCESS);
229 }
230 
231 static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFn *fnc)
232 {
233   PetscHashIter it;
234   PetscBool     found;
235 
236   PetscFunctionBegin;
237   PetscAssertPointer(name, 2);
238   if (fnc) PetscValidFunction(fnc, 3);
239   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
240   if (fnc) {
241     if (found) {
242       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
243     } else {
244       char *tmp_name;
245 
246       PetscCall(PetscStrallocpy(name, &tmp_name));
247       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
248     }
249   } else if (found) {
250     const char *tmp_name;
251 
252     PetscHashIterGetKey(map, it, tmp_name);
253     PetscCall(PetscFree(tmp_name));
254     PetscCall(PetscHMapFuncIterDel(map, it));
255   }
256   PetscFunctionReturn(PETSC_SUCCESS);
257 }
258 
259 static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
260 {
261   PetscFunctionBegin;
262   if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
263   PetscCall(PetscNew(fl));
264   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
265   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
266   PetscFunctionReturn(PETSC_SUCCESS);
267 }
268 
269 /*MC
270   PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
271   specified registry.
272 
273   Synopsis:
274   #include <petscsys.h>
275   PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
276 
277   Not Collective
278 
279   Input Parameters:
280 + fl   - pointer to function list object
281 . name - string to identify routine
282 - fptr - function pointer
283 
284   Level: developer
285 
286   Notes:
287   To remove a registered routine, pass in a `NULL` `fptr`.
288 
289   Users who wish to register new classes for use by a particular PETSc
290   component (e.g., `SNES`) should generally call the registration routine
291   for that particular component (e.g., `SNESRegister()`) instead of
292   calling `PetscFunctionListAdd()` directly.
293 
294 .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,`PetscFunctionListDuplicate()`
295           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
296 M*/
297 PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFn *fptr)
298 {
299   PetscFunctionBegin;
300   PetscAssertPointer(fl, 1);
301   if (name) PetscAssertPointer(name, 2);
302   if (fptr) PetscValidFunction(fptr, 3);
303   if (!fptr && !*fl) PetscFunctionReturn(PETSC_SUCCESS);
304   PetscCall(PetscFunctionListCreate_Private(0, fl));
305   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fptr));
306   PetscFunctionReturn(PETSC_SUCCESS);
307 }
308 
309 /*@C
310   PetscFunctionListDestroy - Destroys a list of registered routines.
311 
312   Input Parameter:
313 . fl - pointer to list
314 
315   Level: developer
316 
317 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
318 @*/
319 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
320 {
321   PetscFunctionBegin;
322   if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
323   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
324   /* free this list */
325   PetscCall(PetscFunctionListClear(*fl));
326   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
327   PetscCall(PetscFree(*fl));
328   PetscFunctionReturn(PETSC_SUCCESS);
329 }
330 
331 #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
332   do { \
333     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
334     PetscHashIter       phmfi_iter_; \
335 \
336     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
337     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
338       const char *PETSC_UNUSED  __key_name__; \
339       PetscVoidFn *PETSC_UNUSED __val_name__; \
340 \
341       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
342       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
343       { \
344         __VA_ARGS__; \
345       } \
346       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
347     } /* end while */ \
348   } while (0)
349 
350 /*@C
351   PetscFunctionListClear - Clear a `PetscFunctionList`
352 
353   Not Collective
354 
355   Input Parameter:
356 . fl - The `PetscFunctionList` to clear
357 
358   Level: developer
359 
360   Notes:
361   This clears the contents of `fl` but does not deallocate the entries themselves.
362 
363 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
364 @*/
365 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
366 {
367   PetscFunctionBegin;
368   if (fl) {
369     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
370     PetscCall(PetscHMapFuncClear(fl->map));
371   }
372   PetscFunctionReturn(PETSC_SUCCESS);
373 }
374 
375 /*
376    Print registered PetscFunctionLists
377 */
378 PetscErrorCode PetscFunctionListPrintAll(void)
379 {
380   PetscFunctionListDLAll current = dlallhead;
381 
382   PetscFunctionBegin;
383   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
384   while (current) {
385     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
386     current = current->next;
387   }
388   PetscFunctionReturn(PETSC_SUCCESS);
389 }
390 
391 /*@C
392   PetscFunctionListPrintNonEmpty - Print composed names for non `NULL` function pointers
393 
394   Logically Collective, No Fortran Support
395 
396   Input Parameter:
397 . fl - the function list
398 
399   Level: developer
400 
401 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
402 @*/
403 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
404 {
405   PetscFunctionBegin;
406   if (fl) {
407     // clang-format off
408     PetscHMapFuncForEach(
409       fl,
410       name, func,
411       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
412     );
413     // clang-format on
414   }
415   PetscFunctionReturn(PETSC_SUCCESS);
416 }
417 
418 /*MC
419   PetscFunctionListFind - Find function registered under given name
420 
421   Not Collective, No Fortran Support
422 
423   Synopsis:
424   #include <petscsys.h>
425   PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
426 
427   Input Parameters:
428 + fl   - the function list
429 - name - name registered for the function
430 
431   Output Parameter:
432 . fptr - the function pointer if name was found, else `NULL`
433 
434   Level: developer
435 
436 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`, `PetscFunctionListDuplicate()`
437 M*/
438 PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFn **fptr)
439 {
440   PetscFunctionBegin;
441   PetscAssertPointer(name, 2);
442   PetscAssertPointer(fptr, 3);
443   *fptr = NULL;
444   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, fptr));
445   PetscFunctionReturn(PETSC_SUCCESS);
446 }
447 
448 /*@C
449   PetscFunctionListView - prints out contents of a `PetscFunctionList`
450 
451   Collective
452 
453   Input Parameters:
454 + list   - the list of functions
455 - viewer - the `PetscViewer` used to view the `PetscFunctionList`
456 
457   Level: developer
458 
459 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
460 @*/
461 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
462 {
463   PetscBool isascii;
464 
465   PetscFunctionBegin;
466   PetscAssertPointer(list, 1);
467   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
468   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
469 
470   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
471   PetscCheck(isascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
472   {
473     PetscInt size;
474 
475     PetscCall(PetscHMapFuncGetSize(list->map, &size));
476     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
477     PetscCall(PetscViewerASCIIPushTab(viewer));
478     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
479     if (size) {
480       PetscInt count = 0;
481 
482       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
483       PetscCall(PetscViewerASCIIPushTab(viewer));
484       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
485       PetscCall(PetscViewerASCIIPopTab(viewer));
486     }
487     PetscCall(PetscViewerASCIIPopTab(viewer));
488   }
489   PetscFunctionReturn(PETSC_SUCCESS);
490 }
491 
492 /*@C
493   PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
494   by help etc.
495 
496   Not Collective, No Fortran Support
497 
498   Input Parameter:
499 . list - list of types
500 
501   Output Parameters:
502 + array - array of names
503 - n     - length of `array`
504 
505   Level: developer
506 
507   Note:
508   This allocates the array so that must be freed with `PetscFree()`. BUT the individual entries should not be freed.
509 
510 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
511 @*/
512 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
513 {
514   PetscInt size = 0;
515 
516   PetscFunctionBegin;
517   PetscAssertPointer(array, 2);
518   *array = NULL;
519   if (list) {
520     const PetscHMapFunc map = list->map;
521     PetscInt            off = 0;
522 
523     PetscCall(PetscHMapFuncGetSize(map, &size));
524     PetscCall(PetscMalloc1(size, (char ***)array));
525     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
526   }
527   PetscCall(PetscCIntCast(size, n));
528   PetscFunctionReturn(PETSC_SUCCESS);
529 }
530 
531 /*@C
532   PetscFunctionListPrintTypes - Prints the methods available in a list of functions
533 
534   Collective, No Fortran Support
535 
536   Input Parameters:
537 + comm   - the communicator (usually `MPI_COMM_WORLD`)
538 . fd     - file to print to, usually `stdout`
539 . prefix - prefix to prepend to name (optional)
540 . name   - option string (for example, `-ksp_type`)
541 . text   - short description of the object (for example, "Krylov solvers")
542 . man    - name of manual page that discusses the object (for example, `KSPCreate`)
543 . list   - list of types
544 . def    - default (current) value
545 - newv   - new value
546 
547   Level: developer
548 
549 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
550 @*/
551 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[])
552 {
553   char p[64];
554 
555   PetscFunctionBegin;
556   (void)fd;
557   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
558   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
559   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
560 
561   if (list) PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
562   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
563   PetscFunctionReturn(PETSC_SUCCESS);
564 }
565 
566 /*@C
567   PetscFunctionListDuplicate - Creates a new list from a given function list `PetscFunctionList`.
568 
569   Input Parameter:
570 . fl - pointer to list
571 
572   Output Parameter:
573 . nl - the new list (should point to `NULL` to start, otherwise appends)
574 
575   Level: developer
576 
577 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
578 @*/
579 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
580 {
581   PetscFunctionBegin;
582   if (fl) {
583     PetscHMapFunc dup_map;
584 
585     if (!*nl) {
586       PetscInt n;
587 
588       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
589       PetscCall(PetscFunctionListCreate_Private(n, nl));
590     }
591     dup_map = (*nl)->map;
592     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
593   }
594   PetscFunctionReturn(PETSC_SUCCESS);
595 }
596