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