xref: /petsc/src/sys/dll/reg.c (revision 750b007cd8d816cecd9de99077bb0a703b4cf61a)
1 
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> /*I "petscsys.h" I*/
7 #include <petscviewer.h>
8 
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   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
18 
19   PetscFunctionBegin;
20   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
21   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
22   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
23   if (*found) {
24     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
25   } else {
26     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
27     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
28     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
29     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
30   }
31   PetscFunctionReturn(0);
32 }
33 #endif
34 
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
54 
55 /*
56     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
57     search path.
58 */
59 PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void) {
60   char     *libname[32];
61   PetscInt  nmax, i;
62   PetscBool preload = PETSC_FALSE;
63 #if defined(PETSC_HAVE_ELEMENTAL)
64   PetscBool PetscInitialized = PetscInitializeCalled;
65 #endif
66 
67   PetscFunctionBegin;
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
72 
73   nmax = 32;
74   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
75   for (i = 0; i < nmax; i++) {
76     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
77     PetscCall(PetscFree(libname[i]));
78   }
79 
80   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
81   if (!preload) {
82     PetscCall(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     PetscCall(PetscLoadDynamicLibrary("", &found));
88     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
89 #else
90     PetscCall(PetscLoadDynamicLibrary("sys", &found));
91     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
92     PetscCall(PetscLoadDynamicLibrary("vec", &found));
93     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
94     PetscCall(PetscLoadDynamicLibrary("mat", &found));
95     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
96     PetscCall(PetscLoadDynamicLibrary("dm", &found));
97     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
98     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
99     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
100     PetscCall(PetscLoadDynamicLibrary("snes", &found));
101     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
102     PetscCall(PetscLoadDynamicLibrary("ts", &found));
103     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
104     PetscCall(PetscLoadDynamicLibrary("tao", &found));
105     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library \n You cannot move the dynamic libraries!");
106 #endif
107 #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
108 #if defined(PETSC_USE_SINGLE_LIBRARY)
109     PetscCall(AOInitializePackage());
110     PetscCall(PetscSFInitializePackage());
111 #if !defined(PETSC_USE_COMPLEX)
112     PetscCall(CharacteristicInitializePackage());
113 #endif
114     PetscCall(ISInitializePackage());
115     PetscCall(VecInitializePackage());
116     PetscCall(MatInitializePackage());
117     PetscCall(DMInitializePackage());
118     PetscCall(PCInitializePackage());
119     PetscCall(KSPInitializePackage());
120     PetscCall(SNESInitializePackage());
121     PetscCall(TSInitializePackage());
122     PetscCall(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   }
128 
129 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
130   {
131     PetscBool found;
132     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
133     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library \n You cannot move the dynamic libraries!");
134   }
135 #endif
136 
137   nmax = 32;
138   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
139   for (i = 0; i < nmax; i++) {
140     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
141     PetscCall(PetscFree(libname[i]));
142   }
143 
144 #if defined(PETSC_HAVE_THREADSAFETY)
145   PetscCall(PetscCommDuplicate(PETSC_COMM_SELF, &PETSC_COMM_SELF_INNER, NULL));
146   PetscCall(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   PetscCall(PetscElementalInitializePackage());
153   PetscInitializeCalled = PetscInitialized;
154 #endif
155   PetscFunctionReturn(0);
156 }
157 
158 /*
159      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
160 */
161 PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void) {
162   PetscBool flg = PETSC_FALSE;
163 
164   PetscFunctionBegin;
165   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
166   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
167   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
168 
169 #if defined(PETSC_HAVE_THREADSAFETY)
170   PetscCall(PetscCommDestroy(&PETSC_COMM_SELF_INNER));
171   PetscCall(PetscCommDestroy(&PETSC_COMM_WORLD_INNER));
172 #endif
173 
174   PetscDLLibrariesLoaded = NULL;
175   PetscFunctionReturn(0);
176 }
177 
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 };
185 
186 /*
187      Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones.
188 */
189 static PetscFunctionList dlallhead = NULL;
190 
191 static PetscErrorCode PetscFunctionListCreateNode_Private(PetscFunctionList *entry, const char name[], void (*func)(void)) {
192   PetscFunctionBegin;
193   PetscCall(PetscNew(entry));
194   PetscCall(PetscStrallocpy(name, &(*entry)->name));
195   (*entry)->routine = func;
196   (*entry)->next    = NULL;
197   PetscFunctionReturn(0);
198 }
199 
200 /*MC
201    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
202    specified registry.
203 
204    Synopsis:
205    #include <petscsys.h>
206    PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
207 
208    Not Collective
209 
210    Input Parameters:
211 +  flist - pointer to function list object
212 .  name - string to identify routine
213 -  fptr - function pointer
214 
215    Notes:
216    To remove a registered routine, pass in a NULL fptr.
217 
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.
222 
223     Level: developer
224 
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   PetscFunctionBegin;
230   PetscValidPointer(fl, 1);
231   if (name) PetscValidCharPointer(name, 2);
232   if (fnc) PetscValidFunction(fnc, 3);
233   if (*fl) {
234     /* search list to see if it is already there */
235     PetscFunctionList empty_node = NULL;
236     PetscFunctionList ne         = *fl;
237 
238     while (1) {
239       PetscBool founddup;
240 
241       PetscCall(PetscStrcmp(ne->name, name, &founddup));
242       if (founddup) {
243         /* found duplicate, clear it */
244         ne->routine = fnc;
245         if (!fnc) PetscCall(PetscFree(ne->name));
246         PetscFunctionReturn(0);
247       }
248 
249       if (!empty_node && !ne->routine && !ne->name) {
250         /* save the empty node for later */
251         empty_node = ne;
252       }
253 
254       if (!ne->next) break; /* end of list */
255       ne = ne->next;
256     }
257 
258     /* there was an empty entry we could grab, fill it and bail */
259     if (empty_node) {
260       empty_node->routine = fnc;
261       PetscCall(PetscStrallocpy(name, &empty_node->name));
262     } else {
263       /* create new entry at the end of list */
264       PetscCall(PetscFunctionListCreateNode_Private(&ne->next, name, fnc));
265     }
266     PetscFunctionReturn(0);
267   }
268 
269   /* we didn't have a list */
270   PetscCall(PetscFunctionListCreateNode_Private(fl, name, fnc));
271   if (PetscDefined(USE_DEBUG)) {
272     const PetscFunctionList head = dlallhead;
273 
274     /* add this new list to list of all lists */
275     dlallhead        = *fl;
276     (*fl)->next_list = head;
277   }
278   PetscFunctionReturn(0);
279 }
280 
281 /*@
282     PetscFunctionListDestroy - Destroys a list of registered routines.
283 
284     Input Parameter:
285 .   fl  - pointer to list
286 
287     Level: developer
288 
289 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
290 @*/
291 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl) {
292   PetscFunctionList next, entry, tmp = dlallhead;
293 
294   PetscFunctionBegin;
295   if (!*fl) PetscFunctionReturn(0);
296 
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   }
310 
311   /* free this list */
312   entry = *fl;
313   while (entry) {
314     next = entry->next;
315     PetscCall(PetscFree(entry->name));
316     PetscCall(PetscFree(entry));
317     entry = next;
318   }
319   *fl = NULL;
320   PetscFunctionReturn(0);
321 }
322 
323 /*@
324   PetscFunctionListClear - Clear a `PetscFunctionList`
325 
326   Not Collective
327 
328   Input Parameter:
329 . fl - The `PetscFunctionList` to clear
330 
331   Notes:
332   This clears the contents of `fl` but does not deallocate the entries themselves.
333 
334   Level: developer
335 
336 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
337 @*/
338 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl) {
339   PetscFunctionBegin;
340   /* free the names and clear the routine but don't deallocate the node */
341   while (fl) {
342     PetscCall(PetscFree(fl->name));
343     fl->routine = NULL;
344     fl          = fl->next;
345   }
346   PetscFunctionReturn(0);
347 }
348 
349 /*
350    Print registered PetscFunctionLists
351 */
352 PetscErrorCode PetscFunctionListPrintAll(void) {
353   PetscFunctionList tmp = dlallhead;
354 
355   PetscFunctionBegin;
356   if (tmp) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
357   while (tmp) {
358     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d]   %s\n", PetscGlobalRank, tmp->name));
359     tmp = tmp->next_list;
360   }
361   PetscFunctionReturn(0);
362 }
363 
364 /*MC
365     PetscFunctionListNonEmpty - Print composed names for non null function pointers
366 
367     Input Parameter:
368 .   flist   - pointer to list
369 
370     Level: developer
371 
372 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
373 M*/
374 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl) {
375   PetscFunctionBegin;
376   while (fl) {
377     PetscFunctionList next = fl->next;
378     if (fl->routine) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] function name: %s\n", PetscGlobalRank, fl->name));
379     fl = next;
380   }
381   PetscFunctionReturn(0);
382 }
383 
384 /*MC
385     PetscFunctionListFind - Find function registered under given name
386 
387     Synopsis:
388     #include <petscsys.h>
389     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
390 
391     Input Parameters:
392 +   flist   - pointer to list
393 -   name - name registered for the function
394 
395     Output Parameters:
396 .   fptr - the function pointer if name was found, else NULL
397 
398     Level: developer
399 
400 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
401 M*/
402 PETSC_EXTERN PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], void (**r)(void)) {
403   PetscFunctionList entry = fl;
404 
405   PetscFunctionBegin;
406   PetscValidCharPointer(name, 2);
407   PetscValidPointer(r, 3);
408   while (entry) {
409     PetscBool flg;
410 
411     PetscCall(PetscStrcmp(name, entry->name, &flg));
412     if (flg) {
413       *r = entry->routine;
414       PetscFunctionReturn(0);
415     }
416     entry = entry->next;
417   }
418   *r = NULL;
419   PetscFunctionReturn(0);
420 }
421 
422 /*@
423    PetscFunctionListView - prints out contents of an PetscFunctionList
424 
425    Collective over viewer
426 
427    Input Parameters:
428 +  list - the list of functions
429 -  viewer - currently ignored
430 
431    Level: developer
432 
433 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
434 @*/
435 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer) {
436   PetscBool iascii;
437 
438   PetscFunctionBegin;
439   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
440   PetscValidPointer(list, 1);
441   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
442 
443   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
444   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
445 
446   while (list) {
447     PetscCall(PetscViewerASCIIPrintf(viewer, " %s\n", list->name));
448     list = list->next;
449   }
450   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
451   PetscFunctionReturn(0);
452 }
453 
454 /*@C
455    PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
456          by help etc.
457 
458    Not Collective
459 
460    Input Parameter:
461 .  list   - list of types
462 
463    Output Parameters:
464 +  array - array of names
465 -  n - length of array
466 
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.
470 
471    Level: developer
472 
473 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
474 @*/
475 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n) {
476   PetscInt          count = 0;
477   PetscFunctionList klist = list;
478 
479   PetscFunctionBegin;
480   while (list) {
481     list = list->next;
482     count++;
483   }
484   PetscCall(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   PetscFunctionReturn(0);
494 }
495 
496 /*@C
497    PetscFunctionListPrintTypes - Prints the methods available in a list of functions
498 
499    Collective over MPI_Comm
500 
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
511 
512    Level: developer
513 
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   char p[64];
518 
519   PetscFunctionBegin;
520   if (!fd) fd = PETSC_STDOUT;
521 
522   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
523   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
524   PetscCall(PetscFPrintf(comm, fd, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
525 
526   while (list) {
527     PetscCall(PetscFPrintf(comm, fd, " %s", list->name));
528     list = list->next;
529   }
530   PetscCall(PetscFPrintf(comm, fd, " (%s)\n", man));
531   PetscFunctionReturn(0);
532 }
533 
534 /*@
535     PetscFunctionListDuplicate - Creates a new list from a given object list.
536 
537     Input Parameters:
538 .   fl   - pointer to list
539 
540     Output Parameters:
541 .   nl - the new list (should point to 0 to start, otherwise appends)
542 
543     Level: developer
544 
545 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
546 @*/
547 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl) {
548   PetscFunctionBegin;
549   while (fl) {
550     PetscCall(PetscFunctionListAdd(nl, fl->name, fl->routine));
551     fl = fl->next;
552   }
553   PetscFunctionReturn(0);
554 }
555