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