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 299 zeroed) rather than the pointer. 300 **/ 301 int CeedFree(void *p) { 302 free(*(void **)p); 303 *(void **)p = NULL; 304 return 0; 305 } 306 307 /** 308 @brief Wait for a CeedRequest to complete. 309 310 Calling CeedRequestWait on a NULL request is a no-op. 311 312 @param req Address of CeedRequest to wait for; zeroed on completion. 313 314 @return An error code: 0 - success, otherwise - failure 315 316 @ref Advanced 317 **/ 318 int CeedRequestWait(CeedRequest *req) { 319 if (!*req) 320 return 0; 321 return CeedError(NULL, 2, "CeedRequestWait not implemented"); 322 } 323 324 /** 325 @brief Initialize a \ref Ceed context to use the specified resource. 326 327 @param resource Resource to use, e.g., "/cpu/self" 328 @param ceed The library context 329 @sa CeedRegister() CeedDestroy() 330 331 @return An error code: 0 - success, otherwise - failure 332 333 @ref Basic 334 **/ 335 int CeedInit(const char *resource, Ceed *ceed) { 336 int ierr; 337 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 338 339 // Find matching backend 340 if (!resource) 341 // LCOV_EXCL_START 342 return CeedError(NULL, 1, "No resource provided"); 343 // LCOV_EXCL_STOP 344 345 for (size_t i=0; i<num_backends; i++) { 346 size_t n; 347 const char *prefix = backends[i].prefix; 348 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 349 priority = backends[i].priority; 350 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 351 matchlen = n; 352 matchpriority = priority; 353 matchidx = i; 354 } 355 } 356 if (!matchlen) 357 // LCOV_EXCL_START 358 return CeedError(NULL, 1, "No suitable backend"); 359 // LCOV_EXCL_STOP 360 361 // Setup Ceed 362 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 363 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 364 if (!ceed_error_handler) 365 ceed_error_handler = "abort"; 366 if (!strcmp(ceed_error_handler, "exit")) 367 (*ceed)->Error = CeedErrorExit; 368 else 369 (*ceed)->Error = CeedErrorAbort; 370 (*ceed)->refcount = 1; 371 (*ceed)->data = NULL; 372 373 // Set lookup table 374 foffset foffsets[] = { 375 CEED_FTABLE_ENTRY(Ceed, Error), 376 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 377 CEED_FTABLE_ENTRY(Ceed, Destroy), 378 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 379 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 380 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 381 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 382 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 383 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 384 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 385 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 386 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 387 CEED_FTABLE_ENTRY(CeedVector, SetArray), 388 CEED_FTABLE_ENTRY(CeedVector, SetValue), 389 CEED_FTABLE_ENTRY(CeedVector, GetArray), 390 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 391 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 392 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 393 CEED_FTABLE_ENTRY(CeedVector, Norm), 394 CEED_FTABLE_ENTRY(CeedVector, Destroy), 395 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 396 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 397 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 398 CEED_FTABLE_ENTRY(CeedBasis, Apply), 399 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 400 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 401 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 402 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 403 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 404 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 405 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 406 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 407 CEED_FTABLE_ENTRY(CeedOperator, Apply), 408 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 409 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 410 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 411 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 412 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 413 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 414 }; 415 416 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 417 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 418 419 // Set fallback for advanced CeedOperator functions 420 const char fallbackresource[] = "/cpu/self/ref/serial"; 421 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 422 CeedChk(ierr); 423 424 // Backend specific setup 425 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 426 427 // Copy resource prefix, if backend setup sucessful 428 size_t len = strlen(backends[matchidx].prefix); 429 char *tmp; 430 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 431 memcpy(tmp, backends[matchidx].prefix, len+1); 432 (*ceed)->resource = tmp; 433 434 return 0; 435 } 436 437 /** 438 @brief Retrieve a parent Ceed context 439 440 @param ceed Ceed context to retrieve parent of 441 @param[out] parent Address to save the parent to 442 443 @return An error code: 0 - success, otherwise - failure 444 445 @ref Developer 446 **/ 447 int CeedGetParent(Ceed ceed, Ceed *parent) { 448 int ierr; 449 if (ceed->parent) { 450 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 451 return 0; 452 } 453 *parent = ceed; 454 return 0; 455 } 456 457 /** 458 @brief Retrieve a delegate Ceed context 459 460 @param ceed Ceed context to retrieve delegate of 461 @param[out] delegate Address to save the delegate to 462 463 @return An error code: 0 - success, otherwise - failure 464 465 @ref Developer 466 **/ 467 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 468 *delegate = ceed->delegate; 469 return 0; 470 } 471 472 /** 473 @brief Set a delegate Ceed context 474 475 This function allows a Ceed context to set a delegate Ceed context. All 476 backend implementations default to the delegate Ceed context, unless 477 overridden. 478 479 @param ceed Ceed context to set delegate of 480 @param[out] delegate Address to set the delegate to 481 482 @return An error code: 0 - success, otherwise - failure 483 484 @ref Advanced 485 **/ 486 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 487 ceed->delegate = delegate; 488 delegate->parent = ceed; 489 return 0; 490 } 491 492 /** 493 @brief Retrieve a delegate Ceed context for a specific object type 494 495 @param ceed Ceed context to retrieve delegate of 496 @param[out] delegate Address to save the delegate to 497 @param[in] objname Name of the object type to retrieve delegate for 498 499 @return An error code: 0 - success, otherwise - failure 500 501 @ref Developer 502 **/ 503 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 504 CeedInt ierr; 505 506 // Check for object delegate 507 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 508 if (!strcmp(objname, ceed->objdelegates->objname)) { 509 *delegate = ceed->objdelegates->delegate; 510 return 0; 511 } 512 513 // Use default delegate if no object delegate 514 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 515 516 return 0; 517 } 518 519 /** 520 @brief Set a delegate Ceed context for a specific object type 521 522 This function allows a Ceed context to set a delegate Ceed context for a 523 given type of Ceed object. All backend implementations default to the 524 delegate Ceed context for this object. For example, 525 CeedSetObjectDelegate(ceed, refceed, "Basis") 526 uses refceed implementations for all CeedBasis backend functions. 527 528 @param ceed Ceed context to set delegate of 529 @param[out] delegate Address to set the delegate to 530 @param[in] objname Name of the object type to set delegate for 531 532 @return An error code: 0 - success, otherwise - failure 533 534 @ref Advanced 535 **/ 536 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 537 CeedInt ierr; 538 CeedInt count = ceed->objdelegatecount; 539 540 // Malloc or Realloc 541 if (count) { 542 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 543 } else { 544 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 545 } 546 ceed->objdelegatecount++; 547 548 // Set object delegate 549 ceed->objdelegates[count].delegate = delegate; 550 size_t slen = strlen(objname) + 1; 551 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 552 memcpy(ceed->objdelegates[count].objname, objname, slen); 553 554 // Set delegate parent 555 delegate->parent = ceed; 556 557 return 0; 558 } 559 560 /** 561 @brief Set the fallback resource for CeedOperators. The current resource, if 562 any, is freed by calling this function. This string is freed upon the 563 destruction of the Ceed context. 564 565 @param[out] ceed Ceed context 566 @param resource Fallback resource to set 567 568 @return An error code: 0 - success, otherwise - failure 569 570 @ref Advanced 571 **/ 572 573 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 574 int ierr; 575 576 // Free old 577 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 578 579 // Set new 580 size_t len = strlen(resource); 581 char *tmp; 582 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 583 memcpy(tmp, resource, len+1); 584 ceed->opfallbackresource = tmp; 585 586 return 0; 587 } 588 589 /** 590 @brief Get the fallback resource for CeedOperators 591 592 @param ceed Ceed context 593 @param[out] resource Variable to store fallback resource 594 595 @return An error code: 0 - success, otherwise - failure 596 597 @ref Advanced 598 **/ 599 600 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 601 *resource = (const char *)ceed->opfallbackresource; 602 return 0; 603 } 604 605 /** 606 @brief Get the parent Ceed context associated with a fallback Ceed context 607 for a CeedOperator 608 609 @param ceed Ceed context 610 @param[out] parent Variable to store parent Ceed context 611 612 @return An error code: 0 - success, otherwise - failure 613 614 @ref Advanced 615 **/ 616 617 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 618 *parent = ceed->opfallbackparent; 619 return 0; 620 } 621 622 /** 623 @brief Return Ceed context preferred memory type 624 625 @param ceed Ceed context to get preferred memory type of 626 @param[out] type Address to save preferred memory type to 627 628 @return An error code: 0 - success, otherwise - failure 629 630 @ref Basic 631 **/ 632 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 633 int ierr; 634 635 if (ceed->GetPreferredMemType) { 636 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 637 } else { 638 Ceed delegate; 639 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 640 641 if (delegate) { 642 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 643 } else { 644 *type = CEED_MEM_HOST; 645 } 646 } 647 648 return 0; 649 } 650 651 /** 652 @brief Set a backend function 653 654 This function is used for a backend to set the function associated with 655 the Ceed objects. For example, 656 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 657 sets the backend implementation of 'CeedVectorCreate' and 658 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 659 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 660 is not required for the object type ("Basis" vs "CeedBasis"). 661 662 @param ceed Ceed context for error handling 663 @param type Type of Ceed object to set function for 664 @param[out] object Ceed object to set function for 665 @param fname Name of function to set 666 @param f Function to set 667 668 @return An error code: 0 - success, otherwise - failure 669 670 @ref Advanced 671 **/ 672 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 673 const char *fname, int (*f)()) { 674 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 675 676 // Build lookup name 677 if (strcmp(type, "Ceed")) 678 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 679 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 680 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 681 682 // Find and use offset 683 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 684 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 685 size_t offset = ceed->foffsets[i].offset; 686 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 687 *fpointer = f; 688 return 0; 689 } 690 691 // LCOV_EXCL_START 692 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 693 "object '%s'", fname, type); 694 // LCOV_EXCL_STOP 695 } 696 697 /** 698 @brief Retrieve backend data for a Ceed context 699 700 @param ceed Ceed context to retrieve data of 701 @param[out] data Address to save data to 702 703 @return An error code: 0 - success, otherwise - failure 704 705 @ref Advanced 706 **/ 707 int CeedGetData(Ceed ceed, void **data) { 708 *data = ceed->data; 709 return 0; 710 } 711 712 /** 713 @brief Set backend data for a Ceed context 714 715 @param ceed Ceed context to set data of 716 @param data Address of data to set 717 718 @return An error code: 0 - success, otherwise - failure 719 720 @ref Advanced 721 **/ 722 int CeedSetData(Ceed ceed, void **data) { 723 ceed->data = *data; 724 return 0; 725 } 726 727 /** 728 @brief Get the full resource name for a Ceed context 729 730 @param ceed Ceed context to get resource name of 731 @param[out] resource Variable to store resource name 732 733 @return An error code: 0 - success, otherwise - failure 734 735 @ref Basic 736 **/ 737 738 int CeedGetResource(Ceed ceed, const char **resource) { 739 *resource = (const char *)ceed->resource; 740 return 0; 741 } 742 743 /** 744 @brief Destroy a Ceed context 745 746 @param ceed Address of Ceed context to destroy 747 748 @return An error code: 0 - success, otherwise - failure 749 750 @ref Basic 751 **/ 752 int CeedDestroy(Ceed *ceed) { 753 int ierr; 754 if (!*ceed || --(*ceed)->refcount > 0) 755 return 0; 756 757 if ((*ceed)->delegate) { 758 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 759 } 760 761 if ((*ceed)->objdelegatecount > 0) { 762 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 763 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 764 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 765 } 766 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 767 } 768 769 if ((*ceed)->Destroy) { 770 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 771 } 772 773 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 774 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 775 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 776 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 777 ierr = CeedFree(ceed); CeedChk(ierr); 778 return 0; 779 } 780 781 /// @} 782