xref: /petsc/src/sys/dll/reg.c (revision ed170139b2a0d64288c7bf97cedbc4d7d1412afc)
17d0a6c19SBarry Smith 
2e5c89e4eSSatish Balay /*
3e5c89e4eSSatish Balay     Provides a general mechanism to allow one to register new routines in
4e5c89e4eSSatish Balay     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5e5c89e4eSSatish Balay */
6af0996ceSBarry Smith #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/
7665c2dedSJed Brown #include <petscviewer.h>
8e5c89e4eSSatish Balay 
9*ed170139SJacob Faibussowitsch #include <petsc/private/hashmap.h>
103fa76a5bSLisandro Dalcin /*
113fa76a5bSLisandro Dalcin     This is the default list used by PETSc with the PetscDLLibrary register routines
123fa76a5bSLisandro Dalcin */
1302c9f0b5SLisandro Dalcin PetscDLLibrary PetscDLLibrariesLoaded = NULL;
143fa76a5bSLisandro Dalcin 
15cbd104e6SBarry Smith #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
16ebd79076SLisandro Dalcin 
17d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
18d71ae5a4SJacob Faibussowitsch {
19487e5849SBarry Smith   char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
20487e5849SBarry Smith 
21487e5849SBarry Smith   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
239566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
249566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
25487e5849SBarry Smith   if (*found) {
269566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
27487e5849SBarry Smith   } else {
289566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
299566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
309566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
3148a46eb9SPierre Jolivet     if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
32487e5849SBarry Smith   }
33487e5849SBarry Smith   PetscFunctionReturn(0);
34487e5849SBarry Smith }
353fa76a5bSLisandro Dalcin #endif
363fa76a5bSLisandro Dalcin 
3760da17ecSBarry Smith #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
3895c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
3995c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
407da51e29SSatish Balay   #if !defined(PETSC_USE_COMPLEX)
4195c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
427da51e29SSatish Balay   #endif
4395c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
4495c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
4595c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
4695c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
4795c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
4895c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
4995c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
5095c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
5160da17ecSBarry Smith PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
5260da17ecSBarry Smith #endif
53acff04ddSBarry Smith 
54e5c89e4eSSatish Balay /*
55e5c89e4eSSatish Balay     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
56e5c89e4eSSatish Balay     search path.
57e5c89e4eSSatish Balay */
58d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
59d71ae5a4SJacob Faibussowitsch {
60487e5849SBarry Smith   char     *libname[32];
61e5c89e4eSSatish Balay   PetscInt  nmax, i;
6260da17ecSBarry Smith   PetscBool preload = PETSC_FALSE;
63540e20f2SPierre Jolivet #if defined(PETSC_HAVE_ELEMENTAL)
64540e20f2SPierre Jolivet   PetscBool PetscInitialized = PetscInitializeCalled;
65540e20f2SPierre Jolivet #endif
66e5c89e4eSSatish Balay 
6760154eb2SBarry Smith   PetscFunctionBegin;
6860da17ecSBarry Smith #if defined(PETSC_HAVE_THREADSAFETY)
6960da17ecSBarry Smith   /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
7060da17ecSBarry Smith   preload = PETSC_TRUE;
7160da17ecSBarry Smith #endif
7260da17ecSBarry Smith 
73e5c89e4eSSatish Balay   nmax = 32;
749566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
75e5c89e4eSSatish Balay   for (i = 0; i < nmax; i++) {
769566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
779566063dSJacob Faibussowitsch     PetscCall(PetscFree(libname[i]));
78e5c89e4eSSatish Balay   }
79e5c89e4eSSatish Balay 
809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
8160da17ecSBarry Smith   if (!preload) {
829566063dSJacob Faibussowitsch     PetscCall(PetscSysInitializePackage());
8360da17ecSBarry Smith   } else {
8460da17ecSBarry Smith #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
85aa2d57e9SJed Brown     PetscBool found;
8660154eb2SBarry Smith   #if defined(PETSC_USE_SINGLE_LIBRARY)
879566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("", &found));
8828b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
8960154eb2SBarry Smith   #else
909566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("sys", &found));
9128b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
929566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("vec", &found));
9328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
949566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("mat", &found));
9528b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
969566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("dm", &found));
9728b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
989566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("ksp", &found));
9928b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
1009566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("snes", &found));
10128b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
1029566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("ts", &found));
10328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
1049566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("tao", &found));
10528b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library \n You cannot move the dynamic libraries!");
106bb84e0fdSBarry Smith   #endif
10760da17ecSBarry Smith #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
10860da17ecSBarry Smith   #if defined(PETSC_USE_SINGLE_LIBRARY)
1099566063dSJacob Faibussowitsch     PetscCall(AOInitializePackage());
1109566063dSJacob Faibussowitsch     PetscCall(PetscSFInitializePackage());
1117da51e29SSatish Balay     #if !defined(PETSC_USE_COMPLEX)
1129566063dSJacob Faibussowitsch     PetscCall(CharacteristicInitializePackage());
1137da51e29SSatish Balay     #endif
1149566063dSJacob Faibussowitsch     PetscCall(ISInitializePackage());
1159566063dSJacob Faibussowitsch     PetscCall(VecInitializePackage());
1169566063dSJacob Faibussowitsch     PetscCall(MatInitializePackage());
1179566063dSJacob Faibussowitsch     PetscCall(DMInitializePackage());
1189566063dSJacob Faibussowitsch     PetscCall(PCInitializePackage());
1199566063dSJacob Faibussowitsch     PetscCall(KSPInitializePackage());
1209566063dSJacob Faibussowitsch     PetscCall(SNESInitializePackage());
1219566063dSJacob Faibussowitsch     PetscCall(TSInitializePackage());
1229566063dSJacob Faibussowitsch     PetscCall(TaoInitializePackage());
12360da17ecSBarry Smith   #else
12460da17ecSBarry Smith     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
12560da17ecSBarry Smith   #endif
12660da17ecSBarry Smith #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
12760da17ecSBarry Smith   }
12860da17ecSBarry Smith 
12960da17ecSBarry Smith #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
13060da17ecSBarry Smith   {
13160da17ecSBarry Smith     PetscBool found;
1329566063dSJacob Faibussowitsch     PetscCall(PetscLoadDynamicLibrary("bamg", &found));
13328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library \n You cannot move the dynamic libraries!");
13460da17ecSBarry Smith   }
13560da17ecSBarry Smith #endif
13660da17ecSBarry Smith 
13760da17ecSBarry Smith   nmax = 32;
1389566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
13960da17ecSBarry Smith   for (i = 0; i < nmax; i++) {
1409566063dSJacob Faibussowitsch     PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
1419566063dSJacob Faibussowitsch     PetscCall(PetscFree(libname[i]));
14260da17ecSBarry Smith   }
14360da17ecSBarry Smith 
144540e20f2SPierre Jolivet #if defined(PETSC_HAVE_ELEMENTAL)
145540e20f2SPierre Jolivet   /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
146540e20f2SPierre Jolivet   /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
147540e20f2SPierre Jolivet   PetscInitializeCalled = PETSC_TRUE;
1489566063dSJacob Faibussowitsch   PetscCall(PetscElementalInitializePackage());
149540e20f2SPierre Jolivet   PetscInitializeCalled = PetscInitialized;
150540e20f2SPierre Jolivet #endif
151e5c89e4eSSatish Balay   PetscFunctionReturn(0);
152e5c89e4eSSatish Balay }
153e5c89e4eSSatish Balay 
154ebd79076SLisandro Dalcin /*
155ebd79076SLisandro Dalcin      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
156ebd79076SLisandro Dalcin */
157d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
158d71ae5a4SJacob Faibussowitsch {
159ace3abfcSBarry Smith   PetscBool flg = PETSC_FALSE;
160e5c89e4eSSatish Balay 
161ebd79076SLisandro Dalcin   PetscFunctionBegin;
1629566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
1639566063dSJacob Faibussowitsch   if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
1649566063dSJacob Faibussowitsch   PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
16502c9f0b5SLisandro Dalcin   PetscDLLibrariesLoaded = NULL;
166e5c89e4eSSatish Balay   PetscFunctionReturn(0);
167e5c89e4eSSatish Balay }
168e5c89e4eSSatish Balay 
169e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------*/
170*ed170139SJacob Faibussowitsch PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFunction, kh_str_hash_func, kh_str_hash_equal, NULL)
171*ed170139SJacob Faibussowitsch 
172140e18c1SBarry Smith struct _n_PetscFunctionList {
173*ed170139SJacob Faibussowitsch   PetscHMapFunc map;
174e5c89e4eSSatish Balay };
175e5c89e4eSSatish Balay 
176*ed170139SJacob Faibussowitsch /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
177*ed170139SJacob Faibussowitsch typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
178*ed170139SJacob Faibussowitsch struct n_PetscFunctionListDLAll {
179*ed170139SJacob Faibussowitsch   PetscFunctionList      data;
180*ed170139SJacob Faibussowitsch   PetscFunctionListDLAll next;
181*ed170139SJacob Faibussowitsch };
182e5c89e4eSSatish Balay 
183*ed170139SJacob Faibussowitsch static PetscFunctionListDLAll dlallhead = NULL;
184*ed170139SJacob Faibussowitsch 
185*ed170139SJacob Faibussowitsch static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
186d71ae5a4SJacob Faibussowitsch {
1870e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
188*ed170139SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
189*ed170139SJacob Faibussowitsch     PetscFunctionListDLAll head;
190*ed170139SJacob Faibussowitsch 
191*ed170139SJacob Faibussowitsch     PetscCall(PetscNew(&head));
192*ed170139SJacob Faibussowitsch     head->data = fl;
193*ed170139SJacob Faibussowitsch     head->next = dlallhead;
194*ed170139SJacob Faibussowitsch     dlallhead  = head;
195*ed170139SJacob Faibussowitsch   }
196*ed170139SJacob Faibussowitsch   PetscFunctionReturn(0);
197*ed170139SJacob Faibussowitsch }
198*ed170139SJacob Faibussowitsch 
199*ed170139SJacob Faibussowitsch static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
200*ed170139SJacob Faibussowitsch {
201*ed170139SJacob Faibussowitsch   PetscFunctionBegin;
202*ed170139SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
203*ed170139SJacob Faibussowitsch     PetscFunctionListDLAll current = dlallhead, prev = NULL;
204*ed170139SJacob Faibussowitsch 
205*ed170139SJacob Faibussowitsch     /* Remove this entry from the main DL list (if it is in it) */
206*ed170139SJacob Faibussowitsch     while (current) {
207*ed170139SJacob Faibussowitsch       const PetscFunctionListDLAll next = current->next;
208*ed170139SJacob Faibussowitsch 
209*ed170139SJacob Faibussowitsch       if (current->data == fl) {
210*ed170139SJacob Faibussowitsch         if (prev) {
211*ed170139SJacob Faibussowitsch           // somewhere in the middle (or end) of the list
212*ed170139SJacob Faibussowitsch           prev->next = next;
213*ed170139SJacob Faibussowitsch         } else {
214*ed170139SJacob Faibussowitsch           // prev = NULL implies current = dlallhead, so front of list
215*ed170139SJacob Faibussowitsch           dlallhead = next;
216*ed170139SJacob Faibussowitsch         }
217*ed170139SJacob Faibussowitsch         PetscCall(PetscFree(current));
218*ed170139SJacob Faibussowitsch         break;
219*ed170139SJacob Faibussowitsch       }
220*ed170139SJacob Faibussowitsch       prev    = current;
221*ed170139SJacob Faibussowitsch       current = next;
222*ed170139SJacob Faibussowitsch     }
223*ed170139SJacob Faibussowitsch   }
224*ed170139SJacob Faibussowitsch   PetscFunctionReturn(0);
225*ed170139SJacob Faibussowitsch }
226*ed170139SJacob Faibussowitsch 
227*ed170139SJacob Faibussowitsch static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFunction fnc)
228*ed170139SJacob Faibussowitsch {
229*ed170139SJacob Faibussowitsch   PetscHashIter it;
230*ed170139SJacob Faibussowitsch   PetscBool     found;
231*ed170139SJacob Faibussowitsch 
232*ed170139SJacob Faibussowitsch   PetscFunctionBegin;
233*ed170139SJacob Faibussowitsch   PetscValidCharPointer(name, 2);
234*ed170139SJacob Faibussowitsch   if (fnc) PetscValidFunction(fnc, 3);
235*ed170139SJacob Faibussowitsch   PetscCall(PetscHMapFuncFind(map, name, &it, &found));
236*ed170139SJacob Faibussowitsch   if (fnc) {
237*ed170139SJacob Faibussowitsch     if (found) {
238*ed170139SJacob Faibussowitsch       PetscCall(PetscHMapFuncIterSet(map, it, fnc));
239*ed170139SJacob Faibussowitsch     } else {
240*ed170139SJacob Faibussowitsch       char *tmp_name;
241*ed170139SJacob Faibussowitsch 
242*ed170139SJacob Faibussowitsch       PetscCall(PetscStrallocpy(name, &tmp_name));
243*ed170139SJacob Faibussowitsch       PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
244*ed170139SJacob Faibussowitsch     }
245*ed170139SJacob Faibussowitsch   } else if (found) {
246*ed170139SJacob Faibussowitsch     const char *tmp_name;
247*ed170139SJacob Faibussowitsch 
248*ed170139SJacob Faibussowitsch     PetscHashIterGetKey(map, it, tmp_name);
249*ed170139SJacob Faibussowitsch     PetscCall(PetscFree(tmp_name));
250*ed170139SJacob Faibussowitsch     PetscCall(PetscHMapFuncIterDel(map, it));
251*ed170139SJacob Faibussowitsch   }
252*ed170139SJacob Faibussowitsch   PetscFunctionReturn(0);
253*ed170139SJacob Faibussowitsch }
254*ed170139SJacob Faibussowitsch 
255*ed170139SJacob Faibussowitsch static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
256*ed170139SJacob Faibussowitsch {
257*ed170139SJacob Faibussowitsch   PetscFunctionBegin;
258*ed170139SJacob Faibussowitsch   if (*fl) PetscFunctionReturn(0);
259*ed170139SJacob Faibussowitsch   PetscCall(PetscNew(fl));
260*ed170139SJacob Faibussowitsch   PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
261*ed170139SJacob Faibussowitsch   PetscCall(PetscFunctionListDLAllPush_Private(*fl));
2620e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
2630e6b6b59SJacob Faibussowitsch }
2640e6b6b59SJacob Faibussowitsch 
265a240a19fSJed Brown /*MC
266140e18c1SBarry Smith    PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
267e5c89e4eSSatish Balay    specified registry.
268e5c89e4eSSatish Balay 
269a240a19fSJed Brown    Synopsis:
270aaa7dc30SBarry Smith    #include <petscsys.h>
271b9fb364aSBarry Smith    PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
272a240a19fSJed Brown 
273d4349b43SBarry Smith    Not Collective
274e5c89e4eSSatish Balay 
275e5c89e4eSSatish Balay    Input Parameters:
276b9fb364aSBarry Smith +  flist - pointer to function list object
277e5c89e4eSSatish Balay .  name - string to identify routine
278a240a19fSJed Brown -  fptr - function pointer
279e5c89e4eSSatish Balay 
280e5c89e4eSSatish Balay    Notes:
281a240a19fSJed Brown    To remove a registered routine, pass in a NULL fptr.
282e5c89e4eSSatish Balay 
283e5c89e4eSSatish Balay    Users who wish to register new classes for use by a particular PETSc
284811af0c4SBarry Smith    component (e.g., `SNES`) should generally call the registration routine
285811af0c4SBarry Smith    for that particular component (e.g., `SNESRegister()`) instead of
286811af0c4SBarry Smith    calling `PetscFunctionListAdd()` directly.
287e5c89e4eSSatish Balay 
288e5c89e4eSSatish Balay     Level: developer
289e5c89e4eSSatish Balay 
290db781477SPatrick Sanan .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,
291db781477SPatrick Sanan           `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
292a240a19fSJed Brown M*/
293*ed170139SJacob Faibussowitsch PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFunction fnc)
294d71ae5a4SJacob Faibussowitsch {
295e5c89e4eSSatish Balay   PetscFunctionBegin;
2960e6b6b59SJacob Faibussowitsch   PetscValidPointer(fl, 1);
2970e6b6b59SJacob Faibussowitsch   if (name) PetscValidCharPointer(name, 2);
2980e6b6b59SJacob Faibussowitsch   if (fnc) PetscValidFunction(fnc, 3);
299*ed170139SJacob Faibussowitsch   PetscCall(PetscFunctionListCreate_Private(0, fl));
300*ed170139SJacob Faibussowitsch   PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fnc));
301e5c89e4eSSatish Balay   PetscFunctionReturn(0);
302e5c89e4eSSatish Balay }
303e5c89e4eSSatish Balay 
304e5c89e4eSSatish Balay /*@
305140e18c1SBarry Smith     PetscFunctionListDestroy - Destroys a list of registered routines.
306e5c89e4eSSatish Balay 
307e5c89e4eSSatish Balay     Input Parameter:
308e5c89e4eSSatish Balay .   fl  - pointer to list
309e5c89e4eSSatish Balay 
310e5c89e4eSSatish Balay     Level: developer
311e5c89e4eSSatish Balay 
3120e6b6b59SJacob Faibussowitsch .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
313e5c89e4eSSatish Balay @*/
314d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
315d71ae5a4SJacob Faibussowitsch {
316e5c89e4eSSatish Balay   PetscFunctionBegin;
3171441b1d3SBarry Smith   if (!*fl) PetscFunctionReturn(0);
318*ed170139SJacob Faibussowitsch   PetscCall(PetscFunctionListDLAllPop_Private(*fl));
319e5c89e4eSSatish Balay   /* free this list */
320*ed170139SJacob Faibussowitsch   PetscCall(PetscFunctionListClear(*fl));
321*ed170139SJacob Faibussowitsch   PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
322*ed170139SJacob Faibussowitsch   PetscCall(PetscFree(*fl));
323e5c89e4eSSatish Balay   PetscFunctionReturn(0);
324e5c89e4eSSatish Balay }
325e5c89e4eSSatish Balay 
326*ed170139SJacob Faibussowitsch #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
327*ed170139SJacob Faibussowitsch   do { \
328*ed170139SJacob Faibussowitsch     const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
329*ed170139SJacob Faibussowitsch     PetscHashIter       phmfi_iter_; \
330*ed170139SJacob Faibussowitsch \
331*ed170139SJacob Faibussowitsch     PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
332*ed170139SJacob Faibussowitsch     while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
333*ed170139SJacob Faibussowitsch       const char *PETSC_UNUSED       __key_name__; \
334*ed170139SJacob Faibussowitsch       PetscVoidFunction PETSC_UNUSED __val_name__; \
335*ed170139SJacob Faibussowitsch \
336*ed170139SJacob Faibussowitsch       PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
337*ed170139SJacob Faibussowitsch       PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
338*ed170139SJacob Faibussowitsch       { \
339*ed170139SJacob Faibussowitsch         __VA_ARGS__; \
340*ed170139SJacob Faibussowitsch       } \
341*ed170139SJacob Faibussowitsch       PetscHashIterNext(phmfi_map_, phmfi_iter_); \
342*ed170139SJacob Faibussowitsch     } /* end while */ \
343*ed170139SJacob Faibussowitsch   } while (0)
344*ed170139SJacob Faibussowitsch 
3450e6b6b59SJacob Faibussowitsch /*@
3460e6b6b59SJacob Faibussowitsch   PetscFunctionListClear - Clear a `PetscFunctionList`
3470e6b6b59SJacob Faibussowitsch 
3480e6b6b59SJacob Faibussowitsch   Not Collective
3490e6b6b59SJacob Faibussowitsch 
3500e6b6b59SJacob Faibussowitsch   Input Parameter:
3510e6b6b59SJacob Faibussowitsch . fl - The `PetscFunctionList` to clear
3520e6b6b59SJacob Faibussowitsch 
3530e6b6b59SJacob Faibussowitsch   Notes:
3540e6b6b59SJacob Faibussowitsch   This clears the contents of `fl` but does not deallocate the entries themselves.
3550e6b6b59SJacob Faibussowitsch 
3560e6b6b59SJacob Faibussowitsch   Level: developer
3570e6b6b59SJacob Faibussowitsch 
3580e6b6b59SJacob Faibussowitsch .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
3590e6b6b59SJacob Faibussowitsch @*/
360d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
361d71ae5a4SJacob Faibussowitsch {
3620e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
363*ed170139SJacob Faibussowitsch   if (fl) {
364*ed170139SJacob Faibussowitsch     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
365*ed170139SJacob Faibussowitsch     PetscCall(PetscHMapFuncClear(fl->map));
3660e6b6b59SJacob Faibussowitsch   }
3670e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
3680e6b6b59SJacob Faibussowitsch }
3690e6b6b59SJacob Faibussowitsch 
370e5c89e4eSSatish Balay /*
3712e956fe4SStefano Zampini    Print registered PetscFunctionLists
372e5c89e4eSSatish Balay */
373d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListPrintAll(void)
374d71ae5a4SJacob Faibussowitsch {
375*ed170139SJacob Faibussowitsch   PetscFunctionListDLAll current = dlallhead;
376e5c89e4eSSatish Balay 
377e5c89e4eSSatish Balay   PetscFunctionBegin;
378*ed170139SJacob Faibussowitsch   if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
379*ed170139SJacob Faibussowitsch   while (current) {
380*ed170139SJacob Faibussowitsch     PetscCall(PetscFunctionListPrintNonEmpty(current->data));
381*ed170139SJacob Faibussowitsch     current = current->next;
38237e93019SBarry Smith   }
383e5c89e4eSSatish Balay   PetscFunctionReturn(0);
384e5c89e4eSSatish Balay }
385e5c89e4eSSatish Balay 
3861c9cd337SJed Brown /*MC
3872e956fe4SStefano Zampini     PetscFunctionListNonEmpty - Print composed names for non null function pointers
3882e956fe4SStefano Zampini 
3892e956fe4SStefano Zampini     Input Parameter:
3902e956fe4SStefano Zampini .   flist   - pointer to list
3912e956fe4SStefano Zampini 
3922e956fe4SStefano Zampini     Level: developer
3932e956fe4SStefano Zampini 
3942e956fe4SStefano Zampini .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
3952e956fe4SStefano Zampini M*/
396d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
397d71ae5a4SJacob Faibussowitsch {
3982e956fe4SStefano Zampini   PetscFunctionBegin;
399*ed170139SJacob Faibussowitsch   if (fl) {
400*ed170139SJacob Faibussowitsch     // clang-format off
401*ed170139SJacob Faibussowitsch     PetscHMapFuncForEach(
402*ed170139SJacob Faibussowitsch       fl,
403*ed170139SJacob Faibussowitsch       name, func,
404*ed170139SJacob Faibussowitsch       PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
405*ed170139SJacob Faibussowitsch     );
406*ed170139SJacob Faibussowitsch     // clang-format on
4072e956fe4SStefano Zampini   }
4082e956fe4SStefano Zampini   PetscFunctionReturn(0);
4092e956fe4SStefano Zampini }
4102e956fe4SStefano Zampini 
4112e956fe4SStefano Zampini /*MC
4121c9cd337SJed Brown     PetscFunctionListFind - Find function registered under given name
4131c9cd337SJed Brown 
4141c9cd337SJed Brown     Synopsis:
415aaa7dc30SBarry Smith     #include <petscsys.h>
4161c9cd337SJed Brown     PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
417e5c89e4eSSatish Balay 
418e5c89e4eSSatish Balay     Input Parameters:
4191c9cd337SJed Brown +   flist   - pointer to list
4201c9cd337SJed Brown -   name - name registered for the function
421e5c89e4eSSatish Balay 
422e5c89e4eSSatish Balay     Output Parameters:
4231c9cd337SJed Brown .   fptr - the function pointer if name was found, else NULL
424e5c89e4eSSatish Balay 
425e5c89e4eSSatish Balay     Level: developer
426e5c89e4eSSatish Balay 
427db781477SPatrick Sanan .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
4281c9cd337SJed Brown M*/
429*ed170139SJacob Faibussowitsch PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFunction *r)
430d71ae5a4SJacob Faibussowitsch {
431e5c89e4eSSatish Balay   PetscFunctionBegin;
4320e6b6b59SJacob Faibussowitsch   PetscValidCharPointer(name, 2);
4330e6b6b59SJacob Faibussowitsch   PetscValidPointer(r, 3);
4340e6b6b59SJacob Faibussowitsch   *r = NULL;
435*ed170139SJacob Faibussowitsch   if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, r));
436e5c89e4eSSatish Balay   PetscFunctionReturn(0);
437e5c89e4eSSatish Balay }
438e5c89e4eSSatish Balay 
439e5c89e4eSSatish Balay /*@
440140e18c1SBarry Smith    PetscFunctionListView - prints out contents of an PetscFunctionList
441e5c89e4eSSatish Balay 
442*ed170139SJacob Faibussowitsch    Collective on `viewer`
443e5c89e4eSSatish Balay 
444e5c89e4eSSatish Balay    Input Parameters:
445e5c89e4eSSatish Balay +  list - the list of functions
446*ed170139SJacob Faibussowitsch -  viewer - the `PetscViewer` used to view the PetscFunctionList
447e5c89e4eSSatish Balay 
448e5c89e4eSSatish Balay    Level: developer
449e5c89e4eSSatish Balay 
450db781477SPatrick Sanan .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
451e5c89e4eSSatish Balay @*/
452d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
453d71ae5a4SJacob Faibussowitsch {
454ace3abfcSBarry Smith   PetscBool iascii;
455e5c89e4eSSatish Balay 
456e5c89e4eSSatish Balay   PetscFunctionBegin;
457e5c89e4eSSatish Balay   PetscValidPointer(list, 1);
458*ed170139SJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
4590700a824SBarry Smith   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
460e5c89e4eSSatish Balay 
4619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
46228b400f6SJacob Faibussowitsch   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
463*ed170139SJacob Faibussowitsch   {
464*ed170139SJacob Faibussowitsch     PetscInt size;
465e5c89e4eSSatish Balay 
466*ed170139SJacob Faibussowitsch     PetscCall(PetscHMapFuncGetSize(list->map, &size));
467*ed170139SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
468*ed170139SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
469*ed170139SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
470*ed170139SJacob Faibussowitsch     if (size) {
471*ed170139SJacob Faibussowitsch       PetscInt count = 0;
472*ed170139SJacob Faibussowitsch 
473*ed170139SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
474*ed170139SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
475*ed170139SJacob Faibussowitsch       PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
476*ed170139SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
477e5c89e4eSSatish Balay     }
478*ed170139SJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
479*ed170139SJacob Faibussowitsch   }
480e5c89e4eSSatish Balay   PetscFunctionReturn(0);
481e5c89e4eSSatish Balay }
482e5c89e4eSSatish Balay 
483065533a5SJed Brown /*@C
484811af0c4SBarry Smith    PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
485e5c89e4eSSatish Balay          by help etc.
486e5c89e4eSSatish Balay 
487d4349b43SBarry Smith    Not Collective
488e5c89e4eSSatish Balay 
489e5c89e4eSSatish Balay    Input Parameter:
490e5c89e4eSSatish Balay .  list   - list of types
491e5c89e4eSSatish Balay 
492d8d19677SJose E. Roman    Output Parameters:
493e5c89e4eSSatish Balay +  array - array of names
494e5c89e4eSSatish Balay -  n - length of array
495e5c89e4eSSatish Balay 
496811af0c4SBarry Smith    Note:
497e5c89e4eSSatish Balay        This allocates the array so that must be freed. BUT the individual entries are
498e5c89e4eSSatish Balay     not copied so should not be freed.
499e5c89e4eSSatish Balay 
500e5c89e4eSSatish Balay    Level: developer
501e5c89e4eSSatish Balay 
502db781477SPatrick Sanan .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
503e5c89e4eSSatish Balay @*/
504d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
505d71ae5a4SJacob Faibussowitsch {
506*ed170139SJacob Faibussowitsch   PetscInt size = 0;
507e5c89e4eSSatish Balay 
508e5c89e4eSSatish Balay   PetscFunctionBegin;
509*ed170139SJacob Faibussowitsch   PetscValidPointer(array, 2);
510*ed170139SJacob Faibussowitsch   *array = NULL;
511*ed170139SJacob Faibussowitsch   if (list) {
512*ed170139SJacob Faibussowitsch     const PetscHMapFunc map = list->map;
513*ed170139SJacob Faibussowitsch     PetscInt            off = 0;
514*ed170139SJacob Faibussowitsch 
515*ed170139SJacob Faibussowitsch     PetscCall(PetscHMapFuncGetSize(map, &size));
516*ed170139SJacob Faibussowitsch     PetscCall(PetscMalloc1(size, (char ***)array));
517*ed170139SJacob Faibussowitsch     PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
518e5c89e4eSSatish Balay   }
519*ed170139SJacob Faibussowitsch   *n = (int)size;
520e5c89e4eSSatish Balay   PetscFunctionReturn(0);
521e5c89e4eSSatish Balay }
522e5c89e4eSSatish Balay 
523e5c89e4eSSatish Balay /*@C
524811af0c4SBarry Smith    PetscFunctionListPrintTypes - Prints the methods available in a list of functions
525e5c89e4eSSatish Balay 
526e5c89e4eSSatish Balay    Collective over MPI_Comm
527e5c89e4eSSatish Balay 
528e5c89e4eSSatish Balay    Input Parameters:
529811af0c4SBarry Smith +  comm   - the communicator (usually `MPI_COMM_WORLD`)
530e5c89e4eSSatish Balay .  fd     - file to print to, usually stdout
531e5c89e4eSSatish Balay .  prefix - prefix to prepend to name (optional)
532e5c89e4eSSatish Balay .  name   - option string (for example, "-ksp_type")
533e5c89e4eSSatish Balay .  text - short description of the object (for example, "Krylov solvers")
534e5c89e4eSSatish Balay .  man - name of manual page that discusses the object (for example, "KSPCreate")
5353cc1e11dSBarry Smith .  list   - list of types
53644ef3d73SBarry Smith .  def - default (current) value
53744ef3d73SBarry Smith -  newv - new value
538e5c89e4eSSatish Balay 
539e5c89e4eSSatish Balay    Level: developer
540e5c89e4eSSatish Balay 
541db781477SPatrick Sanan .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
542e5c89e4eSSatish Balay @*/
543d71ae5a4SJacob Faibussowitsch 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[])
544d71ae5a4SJacob Faibussowitsch {
545e5c89e4eSSatish Balay   char p[64];
546e5c89e4eSSatish Balay 
547e5c89e4eSSatish Balay   PetscFunctionBegin;
548*ed170139SJacob Faibussowitsch   (void)fd;
5499566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(p, "-", sizeof(p)));
5509566063dSJacob Faibussowitsch   if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
551*ed170139SJacob Faibussowitsch   PetscCall((*PetscHelpPrintf)(comm, "  %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
552e5c89e4eSSatish Balay 
553*ed170139SJacob Faibussowitsch   PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
554*ed170139SJacob Faibussowitsch   PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
555e5c89e4eSSatish Balay   PetscFunctionReturn(0);
556e5c89e4eSSatish Balay }
557e5c89e4eSSatish Balay 
558e5c89e4eSSatish Balay /*@
559140e18c1SBarry Smith     PetscFunctionListDuplicate - Creates a new list from a given object list.
560e5c89e4eSSatish Balay 
561e5c89e4eSSatish Balay     Input Parameters:
562e5c89e4eSSatish Balay .   fl   - pointer to list
563e5c89e4eSSatish Balay 
564e5c89e4eSSatish Balay     Output Parameters:
565e5c89e4eSSatish Balay .   nl - the new list (should point to 0 to start, otherwise appends)
566e5c89e4eSSatish Balay 
567e5c89e4eSSatish Balay     Level: developer
568e5c89e4eSSatish Balay 
569db781477SPatrick Sanan .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
570e5c89e4eSSatish Balay @*/
571d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
572d71ae5a4SJacob Faibussowitsch {
573e5c89e4eSSatish Balay   PetscFunctionBegin;
574*ed170139SJacob Faibussowitsch   if (fl) {
575*ed170139SJacob Faibussowitsch     PetscHMapFunc dup_map;
576*ed170139SJacob Faibussowitsch 
577*ed170139SJacob Faibussowitsch     if (!*nl) {
578*ed170139SJacob Faibussowitsch       PetscInt n;
579*ed170139SJacob Faibussowitsch 
580*ed170139SJacob Faibussowitsch       PetscCall(PetscHMapFuncGetSize(fl->map, &n));
581*ed170139SJacob Faibussowitsch       PetscCall(PetscFunctionListCreate_Private(n, nl));
582*ed170139SJacob Faibussowitsch     }
583*ed170139SJacob Faibussowitsch     dup_map = (*nl)->map;
584*ed170139SJacob Faibussowitsch     PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
585e5c89e4eSSatish Balay   }
586e5c89e4eSSatish Balay   PetscFunctionReturn(0);
587e5c89e4eSSatish Balay }
588