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