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