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