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