xref: /petsc/src/sys/dll/reg.c (revision 2291d37ff9f2707ae4fb2adee7b6024b8e94bc95)
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 {
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   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
24   if (*found) {
25     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
26   } else {
27     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
28     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
29     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
30     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
31   }
32   PetscFunctionReturn(0);
33 }
34 #endif
35 
36 #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
37 PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
38 PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
39   #if !defined(PETSC_USE_COMPLEX)
40 PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
41   #endif
42 PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
43 PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
44 PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
45 PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
46 PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
47 PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
48 PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
49 PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
50 PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
51 #endif
52 
53 /*
54     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
55     search path.
56 */
57 PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
58 {
59   char     *libname[32];
60   PetscInt  nmax, i;
61   PetscBool preload = PETSC_FALSE;
62 #if defined(PETSC_HAVE_ELEMENTAL)
63   PetscBool PetscInitialized = PetscInitializeCalled;
64 #endif
65 
66   PetscFunctionBegin;
67 #if defined(PETSC_HAVE_THREADSAFETY)
68   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
69   preload = PETSC_TRUE;
70 #endif
71 
72   nmax = 32;
73   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
74   for (i = 0; i < nmax; i++) {
75     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
76     PetscCall(PetscFree(libname[i]));
77   }
78 
79   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
80   if (!preload) {
81     PetscCall(PetscSysInitializePackage());
82   } else {
83 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
84     PetscBool found;
85   #if defined(PETSC_USE_SINGLE_LIBRARY)
86     PetscCall(PetscLoadDynamicLibrary("", &found));
87     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
88   #else
89     PetscCall(PetscLoadDynamicLibrary("sys", &found));
90     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
91     PetscCall(PetscLoadDynamicLibrary("vec", &found));
92     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
93     PetscCall(PetscLoadDynamicLibrary("mat", &found));
94     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
95     PetscCall(PetscLoadDynamicLibrary("dm", &found));
96     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
97     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
98     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
99     PetscCall(PetscLoadDynamicLibrary("snes", &found));
100     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
101     PetscCall(PetscLoadDynamicLibrary("ts", &found));
102     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
103     PetscCall(PetscLoadDynamicLibrary("tao", &found));
104     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library \n You cannot move the dynamic libraries!");
105   #endif
106 #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
107   #if defined(PETSC_USE_SINGLE_LIBRARY)
108     PetscCall(AOInitializePackage());
109     PetscCall(PetscSFInitializePackage());
110     #if !defined(PETSC_USE_COMPLEX)
111     PetscCall(CharacteristicInitializePackage());
112     #endif
113     PetscCall(ISInitializePackage());
114     PetscCall(VecInitializePackage());
115     PetscCall(MatInitializePackage());
116     PetscCall(DMInitializePackage());
117     PetscCall(PCInitializePackage());
118     PetscCall(KSPInitializePackage());
119     PetscCall(SNESInitializePackage());
120     PetscCall(TSInitializePackage());
121     PetscCall(TaoInitializePackage());
122   #else
123     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
124   #endif
125 #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
126   }
127 
128 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
129   {
130     PetscBool found;
131     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
132     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library \n You cannot move the dynamic libraries!");
133   }
134 #endif
135 
136   nmax = 32;
137   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
138   for (i = 0; i < nmax; i++) {
139     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
140     PetscCall(PetscFree(libname[i]));
141   }
142 
143 #if defined(PETSC_HAVE_ELEMENTAL)
144   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
145   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
146   PetscInitializeCalled = PETSC_TRUE;
147   PetscCall(PetscElementalInitializePackage());
148   PetscInitializeCalled = PetscInitialized;
149 #endif
150   PetscFunctionReturn(0);
151 }
152 
153 /*
154      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
155 */
156 PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
157 {
158   PetscBool flg = PETSC_FALSE;
159 
160   PetscFunctionBegin;
161   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
162   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
163   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
164   PetscDLLibrariesLoaded = NULL;
165   PetscFunctionReturn(0);
166 }
167 
168 /* ------------------------------------------------------------------------------*/
169 struct _n_PetscFunctionList {
170   void (*routine)(void);       /* the routine */
171   char             *name;      /* string to identify routine */
172   PetscFunctionList next;      /* next pointer */
173   PetscFunctionList next_list; /* used to maintain list of all lists for freeing */
174 };
175 
176 /*
177      Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones.
178 */
179 static PetscFunctionList dlallhead = NULL;
180 
181 static PetscErrorCode PetscFunctionListCreateNode_Private(PetscFunctionList *entry, const char name[], void (*func)(void))
182 {
183   PetscFunctionBegin;
184   PetscCall(PetscNew(entry));
185   PetscCall(PetscStrallocpy(name, &(*entry)->name));
186   (*entry)->routine = func;
187   (*entry)->next    = NULL;
188   PetscFunctionReturn(0);
189 }
190 
191 /*MC
192    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
193    specified registry.
194 
195    Synopsis:
196    #include <petscsys.h>
197    PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
198 
199    Not Collective
200 
201    Input Parameters:
202 +  flist - pointer to function list object
203 .  name - string to identify routine
204 -  fptr - function pointer
205 
206    Notes:
207    To remove a registered routine, pass in a NULL fptr.
208 
209    Users who wish to register new classes for use by a particular PETSc
210    component (e.g., `SNES`) should generally call the registration routine
211    for that particular component (e.g., `SNESRegister()`) instead of
212    calling `PetscFunctionListAdd()` directly.
213 
214     Level: developer
215 
216 .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,
217           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
218 M*/
219 PETSC_EXTERN PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], void (*fnc)(void))
220 {
221   PetscFunctionBegin;
222   PetscValidPointer(fl, 1);
223   if (name) PetscValidCharPointer(name, 2);
224   if (fnc) PetscValidFunction(fnc, 3);
225   if (*fl) {
226     /* search list to see if it is already there */
227     PetscFunctionList empty_node = NULL;
228     PetscFunctionList ne         = *fl;
229 
230     while (1) {
231       PetscBool founddup;
232 
233       PetscCall(PetscStrcmp(ne->name, name, &founddup));
234       if (founddup) {
235         /* found duplicate, clear it */
236         ne->routine = fnc;
237         if (!fnc) PetscCall(PetscFree(ne->name));
238         PetscFunctionReturn(0);
239       }
240 
241       if (!empty_node && !ne->routine && !ne->name) {
242         /* save the empty node for later */
243         empty_node = ne;
244       }
245 
246       if (!ne->next) break; /* end of list */
247       ne = ne->next;
248     }
249 
250     /* there was an empty entry we could grab, fill it and bail */
251     if (empty_node) {
252       empty_node->routine = fnc;
253       PetscCall(PetscStrallocpy(name, &empty_node->name));
254     } else {
255       /* create new entry at the end of list */
256       PetscCall(PetscFunctionListCreateNode_Private(&ne->next, name, fnc));
257     }
258     PetscFunctionReturn(0);
259   }
260 
261   /* we didn't have a list */
262   PetscCall(PetscFunctionListCreateNode_Private(fl, name, fnc));
263   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
264     const PetscFunctionList head = dlallhead;
265 
266     /* add this new list to list of all lists */
267     dlallhead        = *fl;
268     (*fl)->next_list = head;
269   }
270   PetscFunctionReturn(0);
271 }
272 
273 /*@
274     PetscFunctionListDestroy - Destroys a list of registered routines.
275 
276     Input Parameter:
277 .   fl  - pointer to list
278 
279     Level: developer
280 
281 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
282 @*/
283 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
284 {
285   PetscFunctionList next, entry, tmp = dlallhead;
286 
287   PetscFunctionBegin;
288   if (!*fl) PetscFunctionReturn(0);
289 
290   /*
291        Remove this entry from the main DL list (if it is in it)
292   */
293   if (dlallhead == *fl) {
294     if (dlallhead->next_list) dlallhead = dlallhead->next_list;
295     else dlallhead = NULL;
296   } else if (tmp) {
297     while (tmp->next_list != *fl) {
298       tmp = tmp->next_list;
299       if (!tmp->next_list) break;
300     }
301     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
302   }
303 
304   /* free this list */
305   entry = *fl;
306   while (entry) {
307     next = entry->next;
308     PetscCall(PetscFree(entry->name));
309     PetscCall(PetscFree(entry));
310     entry = next;
311   }
312   *fl = NULL;
313   PetscFunctionReturn(0);
314 }
315 
316 /*@
317   PetscFunctionListClear - Clear a `PetscFunctionList`
318 
319   Not Collective
320 
321   Input Parameter:
322 . fl - The `PetscFunctionList` to clear
323 
324   Notes:
325   This clears the contents of `fl` but does not deallocate the entries themselves.
326 
327   Level: developer
328 
329 .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
330 @*/
331 PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
332 {
333   PetscFunctionBegin;
334   /* free the names and clear the routine but don't deallocate the node */
335   while (fl) {
336     PetscCall(PetscFree(fl->name));
337     fl->routine = NULL;
338     fl          = fl->next;
339   }
340   PetscFunctionReturn(0);
341 }
342 
343 /*
344    Print registered PetscFunctionLists
345 */
346 PetscErrorCode PetscFunctionListPrintAll(void)
347 {
348   PetscFunctionList tmp = dlallhead;
349 
350   PetscFunctionBegin;
351   if (tmp) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
352   while (tmp) {
353     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d]   %s\n", PetscGlobalRank, tmp->name));
354     tmp = tmp->next_list;
355   }
356   PetscFunctionReturn(0);
357 }
358 
359 /*MC
360     PetscFunctionListNonEmpty - Print composed names for non null function pointers
361 
362     Input Parameter:
363 .   flist   - pointer to list
364 
365     Level: developer
366 
367 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
368 M*/
369 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
370 {
371   PetscFunctionBegin;
372   while (fl) {
373     PetscFunctionList next = fl->next;
374     if (fl->routine) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] function name: %s\n", PetscGlobalRank, fl->name));
375     fl = next;
376   }
377   PetscFunctionReturn(0);
378 }
379 
380 /*MC
381     PetscFunctionListFind - Find function registered under given name
382 
383     Synopsis:
384     #include <petscsys.h>
385     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
386 
387     Input Parameters:
388 +   flist   - pointer to list
389 -   name - name registered for the function
390 
391     Output Parameters:
392 .   fptr - the function pointer if name was found, else NULL
393 
394     Level: developer
395 
396 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
397 M*/
398 PETSC_EXTERN PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], void (**r)(void))
399 {
400   PetscFunctionList entry = fl;
401 
402   PetscFunctionBegin;
403   PetscValidCharPointer(name, 2);
404   PetscValidPointer(r, 3);
405   while (entry) {
406     PetscBool flg;
407 
408     PetscCall(PetscStrcmp(name, entry->name, &flg));
409     if (flg) {
410       *r = entry->routine;
411       PetscFunctionReturn(0);
412     }
413     entry = entry->next;
414   }
415   *r = NULL;
416   PetscFunctionReturn(0);
417 }
418 
419 /*@
420    PetscFunctionListView - prints out contents of an PetscFunctionList
421 
422    Collective over viewer
423 
424    Input Parameters:
425 +  list - the list of functions
426 -  viewer - currently ignored
427 
428    Level: developer
429 
430 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
431 @*/
432 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
433 {
434   PetscBool iascii;
435 
436   PetscFunctionBegin;
437   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
438   PetscValidPointer(list, 1);
439   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
440 
441   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
442   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
443 
444   while (list) {
445     PetscCall(PetscViewerASCIIPrintf(viewer, " %s\n", list->name));
446     list = list->next;
447   }
448   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
449   PetscFunctionReturn(0);
450 }
451 
452 /*@C
453    PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
454          by help etc.
455 
456    Not Collective
457 
458    Input Parameter:
459 .  list   - list of types
460 
461    Output Parameters:
462 +  array - array of names
463 -  n - length of array
464 
465    Note:
466        This allocates the array so that must be freed. BUT the individual entries are
467     not copied so should not be freed.
468 
469    Level: developer
470 
471 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
472 @*/
473 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
474 {
475   PetscInt          count = 0;
476   PetscFunctionList klist = list;
477 
478   PetscFunctionBegin;
479   while (list) {
480     list = list->next;
481     count++;
482   }
483   PetscCall(PetscMalloc1(count + 1, (char ***)array));
484   count = 0;
485   while (klist) {
486     (*array)[count] = klist->name;
487     klist           = klist->next;
488     count++;
489   }
490   (*array)[count] = NULL;
491   *n              = count + 1;
492   PetscFunctionReturn(0);
493 }
494 
495 /*@C
496    PetscFunctionListPrintTypes - Prints the methods available in a list of functions
497 
498    Collective over MPI_Comm
499 
500    Input Parameters:
501 +  comm   - the communicator (usually `MPI_COMM_WORLD`)
502 .  fd     - file to print to, usually stdout
503 .  prefix - prefix to prepend to name (optional)
504 .  name   - option string (for example, "-ksp_type")
505 .  text - short description of the object (for example, "Krylov solvers")
506 .  man - name of manual page that discusses the object (for example, "KSPCreate")
507 .  list   - list of types
508 .  def - default (current) value
509 -  newv - new value
510 
511    Level: developer
512 
513 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
514 @*/
515 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[])
516 {
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 {
549   PetscFunctionBegin;
550   while (fl) {
551     PetscCall(PetscFunctionListAdd(nl, fl->name, fl->routine));
552     fl = fl->next;
553   }
554   PetscFunctionReturn(0);
555 }
556