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