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