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