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