1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #define _POSIX_C_SOURCE 200112 18 #include <ceed-impl.h> 19 #include <ceed-backend.h> 20 #include <limits.h> 21 #include <stdarg.h> 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 /// @cond DOXYGEN_SKIP 28 static CeedRequest ceed_request_immediate; 29 static CeedRequest ceed_request_ordered; 30 31 static struct { 32 char prefix[CEED_MAX_RESOURCE_LEN]; 33 int (*init)(const char *resource, Ceed f); 34 unsigned int priority; 35 } backends[32]; 36 static size_t num_backends; 37 38 #define CEED_FTABLE_ENTRY(class, method) \ 39 {#class #method, offsetof(struct class ##_private, method)} 40 /// @endcond 41 42 /// @file 43 /// Implementation of core components of Ceed library 44 /// 45 /// @addtogroup Ceed 46 /// @{ 47 48 /** 49 @brief Request immediate completion 50 51 This predefined constant is passed as the \ref CeedRequest argument to 52 interfaces when the caller wishes for the operation to be performed 53 immediately. The code 54 55 @code 56 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 57 @endcode 58 59 is semantically equivalent to 60 61 @code 62 CeedRequest request; 63 CeedOperatorApply(op, ..., &request); 64 CeedRequestWait(&request); 65 @endcode 66 67 @sa CEED_REQUEST_ORDERED 68 **/ 69 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 70 71 /** 72 @brief Request ordered completion 73 74 This predefined constant is passed as the \ref CeedRequest argument to 75 interfaces when the caller wishes for the operation to be completed in the 76 order that it is submitted to the device. It is typically used in a construct 77 such as 78 79 @code 80 CeedRequest request; 81 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 82 CeedOperatorApply(op2, ..., &request); 83 // other optional work 84 CeedWait(&request); 85 @endcode 86 87 which allows the sequence to complete asynchronously but does not start 88 `op2` until `op1` has completed. 89 90 @todo The current implementation is overly strict, offering equivalent 91 semantics to CEED_REQUEST_IMMEDIATE. 92 93 @sa CEED_REQUEST_IMMEDIATE 94 */ 95 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 96 97 /** 98 @brief Error handling implementation; use \ref CeedError instead. 99 100 @ref Developer 101 **/ 102 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 103 int ecode, const char *format, ...) { 104 va_list args; 105 int retval; 106 va_start(args, format); 107 if (ceed) { 108 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args); 109 } else { 110 // This function doesn't actually return 111 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 112 } 113 va_end(args); 114 return retval; 115 } 116 117 /** 118 @brief Error handler that returns without printing anything. 119 120 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 121 122 @ref Developer 123 **/ 124 // LCOV_EXCL_START 125 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 126 const char *func, int ecode, const char *format, 127 va_list args) { 128 return ecode; 129 } 130 // LCOV_EXCL_STOP 131 132 /** 133 @brief Error handler that prints to stderr and aborts 134 135 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 136 137 @ref Developer 138 **/ 139 // LCOV_EXCL_START 140 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 141 const char *func, int ecode, const char *format, 142 va_list args) { 143 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 144 vfprintf(stderr, format, args); 145 fprintf(stderr, "\n"); 146 abort(); 147 return ecode; 148 } 149 // LCOV_EXCL_STOP 150 151 /** 152 @brief Error handler that prints to stderr and exits 153 154 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 155 156 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 157 handlers (e.g., as used by gcov) are run. 158 159 @ref Developer 160 **/ 161 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 162 int ecode, const char *format, va_list args) { 163 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 164 vfprintf(stderr, format, args); 165 fprintf(stderr, "\n"); 166 exit(ecode); 167 return ecode; 168 } 169 170 /** 171 @brief Set error handler 172 173 A default error handler is set in CeedInit(). Use this function to change 174 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 175 error handler. 176 177 @ref Developer 178 **/ 179 int CeedSetErrorHandler(Ceed ceed, 180 int (eh)(Ceed, const char *, int, const char *, 181 int, const char *, va_list)) { 182 ceed->Error = eh; 183 return 0; 184 } 185 186 /** 187 @brief Register a Ceed backend 188 189 @param prefix Prefix of resources for this backend to respond to. For 190 example, the reference backend responds to "/cpu/self". 191 @param init Initialization function called by CeedInit() when the backend 192 is selected to drive the requested resource. 193 @param priority Integer priority. Lower values are preferred in case the 194 resource requested by CeedInit() has non-unique best prefix 195 match. 196 197 @return An error code: 0 - success, otherwise - failure 198 199 @ref Advanced 200 **/ 201 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 202 unsigned int priority) { 203 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 204 // LCOV_EXCL_START 205 return CeedError(NULL, 1, "Too many backends"); 206 // LCOV_EXCL_STOP 207 208 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 209 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 210 backends[num_backends].init = init; 211 backends[num_backends].priority = priority; 212 num_backends++; 213 return 0; 214 } 215 216 /** 217 @brief Allocate an array on the host; use CeedMalloc() 218 219 Memory usage can be tracked by the library. This ensures sufficient 220 alignment for vectorization and should be used for large allocations. 221 222 @param n Number of units to allocate 223 @param unit Size of each unit 224 @param p Address of pointer to hold the result. 225 226 @return An error code: 0 - success, otherwise - failure 227 228 @sa CeedFree() 229 230 @ref Advanced 231 **/ 232 int CeedMallocArray(size_t n, size_t unit, void *p) { 233 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 234 if (ierr) 235 // LCOV_EXCL_START 236 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 237 "members of size %zd\n", n, unit); 238 // LCOV_EXCL_STOP 239 240 return 0; 241 } 242 243 /** 244 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 245 246 Memory usage can be tracked by the library. 247 248 @param n Number of units to allocate 249 @param unit Size of each unit 250 @param p Address of pointer to hold the result. 251 252 @return An error code: 0 - success, otherwise - failure 253 254 @sa CeedFree() 255 256 @ref Advanced 257 **/ 258 int CeedCallocArray(size_t n, size_t unit, void *p) { 259 *(void **)p = calloc(n, unit); 260 if (n && unit && !*(void **)p) 261 // LCOV_EXCL_START 262 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 263 "%zd\n", n, unit); 264 // LCOV_EXCL_STOP 265 266 return 0; 267 } 268 269 /** 270 @brief Reallocate an array on the host; use CeedRealloc() 271 272 Memory usage can be tracked by the library. 273 274 @param n Number of units to allocate 275 @param unit Size of each unit 276 @param p Address of pointer to hold the result. 277 278 @return An error code: 0 - success, otherwise - failure 279 280 @sa CeedFree() 281 282 @ref Advanced 283 **/ 284 int CeedReallocArray(size_t n, size_t unit, void *p) { 285 *(void **)p = realloc(*(void **)p, n*unit); 286 if (n && unit && !*(void **)p) 287 // LCOV_EXCL_START 288 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 289 "%zd\n", n, unit); 290 // LCOV_EXCL_STOP 291 292 return 0; 293 } 294 295 /// Free memory allocated using CeedMalloc() or CeedCalloc() 296 /// 297 /// @param p address of pointer to memory. This argument is of type void* to 298 /// avoid needing a cast, but is the address of the pointer (which is zeroed) 299 /// rather than the pointer. 300 int CeedFree(void *p) { 301 free(*(void **)p); 302 *(void **)p = NULL; 303 return 0; 304 } 305 306 /** 307 @brief Wait for a CeedRequest to complete. 308 309 Calling CeedRequestWait on a NULL request is a no-op. 310 311 @param req Address of CeedRequest to wait for; zeroed on completion. 312 313 @return An error code: 0 - success, otherwise - failure 314 315 @ref Advanced 316 **/ 317 int CeedRequestWait(CeedRequest *req) { 318 if (!*req) 319 return 0; 320 return CeedError(NULL, 2, "CeedRequestWait not implemented"); 321 } 322 323 /** 324 @brief Initialize a \ref Ceed to use the specified resource. 325 326 @param resource Resource to use, e.g., "/cpu/self" 327 @param ceed The library context 328 @sa CeedRegister() CeedDestroy() 329 330 @return An error code: 0 - success, otherwise - failure 331 332 @ref Basic 333 **/ 334 int CeedInit(const char *resource, Ceed *ceed) { 335 int ierr; 336 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 337 338 // Find matching backend 339 if (!resource) 340 // LCOV_EXCL_START 341 return CeedError(NULL, 1, "No resource provided"); 342 // LCOV_EXCL_STOP 343 344 for (size_t i=0; i<num_backends; i++) { 345 size_t n; 346 const char *prefix = backends[i].prefix; 347 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 348 priority = backends[i].priority; 349 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 350 matchlen = n; 351 matchpriority = priority; 352 matchidx = i; 353 } 354 } 355 if (!matchlen) 356 // LCOV_EXCL_START 357 return CeedError(NULL, 1, "No suitable backend"); 358 // LCOV_EXCL_STOP 359 360 // Setup Ceed 361 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 362 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 363 if (!ceed_error_handler) 364 ceed_error_handler = "abort"; 365 if (!strcmp(ceed_error_handler, "exit")) 366 (*ceed)->Error = CeedErrorExit; 367 else 368 (*ceed)->Error = CeedErrorAbort; 369 (*ceed)->refcount = 1; 370 (*ceed)->data = NULL; 371 372 // Set lookup table 373 foffset foffsets[] = { 374 CEED_FTABLE_ENTRY(Ceed, Error), 375 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 376 CEED_FTABLE_ENTRY(Ceed, Destroy), 377 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 378 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 379 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 380 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 381 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 382 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 383 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 384 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 385 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 386 CEED_FTABLE_ENTRY(CeedVector, SetArray), 387 CEED_FTABLE_ENTRY(CeedVector, SetValue), 388 CEED_FTABLE_ENTRY(CeedVector, GetArray), 389 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 390 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 391 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 392 CEED_FTABLE_ENTRY(CeedVector, Destroy), 393 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 394 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 395 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 396 CEED_FTABLE_ENTRY(CeedBasis, Apply), 397 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 398 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 399 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 400 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 401 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 402 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 403 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 404 CEED_FTABLE_ENTRY(CeedOperator, Apply), 405 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 406 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 407 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 408 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 409 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 410 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 411 }; 412 413 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 414 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 415 416 // Set fallback for advanced CeedOperator functions 417 const char fallbackresource[] = "/cpu/self/ref/serial"; 418 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 419 CeedChk(ierr); 420 421 // Backend specific setup 422 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 423 424 // Copy resource prefix, if backend setup sucessful 425 size_t len = strlen(backends[matchidx].prefix); 426 char *tmp; 427 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 428 memcpy(tmp, backends[matchidx].prefix, len+1); 429 (*ceed)->resource = tmp; 430 431 return 0; 432 } 433 434 /** 435 @brief Retrieve a parent CEED 436 437 @param ceed Ceed to retrieve parent of 438 @param[out] parent Address to save the parent to 439 440 @return An error code: 0 - success, otherwise - failure 441 442 @ref Developer 443 **/ 444 int CeedGetParent(Ceed ceed, Ceed *parent) { 445 int ierr; 446 if (ceed->parent) { 447 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 448 return 0; 449 } 450 *parent = ceed; 451 return 0; 452 } 453 454 /** 455 @brief Retrieve a delegate CEED 456 457 @param ceed Ceed to retrieve delegate of 458 @param[out] delegate Address to save the delegate to 459 460 @return An error code: 0 - success, otherwise - failure 461 462 @ref Developer 463 **/ 464 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 465 *delegate = ceed->delegate; 466 return 0; 467 } 468 469 /** 470 @brief Set a delegate CEED 471 472 This function allows a CEED to set a delegate CEED. All backend 473 implementations default to the delegate CEED, unless overridden. 474 475 @param ceed Ceed to set delegate of 476 @param[out] delegate Address to set the delegate to 477 478 @return An error code: 0 - success, otherwise - failure 479 480 @ref Advanced 481 **/ 482 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 483 ceed->delegate = delegate; 484 delegate->parent = ceed; 485 return 0; 486 } 487 488 /** 489 @brief Retrieve a delegate CEED for a specific object type 490 491 @param ceed Ceed to retrieve delegate of 492 @param[out] delegate Address to save the delegate to 493 @param[in] objname Name of the object type to retrieve delegate for 494 495 @return An error code: 0 - success, otherwise - failure 496 497 @ref Developer 498 **/ 499 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 500 CeedInt ierr; 501 502 // Check for object delegate 503 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 504 if (!strcmp(objname, ceed->objdelegates->objname)) { 505 *delegate = ceed->objdelegates->delegate; 506 return 0; 507 } 508 509 // Use default delegate if no object delegate 510 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 511 512 return 0; 513 } 514 515 /** 516 @brief Set a delegate CEED for a specific object type 517 518 This function allows a CEED to set a delegate CEED for a given type of 519 CEED object. All backend implementations default to the delegate CEED for 520 this object. For example, 521 CeedSetObjectDelegate(ceed, refceed, "Basis") 522 uses refceed implementations for all CeedBasis backend functions. 523 524 @param ceed Ceed to set delegate of 525 @param[out] delegate Address to set the delegate to 526 @param[in] objname Name of the object type to set delegate for 527 528 @return An error code: 0 - success, otherwise - failure 529 530 @ref Advanced 531 **/ 532 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 533 CeedInt ierr; 534 CeedInt count = ceed->objdelegatecount; 535 536 // Malloc or Realloc 537 if (count) { 538 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 539 } else { 540 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 541 } 542 ceed->objdelegatecount++; 543 544 // Set object delegate 545 ceed->objdelegates[count].delegate = delegate; 546 size_t slen = strlen(objname) + 1; 547 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 548 memcpy(ceed->objdelegates[count].objname, objname, slen); 549 550 // Set delegate parent 551 delegate->parent = ceed; 552 553 return 0; 554 } 555 556 /** 557 @brief Set the fallback resource for CeedOperators. The current resource, if 558 any, is freed by calling this function. This string is freed upon the 559 destruction of the Ceed. 560 561 @param[out] ceed Ceed context 562 @param resource Fallback resource to set 563 564 @return An error code: 0 - success, otherwise - failure 565 566 @ref Advanced 567 **/ 568 569 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 570 int ierr; 571 572 // Free old 573 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 574 575 // Set new 576 size_t len = strlen(resource); 577 char *tmp; 578 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 579 memcpy(tmp, resource, len+1); 580 ceed->opfallbackresource = tmp; 581 582 return 0; 583 } 584 585 /** 586 @brief Get the fallback resource for CeedOperators 587 588 @param ceed Ceed context 589 @param[out] resource Variable to store fallback resource 590 591 @return An error code: 0 - success, otherwise - failure 592 593 @ref Advanced 594 **/ 595 596 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 597 *resource = (const char *)ceed->opfallbackresource; 598 return 0; 599 } 600 601 /** 602 @brief Get the parent Ceed associated with a fallback Ceed for a CeedOperator 603 604 @param ceed Ceed context 605 @param[out] ceed Variable to store parent Ceed 606 607 @return An error code: 0 - success, otherwise - failure 608 609 @ref Advanced 610 **/ 611 612 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 613 *parent = ceed->opfallbackparent; 614 return 0; 615 } 616 617 /** 618 @brief Return Ceed preferred memory type 619 620 @param ceed Ceed to get preferred memory type of 621 @param[out] type Address to save preferred memory type to 622 623 @return An error code: 0 - success, otherwise - failure 624 625 @ref Basic 626 **/ 627 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 628 int ierr; 629 630 if (ceed->GetPreferredMemType) { 631 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 632 } else { 633 Ceed delegate; 634 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 635 636 if (delegate) { 637 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 638 } else { 639 *type = CEED_MEM_HOST; 640 } 641 } 642 643 return 0; 644 } 645 646 /** 647 @brief Set a backend function 648 649 This function is used for a backend to set the function associated with 650 the CEED objects. For example, 651 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 652 sets the backend implementation of 'CeedVectorCreate' and 653 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 654 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 655 is not required for the object type ("Basis" vs "CeedBasis"). 656 657 @param ceed Ceed for error handling 658 @param type Type of Ceed object to set function for 659 @param[out] object Ceed object to set function for 660 @param fname Name of function to set 661 @param f Function to set 662 663 @return An error code: 0 - success, otherwise - failure 664 665 @ref Advanced 666 **/ 667 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 668 const char *fname, int (*f)()) { 669 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 670 671 // Build lookup name 672 if (strcmp(type, "Ceed")) 673 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 674 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 675 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 676 677 // Find and use offset 678 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 679 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 680 size_t offset = ceed->foffsets[i].offset; 681 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 682 *fpointer = f; 683 return 0; 684 } 685 686 // LCOV_EXCL_START 687 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 688 "object '%s'", fname, type); 689 // LCOV_EXCL_STOP 690 } 691 692 /** 693 @brief Retrieve backend data for a CEED 694 695 @param ceed Ceed to retrieve data of 696 @param[out] data Address to save data to 697 698 @return An error code: 0 - success, otherwise - failure 699 700 @ref Advanced 701 **/ 702 int CeedGetData(Ceed ceed, void **data) { 703 *data = ceed->data; 704 return 0; 705 } 706 707 /** 708 @brief Set backend data for a CEED 709 710 @param ceed Ceed to set data of 711 @param data Address of data to set 712 713 @return An error code: 0 - success, otherwise - failure 714 715 @ref Advanced 716 **/ 717 int CeedSetData(Ceed ceed, void **data) { 718 ceed->data = *data; 719 return 0; 720 } 721 722 /** 723 @brief Get the full resource name for a CEED 724 725 @param ceed Ceed to get resource name of 726 @param[out] resource Variable to store resource name 727 728 @return An error code: 0 - success, otherwise - failure 729 730 @ref Basic 731 **/ 732 733 int CeedGetResource(Ceed ceed, const char **resource) { 734 *resource = (const char *)ceed->resource; 735 return 0; 736 } 737 738 /** 739 @brief Destroy a Ceed context 740 741 @param ceed Address of Ceed context to destroy 742 743 @return An error code: 0 - success, otherwise - failure 744 745 @ref Basic 746 **/ 747 int CeedDestroy(Ceed *ceed) { 748 int ierr; 749 750 if (!*ceed || --(*ceed)->refcount > 0) 751 return 0; 752 if ((*ceed)->delegate) { 753 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 754 } 755 if ((*ceed)->objdelegatecount > 0) { 756 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 757 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 758 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 759 } 760 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 761 } 762 if ((*ceed)->Destroy) { 763 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 764 } 765 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 766 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 767 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 768 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 769 ierr = CeedFree(ceed); CeedChk(ierr); 770 return 0; 771 } 772 773 /// @} 774