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 <petscsys.h> /*I "petscsys.h" I*/ 7 8 #undef __FUNCT__ 9 #define __FUNCT__ "PetscFListGetPathAndFunction" 10 PetscErrorCode PetscFListGetPathAndFunction(const char name[],char *path[],char *function[]) 11 { 12 PetscErrorCode ierr; 13 char work[PETSC_MAX_PATH_LEN],*lfunction; 14 15 PetscFunctionBegin; 16 ierr = PetscStrncpy(work,name,sizeof(work));CHKERRQ(ierr); 17 work[sizeof(work) - 1] = 0; 18 ierr = PetscStrchr(work,':',&lfunction);CHKERRQ(ierr); 19 if (lfunction != work && lfunction && lfunction[1] != ':') { 20 lfunction[0] = 0; 21 ierr = PetscStrallocpy(work,path);CHKERRQ(ierr); 22 ierr = PetscStrallocpy(lfunction+1,function);CHKERRQ(ierr); 23 } else { 24 *path = 0; 25 ierr = PetscStrallocpy(name,function);CHKERRQ(ierr); 26 } 27 PetscFunctionReturn(0); 28 } 29 30 /* 31 This is the default list used by PETSc with the PetscDLLibrary register routines 32 */ 33 PetscDLLibrary PetscDLLibrariesLoaded = 0; 34 35 #if defined(PETSC_USE_DYNAMIC_LIBRARIES) 36 37 #undef __FUNCT__ 38 #define __FUNCT__ "PetscLoadDynamicLibrary" 39 static PetscErrorCode PetscLoadDynamicLibrary(const char *name,PetscBool *found) 40 { 41 char libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN]; 42 PetscErrorCode ierr; 43 44 PetscFunctionBegin; 45 ierr = PetscStrcpy(libs,"${PETSC_LIB_DIR}/libpetsc");CHKERRQ(ierr); 46 ierr = PetscStrcat(libs,name);CHKERRQ(ierr); 47 ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr); 48 if (*found) { 49 ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,dlib);CHKERRQ(ierr); 50 } else { 51 ierr = PetscStrcpy(libs,"${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc");CHKERRQ(ierr); 52 ierr = PetscStrcat(libs,name);CHKERRQ(ierr); 53 ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr); 54 if (*found) { 55 ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,dlib);CHKERRQ(ierr); 56 } 57 } 58 PetscFunctionReturn(0); 59 } 60 61 #endif 62 63 #undef __FUNCT__ 64 #define __FUNCT__ "PetscInitialize_DynamicLibraries" 65 /* 66 PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the 67 search path. 68 */ 69 PetscErrorCode PetscInitialize_DynamicLibraries(void) 70 { 71 char *libname[32]; 72 PetscErrorCode ierr; 73 PetscInt nmax,i; 74 #if defined(PETSC_USE_DYNAMIC_LIBRARIES) 75 PetscBool found; 76 #endif 77 78 PetscFunctionBegin; 79 nmax = 32; 80 ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_prepend",libname,&nmax,PETSC_NULL);CHKERRQ(ierr); 81 for (i=0; i<nmax; i++) { 82 ierr = PetscDLLibraryPrepend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,libname[i]);CHKERRQ(ierr); 83 ierr = PetscFree(libname[i]);CHKERRQ(ierr); 84 } 85 86 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) 87 /* 88 This just initializes the most basic PETSc stuff. 89 90 The classes, from PetscDraw to PetscTS, are initialized the first 91 time an XXCreate() is called. 92 */ 93 ierr = PetscSysInitializePackage(PETSC_NULL);CHKERRQ(ierr); 94 #else 95 #if defined(PETSC_USE_SINGLE_LIBRARY) 96 ierr = PetscLoadDynamicLibrary("",&found);CHKERRQ(ierr); 97 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!"); 98 #else 99 ierr = PetscLoadDynamicLibrary("sys",&found);CHKERRQ(ierr); 100 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!"); 101 ierr = PetscLoadDynamicLibrary("vec",&found);CHKERRQ(ierr); 102 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!"); 103 ierr = PetscLoadDynamicLibrary("mat",&found);CHKERRQ(ierr); 104 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!"); 105 ierr = PetscLoadDynamicLibrary("dm",&found);CHKERRQ(ierr); 106 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!"); 107 ierr = PetscLoadDynamicLibrary("characteristic",&found);CHKERRQ(ierr); 108 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Characteristic dynamic library \n You cannot move the dynamic libraries!"); 109 ierr = PetscLoadDynamicLibrary("ksp",&found);CHKERRQ(ierr); 110 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!"); 111 ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr); 112 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!"); 113 ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr); 114 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!"); 115 #endif 116 117 ierr = PetscLoadDynamicLibrary("mesh",&found);CHKERRQ(ierr); 118 ierr = PetscLoadDynamicLibrary("contrib",&found);CHKERRQ(ierr); 119 #endif 120 121 nmax = 32; 122 ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);CHKERRQ(ierr); 123 for (i=0; i<nmax; i++) { 124 ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&PetscDLLibrariesLoaded,libname[i]);CHKERRQ(ierr); 125 ierr = PetscFree(libname[i]);CHKERRQ(ierr); 126 } 127 128 PetscFunctionReturn(0); 129 } 130 131 #undef __FUNCT__ 132 #define __FUNCT__ "PetscFinalize_DynamicLibraries" 133 /* 134 PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries. 135 */ 136 PetscErrorCode PetscFinalize_DynamicLibraries(void) 137 { 138 PetscErrorCode ierr; 139 PetscBool flg = PETSC_FALSE; 140 141 PetscFunctionBegin; 142 ierr = PetscOptionsGetBool(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr); 143 if (flg) { ierr = PetscDLLibraryPrintPath(PetscDLLibrariesLoaded);CHKERRQ(ierr); } 144 ierr = PetscDLLibraryClose(PetscDLLibrariesLoaded);CHKERRQ(ierr); 145 PetscDLLibrariesLoaded = 0; 146 PetscFunctionReturn(0); 147 } 148 149 150 151 /* ------------------------------------------------------------------------------*/ 152 struct _n_PetscFList { 153 void (*routine)(void); /* the routine */ 154 char *path; /* path of link library containing routine */ 155 char *name; /* string to identify routine */ 156 char *rname; /* routine name in dynamic library */ 157 PetscFList next; /* next pointer */ 158 PetscFList next_list; /* used to maintain list of all lists for freeing */ 159 }; 160 161 /* 162 Keep a linked list of PetscFLists so that we can destroy all the left-over ones. 163 */ 164 static PetscFList dlallhead = 0; 165 166 #undef __FUNCT__ 167 #define __FUNCT__ "PetscFListAdd" 168 /*@C 169 PetscFListAdd - Given a routine and a string id, saves that routine in the 170 specified registry. 171 172 Formally Collective on MPI_Comm 173 174 Input Parameters: 175 + comm - the comm where this exists (currently not used) 176 . fl - pointer registry 177 . name - string to identify routine 178 . rname - routine name in dynamic library 179 - fnc - function pointer (optional if using dynamic libraries) 180 181 Notes: 182 To remove a registered routine, pass in a PETSC_NULL rname and fnc(). 183 184 Users who wish to register new classes for use by a particular PETSc 185 component (e.g., SNES) should generally call the registration routine 186 for that particular component (e.g., SNESRegisterDynamic()) instead of 187 calling PetscFListAdd() directly. 188 189 ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable} 190 occuring in pathname will be replaced with appropriate values. 191 192 Level: developer 193 194 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(), 195 PCRegisterDynamic(), TSRegisterDynamic(), PetscFList 196 @*/ 197 PetscErrorCode PetscFListAdd(MPI_Comm comm,PetscFList *fl,const char name[],const char rname[],void (*fnc)(void)) 198 { 199 PetscFList entry,ne; 200 PetscErrorCode ierr; 201 char *fpath,*fname; 202 203 PetscFunctionBegin; 204 if (!*fl) { 205 ierr = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr); 206 ierr = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr); 207 ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr); 208 entry->path = fpath; 209 entry->rname = fname; 210 entry->routine = fnc; 211 entry->next = 0; 212 *fl = entry; 213 214 /* add this new list to list of all lists */ 215 if (!dlallhead) { 216 dlallhead = *fl; 217 (*fl)->next_list = 0; 218 } else { 219 ne = dlallhead; 220 dlallhead = *fl; 221 (*fl)->next_list = ne; 222 } 223 } else { 224 /* search list to see if it is already there */ 225 ne = *fl; 226 while (ne) { 227 PetscBool founddup; 228 229 ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr); 230 if (founddup) { /* found duplicate */ 231 ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr); 232 ierr = PetscFree(ne->path);CHKERRQ(ierr); 233 ierr = PetscFree(ne->rname);CHKERRQ(ierr); 234 ne->path = fpath; 235 ne->rname = fname; 236 ne->routine = fnc; 237 PetscFunctionReturn(0); 238 } 239 if (ne->next) ne = ne->next; else break; 240 } 241 /* create new entry and add to end of list */ 242 ierr = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr); 243 ierr = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr); 244 ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr); 245 entry->path = fpath; 246 entry->rname = fname; 247 entry->routine = fnc; 248 entry->next = 0; 249 ne->next = entry; 250 } 251 PetscFunctionReturn(0); 252 } 253 254 #undef __FUNCT__ 255 #define __FUNCT__ "PetscFListDestroy" 256 /*@ 257 PetscFListDestroy - Destroys a list of registered routines. 258 259 Input Parameter: 260 . fl - pointer to list 261 262 Level: developer 263 264 .seealso: PetscFListAddDynamic(), PetscFList 265 @*/ 266 PetscErrorCode PetscFListDestroy(PetscFList *fl) 267 { 268 PetscFList next,entry,tmp = dlallhead; 269 PetscErrorCode ierr; 270 271 PetscFunctionBegin; 272 if (!*fl) PetscFunctionReturn(0); 273 if (!dlallhead) PetscFunctionReturn(0); 274 275 /* 276 Remove this entry from the master DL list (if it is in it) 277 */ 278 if (dlallhead == *fl) { 279 if (dlallhead->next_list) { 280 dlallhead = dlallhead->next_list; 281 } else { 282 dlallhead = 0; 283 } 284 } else { 285 while (tmp->next_list != *fl) { 286 tmp = tmp->next_list; 287 if (!tmp->next_list) break; 288 } 289 if (tmp->next_list) tmp->next_list = tmp->next_list->next_list; 290 } 291 292 /* free this list */ 293 entry = *fl; 294 while (entry) { 295 next = entry->next; 296 ierr = PetscFree(entry->path);CHKERRQ(ierr); 297 ierr = PetscFree(entry->name);CHKERRQ(ierr); 298 ierr = PetscFree(entry->rname);CHKERRQ(ierr); 299 ierr = PetscFree(entry);CHKERRQ(ierr); 300 entry = next; 301 } 302 *fl = 0; 303 PetscFunctionReturn(0); 304 } 305 306 /* 307 Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc. 308 */ 309 #undef __FUNCT__ 310 #define __FUNCT__ "PetscFListDestroyAll" 311 PetscErrorCode PetscFListDestroyAll(void) 312 { 313 PetscFList tmp2,tmp1 = dlallhead; 314 PetscErrorCode ierr; 315 316 PetscFunctionBegin; 317 while (tmp1) { 318 tmp2 = tmp1->next_list; 319 ierr = PetscFListDestroy(&tmp1);CHKERRQ(ierr); 320 tmp1 = tmp2; 321 } 322 dlallhead = 0; 323 PetscFunctionReturn(0); 324 } 325 326 #undef __FUNCT__ 327 #define __FUNCT__ "PetscFListFind" 328 /*@C 329 PetscFListFind - Given a name, finds the matching routine. 330 331 Input Parameters: 332 + fl - pointer to list 333 . comm - processors looking for routine 334 . name - name string 335 - searchlibraries - if not found in the list then search the dynamic libraries and executable for the symbol 336 337 Output Parameters: 338 . r - the routine 339 340 Level: developer 341 342 .seealso: PetscFListAddDynamic(), PetscFList 343 @*/ 344 PetscErrorCode PetscFListFind(MPI_Comm comm,PetscFList fl,const char name[],PetscBool searchlibraries,void (**r)(void)) 345 { 346 PetscFList entry = fl; 347 PetscErrorCode ierr; 348 char *function,*path; 349 PetscBool flg,f1,f2,f3; 350 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 351 char *newpath; 352 #endif 353 354 PetscFunctionBegin; 355 if (!name) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Trying to find routine with null name"); 356 357 *r = 0; 358 ierr = PetscFListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr); 359 360 /* 361 If path then append it to search libraries 362 */ 363 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 364 if (path) { 365 ierr = PetscDLLibraryAppend(comm,&PetscDLLibrariesLoaded,path);CHKERRQ(ierr); 366 } 367 #endif 368 369 while (entry) { 370 flg = PETSC_FALSE; 371 if (path && entry->path) { 372 ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr); 373 ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr); 374 ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr); 375 flg = (PetscBool) ((f1 && f2) || (f1 && f3)); 376 } else if (!path) { 377 ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr); 378 ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr); 379 flg = (PetscBool) (f1 || f2); 380 } else { 381 ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr); 382 if (flg) { 383 ierr = PetscFree(function);CHKERRQ(ierr); 384 ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr); 385 } else { 386 ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr); 387 } 388 } 389 390 if (flg) { 391 if (entry->routine) { 392 *r = entry->routine; 393 ierr = PetscFree(path);CHKERRQ(ierr); 394 ierr = PetscFree(function);CHKERRQ(ierr); 395 PetscFunctionReturn(0); 396 } 397 if (!(entry->rname && entry->rname[0])) { /* The entry has been cleared */ 398 ierr = PetscFree(function);CHKERRQ(ierr); 399 PetscFunctionReturn(0); 400 } 401 if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */ 402 ierr = PetscFree(function);CHKERRQ(ierr); 403 ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr); 404 } 405 406 /* it is not yet in memory so load from dynamic library */ 407 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 408 newpath = path; 409 if (!path) newpath = entry->path; 410 ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr); 411 if (*r) { 412 entry->routine = *r; 413 ierr = PetscFree(path);CHKERRQ(ierr); 414 ierr = PetscFree(function);CHKERRQ(ierr); 415 PetscFunctionReturn(0); 416 } 417 #endif 418 } 419 entry = entry->next; 420 } 421 422 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 423 if (searchlibraries) { 424 /* Function never registered; try for it anyway */ 425 ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr); 426 ierr = PetscFree(path);CHKERRQ(ierr); 427 if (*r) { 428 ierr = PetscFListAdd(comm,&fl,name,name,*r);CHKERRQ(ierr); 429 } 430 } 431 #endif 432 ierr = PetscFree(function);CHKERRQ(ierr); 433 PetscFunctionReturn(0); 434 } 435 436 #undef __FUNCT__ 437 #define __FUNCT__ "PetscFListView" 438 /*@ 439 PetscFListView - prints out contents of an PetscFList 440 441 Collective over MPI_Comm 442 443 Input Parameters: 444 + list - the list of functions 445 - viewer - currently ignored 446 447 Level: developer 448 449 .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList 450 @*/ 451 PetscErrorCode PetscFListView(PetscFList list,PetscViewer viewer) 452 { 453 PetscErrorCode ierr; 454 PetscBool iascii; 455 456 PetscFunctionBegin; 457 if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF; 458 PetscValidPointer(list,1); 459 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 460 461 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 462 if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported"); 463 464 while (list) { 465 if (list->path) { 466 ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr); 467 } else { 468 ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr); 469 } 470 list = list->next; 471 } 472 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 473 PetscFunctionReturn(0); 474 } 475 476 #undef __FUNCT__ 477 #define __FUNCT__ "PetscFListGet" 478 /*@C 479 PetscFListGet - Gets an array the contains the entries in PetscFList, this is used 480 by help etc. 481 482 Collective over MPI_Comm 483 484 Input Parameter: 485 . list - list of types 486 487 Output Parameter: 488 + array - array of names 489 - n - length of array 490 491 Notes: 492 This allocates the array so that must be freed. BUT the individual entries are 493 not copied so should not be freed. 494 495 Level: developer 496 497 .seealso: PetscFListAddDynamic(), PetscFList 498 @*/ 499 PetscErrorCode PetscFListGet(PetscFList list,const char ***array,int *n) 500 { 501 PetscErrorCode ierr; 502 PetscInt count = 0; 503 PetscFList klist = list; 504 505 PetscFunctionBegin; 506 while (list) { 507 list = list->next; 508 count++; 509 } 510 ierr = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr); 511 count = 0; 512 while (klist) { 513 (*array)[count] = klist->name; 514 klist = klist->next; 515 count++; 516 } 517 (*array)[count] = 0; 518 *n = count+1; 519 PetscFunctionReturn(0); 520 } 521 522 523 #undef __FUNCT__ 524 #define __FUNCT__ "PetscFListPrintTypes" 525 /*@C 526 PetscFListPrintTypes - Prints the methods available. 527 528 Collective over MPI_Comm 529 530 Input Parameters: 531 + comm - the communicator (usually MPI_COMM_WORLD) 532 . fd - file to print to, usually stdout 533 . prefix - prefix to prepend to name (optional) 534 . name - option string (for example, "-ksp_type") 535 . text - short description of the object (for example, "Krylov solvers") 536 . man - name of manual page that discusses the object (for example, "KSPCreate") 537 . list - list of types 538 - def - default (current) value 539 540 Level: developer 541 542 .seealso: PetscFListAddDynamic(), PetscFList 543 @*/ 544 PetscErrorCode PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list,const char def[]) 545 { 546 PetscErrorCode ierr; 547 PetscInt count = 0; 548 char p[64]; 549 550 PetscFunctionBegin; 551 if (!fd) fd = PETSC_STDOUT; 552 553 ierr = PetscStrcpy(p,"-");CHKERRQ(ierr); 554 if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);} 555 ierr = PetscFPrintf(comm,fd," %s%s <%s>: %s (one of)",p,name+1,def,text);CHKERRQ(ierr); 556 557 while (list) { 558 ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr); 559 list = list->next; 560 count++; 561 if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n ");CHKERRQ(ierr);} 562 } 563 ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr); 564 PetscFunctionReturn(0); 565 } 566 567 #undef __FUNCT__ 568 #define __FUNCT__ "PetscFListDuplicate" 569 /*@ 570 PetscFListDuplicate - Creates a new list from a given object list. 571 572 Input Parameters: 573 . fl - pointer to list 574 575 Output Parameters: 576 . nl - the new list (should point to 0 to start, otherwise appends) 577 578 Level: developer 579 580 .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy() 581 582 @*/ 583 PetscErrorCode PetscFListDuplicate(PetscFList fl,PetscFList *nl) 584 { 585 PetscErrorCode ierr; 586 char path[PETSC_MAX_PATH_LEN]; 587 588 PetscFunctionBegin; 589 while (fl) { 590 /* this is silly, rebuild the complete pathname */ 591 if (fl->path) { 592 ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr); 593 ierr = PetscStrcat(path,":");CHKERRQ(ierr); 594 ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr); 595 } else { 596 ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr); 597 } 598 ierr = PetscFListAdd(PETSC_COMM_WORLD,nl,path,fl->rname,fl->routine);CHKERRQ(ierr); 599 fl = fl->next; 600 } 601 PetscFunctionReturn(0); 602 } 603 604 605 #undef __FUNCT__ 606 #define __FUNCT__ "PetscFListConcat" 607 /* 608 PetscFListConcat - joins name of a libary, and the path where it is located 609 into a single string. 610 611 Input Parameters: 612 . path - path to the library name. 613 . name - name of the library 614 615 Output Parameters: 616 . fullname - the name that is the union of the path and the library name, 617 delimited by a semicolon, i.e., path:name 618 619 Notes: 620 If the path is NULL, assumes that the name, specified also includes 621 the path as path:name 622 623 */ 624 PetscErrorCode PetscFListConcat(const char path[],const char name[],char fullname[]) 625 { 626 PetscErrorCode ierr; 627 PetscFunctionBegin; 628 if (path) { 629 ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr); 630 ierr = PetscStrcat(fullname,":");CHKERRQ(ierr); 631 ierr = PetscStrcat(fullname,name);CHKERRQ(ierr); 632 } else { 633 ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr); 634 } 635 PetscFunctionReturn(0); 636 } 637 638 639 640 /* ------------------------------------------------------------------------------*/ 641 struct _n_PetscOpFList { 642 char *op; /* op name */ 643 PetscInt numArgs; /* number of arguments to the operation */ 644 char **argTypes; /* list of argument types */ 645 PetscVoidFunction routine; /* the routine */ 646 char *url; /* url naming the link library and the routine */ 647 char *path; /* path of link library containing routine */ 648 char *name; /* routine name in dynamic library */ 649 PetscOpFList next; /* next pointer */ 650 PetscOpFList next_list; /* used to maintain list of all lists for freeing */ 651 }; 652 653 /* 654 Keep a linked list of PetscOfFLists so that we can destroy all the left-over ones. 655 */ 656 static PetscOpFList opallhead = 0; 657 658 #undef __FUNCT__ 659 #define __FUNCT__ "PetscOpFListAdd" 660 /*@C 661 PetscOpFListAdd - Given a routine, a string id, and the type names of arguments saves that routine in the specified registry. 662 663 Formally collective on comm. 664 665 Input Parameters: 666 + comm - processors adding the op 667 . fl - list of known ops 668 . url - routine locator (optional, if not using dynamic libraries and a nonempty fnc) 669 . fnc - function pointer (optional, if using dynamic libraries and a nonempty url) 670 . op - operation name 671 . numArgs - number of op arguments 672 - argTypes - list of argument type names (const char*) 673 674 Notes: 675 To remove a registered routine, pass in a PETSC_NULL url and fnc(). 676 677 url can be of the form [/path/libname[.so.1.0]:]functionname[()] where items in [] denote optional 678 679 ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environment variable} 680 occuring in url will be replaced with appropriate values. 681 682 Level: developer 683 684 .seealso: PetscOpFListDestroy(), PetscOpFList, PetscFListAdd(), PetscFList 685 @*/ 686 PetscErrorCode PetscOpFListAdd(MPI_Comm comm, PetscOpFList *fl,const char url[],PetscVoidFunction fnc,const char op[], PetscInt numArgs, char* argTypes[]) 687 { 688 PetscOpFList entry,e,ne; 689 PetscErrorCode ierr; 690 char *fpath,*fname; 691 PetscInt i; 692 693 PetscFunctionBegin; 694 if (!*fl) { 695 ierr = PetscNew(struct _n_PetscOpFList,&entry);CHKERRQ(ierr); 696 ierr = PetscStrallocpy(op,&entry->op);CHKERRQ(ierr); 697 ierr = PetscStrallocpy(url,&(entry->url));CHKERRQ(ierr); 698 ierr = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr); 699 entry->path = fpath; 700 entry->name = fname; 701 entry->routine = fnc; 702 entry->numArgs = numArgs; 703 if (numArgs) { 704 ierr = PetscMalloc(sizeof(char*)*numArgs, &(entry->argTypes));CHKERRQ(ierr); 705 for (i = 0; i < numArgs; ++i) { 706 ierr = PetscStrallocpy(argTypes[i], &(entry->argTypes[i]));CHKERRQ(ierr); 707 } 708 } 709 entry->next = 0; 710 *fl = entry; 711 712 /* add this new list to list of all lists */ 713 if (!opallhead) { 714 opallhead = *fl; 715 (*fl)->next_list = 0; 716 } else { 717 ne = opallhead; 718 opallhead = *fl; 719 (*fl)->next_list = ne; 720 } 721 } else { 722 /* search list to see if it is already there */ 723 e = PETSC_NULL; 724 ne = *fl; 725 while (ne) { 726 PetscBool match; 727 ierr = PetscStrcmp(ne->op,op,&match);CHKERRQ(ierr); 728 if (!match) goto next; 729 if (numArgs == ne->numArgs) match = PETSC_TRUE; 730 else match = PETSC_FALSE; 731 if (!match) goto next; 732 if (numArgs) { 733 for (i = 0; i < numArgs; ++i) { 734 ierr = PetscStrcmp(argTypes[i], ne->argTypes[i], &match);CHKERRQ(ierr); 735 if (!match) goto next; 736 } 737 } 738 if (!url && !fnc) { 739 /* remove this record */ 740 if (e) e->next = ne->next; 741 ierr = PetscFree(ne->op);CHKERRQ(ierr); 742 ierr = PetscFree(ne->url);CHKERRQ(ierr); 743 ierr = PetscFree(ne->path);CHKERRQ(ierr); 744 ierr = PetscFree(ne->name);CHKERRQ(ierr); 745 if (numArgs) { 746 for (i = 0; i < numArgs; ++i) { 747 ierr = PetscFree(ne->argTypes[i]);CHKERRQ(ierr); 748 } 749 ierr = PetscFree(ne->argTypes);CHKERRQ(ierr); 750 } 751 ierr = PetscFree(ne);CHKERRQ(ierr); 752 } else { 753 /* Replace url, fpath, fname and fnc. */ 754 ierr = PetscStrallocpy(url, &(ne->url));CHKERRQ(ierr); 755 ierr = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr); 756 ierr = PetscFree(ne->path);CHKERRQ(ierr); 757 ierr = PetscFree(ne->name);CHKERRQ(ierr); 758 ne->path = fpath; 759 ne->name = fname; 760 ne->routine = fnc; 761 } 762 PetscFunctionReturn(0); 763 next: {e = ne; ne = ne->next;} 764 } 765 /* create new entry and add to end of list */ 766 ierr = PetscNew(struct _n_PetscOpFList,&entry);CHKERRQ(ierr); 767 ierr = PetscStrallocpy(op,&entry->op);CHKERRQ(ierr); 768 entry->numArgs = numArgs; 769 if (numArgs) { 770 ierr = PetscMalloc(sizeof(char*)*numArgs, &(entry->argTypes));CHKERRQ(ierr); 771 for (i = 0; i < numArgs; ++i) { 772 ierr = PetscStrallocpy(argTypes[i], &(entry->argTypes[i]));CHKERRQ(ierr); 773 } 774 } 775 ierr = PetscStrallocpy(url, &(entry->url));CHKERRQ(ierr); 776 ierr = PetscFListGetPathAndFunction(url,&fpath,&fname);CHKERRQ(ierr); 777 entry->path = fpath; 778 entry->name = fname; 779 entry->routine = fnc; 780 entry->next = 0; 781 ne->next = entry; 782 } 783 PetscFunctionReturn(0); 784 } 785 786 #undef __FUNCT__ 787 #define __FUNCT__ "PetscOpFListDestroy" 788 /*@C 789 PetscOpFListDestroy - Destroys a list of registered op routines. 790 791 Input Parameter: 792 . fl - pointer to list 793 794 Level: developer 795 796 .seealso: PetscOpFListAdd(), PetscOpFList 797 @*/ 798 PetscErrorCode PetscOpFListDestroy(PetscOpFList *fl) 799 { 800 PetscOpFList next,entry,tmp; 801 PetscErrorCode ierr; 802 PetscInt i; 803 804 PetscFunctionBegin; 805 if (!*fl) PetscFunctionReturn(0); 806 if (!opallhead) PetscFunctionReturn(0); 807 808 /* 809 Remove this entry from the master Op list (if it is in it) 810 */ 811 if (opallhead == *fl) { 812 if (opallhead->next_list) { 813 opallhead = opallhead->next_list; 814 } else { 815 opallhead = 0; 816 } 817 } else { 818 tmp = opallhead; 819 while (tmp->next_list != *fl) { 820 tmp = tmp->next_list; 821 if (!tmp->next_list) break; 822 } 823 if (tmp->next_list) tmp->next_list = tmp->next_list->next_list; 824 } 825 826 /* free this list */ 827 entry = *fl; 828 while (entry) { 829 next = entry->next; 830 ierr = PetscFree(entry->op);CHKERRQ(ierr); 831 for (i = 0; i < entry->numArgs; ++i) { 832 ierr = PetscFree(entry->argTypes[i]);CHKERRQ(ierr); 833 } 834 ierr = PetscFree(entry->argTypes);CHKERRQ(ierr); 835 ierr = PetscFree(entry->url);CHKERRQ(ierr); 836 ierr = PetscFree(entry->path);CHKERRQ(ierr); 837 ierr = PetscFree(entry->name);CHKERRQ(ierr); 838 ierr = PetscFree(entry);CHKERRQ(ierr); 839 entry = next; 840 } 841 *fl = 0; 842 PetscFunctionReturn(0); 843 } 844 845 /* 846 Destroys all the function lists that anyone has every registered, such as MatOpList, etc. 847 */ 848 #undef __FUNCT__ 849 #define __FUNCT__ "PetscOpFListDestroyAll" 850 PetscErrorCode PetscOpFListDestroyAll(void) 851 { 852 PetscOpFList tmp2,tmp1 = opallhead; 853 PetscErrorCode ierr; 854 855 PetscFunctionBegin; 856 while (tmp1) { 857 tmp2 = tmp1->next_list; 858 ierr = PetscOpFListDestroy(&tmp1);CHKERRQ(ierr); 859 tmp1 = tmp2; 860 } 861 opallhead = 0; 862 PetscFunctionReturn(0); 863 } 864 865 #undef __FUNCT__ 866 #define __FUNCT__ "PetscOpFListFind" 867 /*@C 868 PetscOpFListFind - Given a name, finds the matching op routine based on the declared arguments' type names. 869 870 Formally collective on MPI_Comm 871 872 Input Parameters: 873 + comm - processes looking for the op 874 . fl - pointer to list of known ops 875 . op - operation name 876 . numArgs - number of op arguments 877 - argTypes - list of argument type names 878 879 Output Parameters: 880 . r - routine implementing op with the given arg types 881 882 Level: developer 883 884 Notes: This is used to implement double dispatch and multiple dispatch based on the type names of the function arguments 885 886 .seealso: PetscOpFListAdd(), PetscOpFList 887 @*/ 888 PetscErrorCode PetscOpFListFind(MPI_Comm comm, PetscOpFList fl,PetscVoidFunction *r, const char* op, PetscInt numArgs, char* argTypes[]) 889 { 890 PetscOpFList entry; 891 PetscErrorCode ierr; 892 PetscBool match; 893 PetscInt i; 894 895 PetscFunctionBegin; 896 PetscValidPointer(r,3); 897 if (!op) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Attempting to find operation with null name"); 898 *r = PETSC_NULL; 899 match = PETSC_FALSE; 900 entry = fl; 901 while (entry) { 902 ierr = PetscStrcmp(entry->op,op,&match);CHKERRQ(ierr); 903 if (!match) goto next; 904 if (numArgs == entry->numArgs) 905 match = PETSC_TRUE; 906 else 907 match = PETSC_FALSE; 908 if (!match) goto next; 909 if (numArgs) { 910 for (i = 0; i < numArgs; ++i) { 911 ierr = PetscStrcmp(argTypes[i], entry->argTypes[i], &match);CHKERRQ(ierr); 912 if (!match) goto next; 913 } 914 } 915 break; 916 next: entry = entry->next; 917 } 918 if (match) { 919 if (entry->routine) { 920 *r = entry->routine; 921 } 922 #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) 923 else { 924 /* it is not yet in memory so load from dynamic library */ 925 ierr = PetscDLLibrarySym(comm,&PetscDLLibrariesLoaded,entry->path,entry->name,(void **)r);CHKERRQ(ierr); 926 if (*r) { 927 entry->routine = *r; 928 } 929 } 930 #endif 931 } 932 933 PetscFunctionReturn(0); 934 } 935 936 #undef __FUNCT__ 937 #define __FUNCT__ "PetscOpFListView" 938 /*@C 939 PetscOpFListView - prints out contents of a PetscOpFList 940 941 Collective on viewer 942 943 Input Parameters: 944 + list - the list of functions 945 - viewer - ASCII viewer Level: developer 946 947 .seealso: PetscOpFListAdd(), PetscOpFList 948 @*/ 949 PetscErrorCode PetscOpFListView(PetscOpFList list,PetscViewer viewer) 950 { 951 PetscErrorCode ierr; 952 PetscBool iascii; 953 PetscInt i; 954 955 PetscFunctionBegin; 956 if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF; 957 PetscValidPointer(list,1); 958 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 959 960 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 961 if (!iascii) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ASCII viewer supported"); 962 963 while (list) { 964 if (list->url) { 965 ierr = PetscViewerASCIIPrintf(viewer," %s: ",list->url);CHKERRQ(ierr); 966 } 967 ierr = PetscViewerASCIIPrintf(viewer, "%s(", list->op);CHKERRQ(ierr); 968 for (i = 0; i < list->numArgs;++i) { 969 if (i > 0) { 970 ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr); 971 } 972 ierr = PetscViewerASCIIPrintf(viewer, "%s", list->argTypes[i]);CHKERRQ(ierr); 973 } 974 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 975 list = list->next; 976 } 977 PetscFunctionReturn(0); 978 } 979