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