xref: /petsc/src/sys/dll/reg.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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 /*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   PetscFunctionList entry, ne;
221 
222   PetscFunctionBegin;
223   if (!*fl) {
224     PetscCall(PetscNew(&entry));
225     PetscCall(PetscStrallocpy(name, &entry->name));
226     entry->routine = fnc;
227     entry->next    = NULL;
228     *fl            = entry;
229 
230     if (PetscDefined(USE_DEBUG)) {
231       /* add this new list to list of all lists */
232       if (!dlallhead) {
233         dlallhead        = *fl;
234         (*fl)->next_list = NULL;
235       } else {
236         ne               = dlallhead;
237         dlallhead        = *fl;
238         (*fl)->next_list = ne;
239       }
240     }
241 
242   } else {
243     /* search list to see if it is already there */
244     ne = *fl;
245     while (ne) {
246       PetscBool founddup;
247 
248       PetscCall(PetscStrcmp(ne->name, name, &founddup));
249       if (founddup) { /* found duplicate */
250         ne->routine = fnc;
251         PetscFunctionReturn(0);
252       }
253       if (ne->next) ne = ne->next;
254       else break;
255     }
256     /* create new entry and add to end of list */
257     PetscCall(PetscNew(&entry));
258     PetscCall(PetscStrallocpy(name, &entry->name));
259     entry->routine = fnc;
260     entry->next    = NULL;
261     ne->next       = entry;
262   }
263   PetscFunctionReturn(0);
264 }
265 
266 /*@
267     PetscFunctionListDestroy - Destroys a list of registered routines.
268 
269     Input Parameter:
270 .   fl  - pointer to list
271 
272     Level: developer
273 
274 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
275 @*/
276 PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl) {
277   PetscFunctionList next, entry, tmp = dlallhead;
278 
279   PetscFunctionBegin;
280   if (!*fl) PetscFunctionReturn(0);
281 
282   /*
283        Remove this entry from the main DL list (if it is in it)
284   */
285   if (dlallhead == *fl) {
286     if (dlallhead->next_list) dlallhead = dlallhead->next_list;
287     else dlallhead = NULL;
288   } else if (tmp) {
289     while (tmp->next_list != *fl) {
290       tmp = tmp->next_list;
291       if (!tmp->next_list) break;
292     }
293     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
294   }
295 
296   /* free this list */
297   entry = *fl;
298   while (entry) {
299     next = entry->next;
300     PetscCall(PetscFree(entry->name));
301     PetscCall(PetscFree(entry));
302     entry = next;
303   }
304   *fl = NULL;
305   PetscFunctionReturn(0);
306 }
307 
308 /*
309    Print registered PetscFunctionLists
310 */
311 PetscErrorCode PetscFunctionListPrintAll(void) {
312   PetscFunctionList tmp = dlallhead;
313 
314   PetscFunctionBegin;
315   if (tmp) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
316   while (tmp) {
317     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d]   %s\n", PetscGlobalRank, tmp->name));
318     tmp = tmp->next_list;
319   }
320   PetscFunctionReturn(0);
321 }
322 
323 /*MC
324     PetscFunctionListNonEmpty - Print composed names for non null function pointers
325 
326     Input Parameter:
327 .   flist   - pointer to list
328 
329     Level: developer
330 
331 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
332 M*/
333 PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl) {
334   PetscFunctionBegin;
335   while (fl) {
336     PetscFunctionList next = fl->next;
337     if (fl->routine) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] function name: %s\n", PetscGlobalRank, fl->name));
338     fl = next;
339   }
340   PetscFunctionReturn(0);
341 }
342 
343 /*MC
344     PetscFunctionListFind - Find function registered under given name
345 
346     Synopsis:
347     #include <petscsys.h>
348     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
349 
350     Input Parameters:
351 +   flist   - pointer to list
352 -   name - name registered for the function
353 
354     Output Parameters:
355 .   fptr - the function pointer if name was found, else NULL
356 
357     Level: developer
358 
359 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
360 M*/
361 PETSC_EXTERN PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], void (**r)(void)) {
362   PetscFunctionList entry = fl;
363   PetscBool         flg;
364 
365   PetscFunctionBegin;
366   PetscCheck(name, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Trying to find routine with null name");
367 
368   *r = NULL;
369   while (entry) {
370     PetscCall(PetscStrcmp(name, entry->name, &flg));
371     if (flg) {
372       *r = entry->routine;
373       PetscFunctionReturn(0);
374     }
375     entry = entry->next;
376   }
377   PetscFunctionReturn(0);
378 }
379 
380 /*@
381    PetscFunctionListView - prints out contents of an PetscFunctionList
382 
383    Collective over MPI_Comm
384 
385    Input Parameters:
386 +  list - the list of functions
387 -  viewer - currently ignored
388 
389    Level: developer
390 
391 .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
392 @*/
393 PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer) {
394   PetscBool iascii;
395 
396   PetscFunctionBegin;
397   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
398   PetscValidPointer(list, 1);
399   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
400 
401   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
402   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
403 
404   while (list) {
405     PetscCall(PetscViewerASCIIPrintf(viewer, " %s\n", list->name));
406     list = list->next;
407   }
408   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
409   PetscFunctionReturn(0);
410 }
411 
412 /*@C
413    PetscFunctionListGet - Gets an array the contains the entries in PetscFunctionList, this is used
414          by help etc.
415 
416    Not Collective
417 
418    Input Parameter:
419 .  list   - list of types
420 
421    Output Parameters:
422 +  array - array of names
423 -  n - length of array
424 
425    Notes:
426        This allocates the array so that must be freed. BUT the individual entries are
427     not copied so should not be freed.
428 
429    Level: developer
430 
431 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
432 @*/
433 PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n) {
434   PetscInt          count = 0;
435   PetscFunctionList klist = list;
436 
437   PetscFunctionBegin;
438   while (list) {
439     list = list->next;
440     count++;
441   }
442   PetscCall(PetscMalloc1(count + 1, (char ***)array));
443   count = 0;
444   while (klist) {
445     (*array)[count] = klist->name;
446     klist           = klist->next;
447     count++;
448   }
449   (*array)[count] = NULL;
450   *n              = count + 1;
451   PetscFunctionReturn(0);
452 }
453 
454 /*@C
455    PetscFunctionListPrintTypes - Prints the methods available.
456 
457    Collective over MPI_Comm
458 
459    Input Parameters:
460 +  comm   - the communicator (usually MPI_COMM_WORLD)
461 .  fd     - file to print to, usually stdout
462 .  prefix - prefix to prepend to name (optional)
463 .  name   - option string (for example, "-ksp_type")
464 .  text - short description of the object (for example, "Krylov solvers")
465 .  man - name of manual page that discusses the object (for example, "KSPCreate")
466 .  list   - list of types
467 .  def - default (current) value
468 -  newv - new value
469 
470    Level: developer
471 
472 .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
473 @*/
474 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[]) {
475   char p[64];
476 
477   PetscFunctionBegin;
478   if (!fd) fd = PETSC_STDOUT;
479 
480   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
481   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
482   PetscCall(PetscFPrintf(comm, fd, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
483 
484   while (list) {
485     PetscCall(PetscFPrintf(comm, fd, " %s", list->name));
486     list = list->next;
487   }
488   PetscCall(PetscFPrintf(comm, fd, " (%s)\n", man));
489   PetscFunctionReturn(0);
490 }
491 
492 /*@
493     PetscFunctionListDuplicate - Creates a new list from a given object list.
494 
495     Input Parameters:
496 .   fl   - pointer to list
497 
498     Output Parameters:
499 .   nl - the new list (should point to 0 to start, otherwise appends)
500 
501     Level: developer
502 
503 .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
504 
505 @*/
506 PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl) {
507   PetscFunctionBegin;
508   while (fl) {
509     PetscCall(PetscFunctionListAdd(nl, fl->name, fl->routine));
510     fl = fl->next;
511   }
512   PetscFunctionReturn(0);
513 }
514