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