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 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 125 const char *func, int ecode, const char *format, 126 va_list args) { 127 return ecode; 128 } 129 130 /** 131 @brief Error handler that prints to stderr and aborts 132 133 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 134 135 @ref Developer 136 **/ 137 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 138 const char *func, int ecode, const char *format, 139 va_list args) { 140 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 141 vfprintf(stderr, format, args); 142 fprintf(stderr, "\n"); 143 abort(); 144 return ecode; 145 } 146 147 /** 148 @brief Error handler that prints to stderr and exits 149 150 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 151 152 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 153 handlers (e.g., as used by gcov) are run. 154 155 @ref Developer 156 **/ 157 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 158 int ecode, const char *format, va_list args) { 159 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 160 vfprintf(stderr, format, args); 161 fprintf(stderr, "\n"); 162 exit(ecode); 163 return ecode; 164 } 165 166 /** 167 @brief Set error handler 168 169 A default error handler is set in CeedInit(). Use this function to change 170 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 171 error handler. 172 173 @ref Developer 174 **/ 175 int CeedSetErrorHandler(Ceed ceed, 176 int (eh)(Ceed, const char *, int, const char *, 177 int, const char *, va_list)) { 178 ceed->Error = eh; 179 return 0; 180 } 181 182 /** 183 @brief Register a Ceed backend 184 185 @param prefix Prefix of resources for this backend to respond to. For 186 example, the reference backend responds to "/cpu/self". 187 @param init Initialization function called by CeedInit() when the backend 188 is selected to drive the requested resource. 189 @param priority Integer priority. Lower values are preferred in case the 190 resource requested by CeedInit() has non-unique best prefix 191 match. 192 193 @return An error code: 0 - success, otherwise - failure 194 195 @ref Advanced 196 **/ 197 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 198 unsigned int priority) { 199 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 200 // LCOV_EXCL_START 201 return CeedError(NULL, 1, "Too many backends"); 202 // LCOV_EXCL_STOP 203 204 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 205 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 206 backends[num_backends].init = init; 207 backends[num_backends].priority = priority; 208 num_backends++; 209 return 0; 210 } 211 212 /** 213 @brief Allocate an array on the host; use CeedMalloc() 214 215 Memory usage can be tracked by the library. This ensures sufficient 216 alignment for vectorization and should be used for large allocations. 217 218 @param n Number of units to allocate 219 @param unit Size of each unit 220 @param p Address of pointer to hold the result. 221 222 @return An error code: 0 - success, otherwise - failure 223 224 @sa CeedFree() 225 226 @ref Advanced 227 **/ 228 int CeedMallocArray(size_t n, size_t unit, void *p) { 229 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 230 if (ierr) 231 // LCOV_EXCL_START 232 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 233 "members of size %zd\n", n, unit); 234 // LCOV_EXCL_STOP 235 236 return 0; 237 } 238 239 /** 240 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 241 242 Memory usage can be tracked by the library. 243 244 @param n Number of units to allocate 245 @param unit Size of each unit 246 @param p Address of pointer to hold the result. 247 248 @return An error code: 0 - success, otherwise - failure 249 250 @sa CeedFree() 251 252 @ref Advanced 253 **/ 254 int CeedCallocArray(size_t n, size_t unit, void *p) { 255 *(void **)p = calloc(n, unit); 256 if (n && unit && !*(void **)p) 257 // LCOV_EXCL_START 258 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 259 "%zd\n", n, unit); 260 // LCOV_EXCL_STOP 261 262 return 0; 263 } 264 265 /** 266 @brief Reallocate an array on the host; use CeedRealloc() 267 268 Memory usage can be tracked by the library. 269 270 @param n Number of units to allocate 271 @param unit Size of each unit 272 @param p Address of pointer to hold the result. 273 274 @return An error code: 0 - success, otherwise - failure 275 276 @sa CeedFree() 277 278 @ref Advanced 279 **/ 280 int CeedReallocArray(size_t n, size_t unit, void *p) { 281 *(void **)p = realloc(*(void **)p, n*unit); 282 if (n && unit && !*(void **)p) 283 // LCOV_EXCL_START 284 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 285 "%zd\n", n, unit); 286 // LCOV_EXCL_STOP 287 288 return 0; 289 } 290 291 /** Free memory allocated using CeedMalloc() or CeedCalloc() 292 293 @param p address of pointer to memory. This argument is of type void* to 294 avoid needing a cast, but is the address of the pointer (which is 295 zeroed) rather than the pointer. 296 **/ 297 int CeedFree(void *p) { 298 free(*(void **)p); 299 *(void **)p = NULL; 300 return 0; 301 } 302 303 /** 304 @brief Wait for a CeedRequest to complete. 305 306 Calling CeedRequestWait on a NULL request is a no-op. 307 308 @param req Address of CeedRequest to wait for; zeroed on completion. 309 310 @return An error code: 0 - success, otherwise - failure 311 312 @ref Advanced 313 **/ 314 int CeedRequestWait(CeedRequest *req) { 315 if (!*req) 316 return 0; 317 return CeedError(NULL, 2, "CeedRequestWait not implemented"); 318 } 319 320 /** 321 @brief Initialize a \ref Ceed context to use the specified resource. 322 323 @param resource Resource to use, e.g., "/cpu/self" 324 @param ceed The library context 325 @sa CeedRegister() CeedDestroy() 326 327 @return An error code: 0 - success, otherwise - failure 328 329 @ref Basic 330 **/ 331 int CeedInit(const char *resource, Ceed *ceed) { 332 int ierr; 333 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 334 335 // Find matching backend 336 if (!resource) 337 return CeedError(NULL, 1, "No resource provided"); 338 for (size_t i=0; i<num_backends; i++) { 339 size_t n; 340 const char *prefix = backends[i].prefix; 341 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 342 priority = backends[i].priority; 343 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 344 matchlen = n; 345 matchpriority = priority; 346 matchidx = i; 347 } 348 } 349 if (!matchlen) 350 return CeedError(NULL, 1, "No suitable backend"); 351 352 // Setup Ceed 353 ierr = CeedCalloc(1,ceed); CeedChk(ierr); 354 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 355 if (!ceed_error_handler) 356 ceed_error_handler = "abort"; 357 if (!strcmp(ceed_error_handler, "exit")) 358 (*ceed)->Error = CeedErrorExit; 359 else 360 (*ceed)->Error = CeedErrorAbort; 361 (*ceed)->refcount = 1; 362 (*ceed)->data = NULL; 363 364 // Set lookup table 365 foffset foffsets[] = { 366 CEED_FTABLE_ENTRY(Ceed, Error), 367 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 368 CEED_FTABLE_ENTRY(Ceed, Destroy), 369 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 370 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 371 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 372 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 373 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 374 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 375 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 376 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 377 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 378 CEED_FTABLE_ENTRY(CeedVector, SetArray), 379 CEED_FTABLE_ENTRY(CeedVector, SetValue), 380 CEED_FTABLE_ENTRY(CeedVector, GetArray), 381 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 382 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 383 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 384 CEED_FTABLE_ENTRY(CeedVector, Destroy), 385 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 386 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 387 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 388 CEED_FTABLE_ENTRY(CeedBasis, Apply), 389 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 390 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 391 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 392 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 393 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 394 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 395 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 396 CEED_FTABLE_ENTRY(CeedOperator, Apply), 397 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 398 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 399 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 400 }; 401 402 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 403 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 404 405 // Set fallback for advanced CeedOperator functions 406 const char fallbackresource[] = "/cpu/self/ref/serial"; 407 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 408 CeedChk(ierr); 409 410 // Backend specific setup 411 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 412 413 // Copy resource prefix, if backend setup sucessful 414 size_t len = strlen(backends[matchidx].prefix); 415 char *tmp; 416 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 417 memcpy(tmp, backends[matchidx].prefix, len+1); 418 (*ceed)->resource = tmp; 419 420 return 0; 421 } 422 423 /** 424 @brief Retrieve a parent Ceed context 425 426 @param ceed Ceed context to retrieve parent of 427 @param[out] parent Address to save the parent to 428 429 @return An error code: 0 - success, otherwise - failure 430 431 @ref Developer 432 **/ 433 int CeedGetParent(Ceed ceed, Ceed *parent) { 434 int ierr; 435 if (ceed->parent) { 436 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 437 return 0; 438 } 439 *parent = ceed; 440 return 0; 441 } 442 443 /** 444 @brief Retrieve a delegate Ceed context 445 446 @param ceed Ceed context to retrieve delegate of 447 @param[out] delegate Address to save the delegate to 448 449 @return An error code: 0 - success, otherwise - failure 450 451 @ref Developer 452 **/ 453 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 454 *delegate = ceed->delegate; 455 return 0; 456 } 457 458 /** 459 @brief Set a delegate Ceed context 460 461 This function allows a Ceed context to set a delegate Ceed context. All 462 backend implementations default to the delegate Ceed context, unless 463 overridden. 464 465 @param ceed Ceed context to set delegate of 466 @param[out] delegate Address to set the delegate to 467 468 @return An error code: 0 - success, otherwise - failure 469 470 @ref Advanced 471 **/ 472 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 473 ceed->delegate = delegate; 474 delegate->parent = ceed; 475 return 0; 476 } 477 478 /** 479 @brief Retrieve a delegate Ceed context for a specific object type 480 481 @param ceed Ceed context to retrieve delegate of 482 @param[out] delegate Address to save the delegate to 483 @param[in] objname Name of the object type to retrieve delegate for 484 485 @return An error code: 0 - success, otherwise - failure 486 487 @ref Developer 488 **/ 489 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 490 CeedInt ierr; 491 492 // Check for object delegate 493 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 494 if (!strcmp(objname, ceed->objdelegates->objname)) { 495 *delegate = ceed->objdelegates->delegate; 496 return 0; 497 } 498 499 // Use default delegate if no object delegate 500 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 501 502 return 0; 503 } 504 505 /** 506 @brief Set a delegate Ceed context for a specific object type 507 508 This function allows a Ceed context to set a delegate Ceed context for a 509 given type of Ceed object. All backend implementations default to the 510 delegate Ceed context for this object. For example, 511 CeedSetObjectDelegate(ceed, refceed, "Basis") 512 uses refceed implementations for all CeedBasis backend functions. 513 514 @param ceed Ceed context to set delegate of 515 @param[out] delegate Address to set the delegate to 516 @param[in] objname Name of the object type to set delegate for 517 518 @return An error code: 0 - success, otherwise - failure 519 520 @ref Advanced 521 **/ 522 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 523 CeedInt ierr; 524 CeedInt count = ceed->objdelegatecount; 525 526 // Malloc or Realloc 527 if (count) { 528 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 529 } else { 530 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 531 } 532 ceed->objdelegatecount++; 533 534 // Set object delegate 535 ceed->objdelegates[count].delegate = delegate; 536 size_t slen = strlen(objname) + 1; 537 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 538 memcpy(ceed->objdelegates[count].objname, objname, slen); 539 540 // Set delegate parent 541 delegate->parent = ceed; 542 543 return 0; 544 } 545 546 /** 547 @brief Set the fallback resource for CeedOperators. The current resource, if 548 any, is freed by calling this function. This string is freed upon the 549 destruction of the Ceed context. 550 551 @param[out] ceed Ceed context 552 @param resource Fallback resource to set 553 554 @return An error code: 0 - success, otherwise - failure 555 556 @ref Advanced 557 **/ 558 559 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 560 int ierr; 561 562 // Free old 563 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 564 565 // Set new 566 size_t len = strlen(resource); 567 char *tmp; 568 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 569 memcpy(tmp, resource, len+1); 570 ceed->opfallbackresource = tmp; 571 572 return 0; 573 } 574 575 /** 576 @brief Get the fallback resource for CeedOperators 577 578 @param ceed Ceed context 579 @param[out] resource Variable to store fallback resource 580 581 @return An error code: 0 - success, otherwise - failure 582 583 @ref Advanced 584 **/ 585 586 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 587 *resource = (const char *)ceed->opfallbackresource; 588 return 0; 589 } 590 591 /** 592 @brief Get the parent Ceed context associated with a fallback Ceed context 593 for a CeedOperator 594 595 @param ceed Ceed context 596 @param[out] ceed Variable to store parent Ceed context 597 598 @return An error code: 0 - success, otherwise - failure 599 600 @ref Advanced 601 **/ 602 603 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 604 *parent = ceed->opfallbackparent; 605 return 0; 606 } 607 608 /** 609 @brief Return Ceed context preferred memory type 610 611 @param ceed Ceed context to get preferred memory type of 612 @param[out] type Address to save preferred memory type to 613 614 @return An error code: 0 - success, otherwise - failure 615 616 @ref Basic 617 **/ 618 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 619 int ierr; 620 621 if (ceed->GetPreferredMemType) { 622 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 623 } else { 624 Ceed delegate; 625 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 626 627 if (delegate) { 628 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 629 } else { 630 *type = CEED_MEM_HOST; 631 } 632 } 633 634 return 0; 635 } 636 637 /** 638 @brief Set a backend function 639 640 This function is used for a backend to set the function associated with 641 the Ceed objects. For example, 642 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 643 sets the backend implementation of 'CeedVectorCreate' and 644 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 645 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 646 is not required for the object type ("Basis" vs "CeedBasis"). 647 648 @param ceed Ceed context for error handling 649 @param type Type of Ceed object to set function for 650 @param[out] object Ceed object to set function for 651 @param fname Name of function to set 652 @param f Function to set 653 654 @return An error code: 0 - success, otherwise - failure 655 656 @ref Advanced 657 **/ 658 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 659 const char *fname, int (*f)()) { 660 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 661 662 // Build lookup name 663 if (strcmp(type, "Ceed")) 664 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 665 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 666 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 667 668 // Find and use offset 669 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 670 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 671 size_t offset = ceed->foffsets[i].offset; 672 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 673 *fpointer = f; 674 return 0; 675 } 676 677 // LCOV_EXCL_START 678 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 679 "object '%s'", fname, type); 680 // LCOV_EXCL_STOP 681 } 682 683 /** 684 @brief Retrieve backend data for a Ceed context 685 686 @param ceed Ceed context to retrieve data of 687 @param[out] data Address to save data to 688 689 @return An error code: 0 - success, otherwise - failure 690 691 @ref Advanced 692 **/ 693 int CeedGetData(Ceed ceed, void **data) { 694 *data = ceed->data; 695 return 0; 696 } 697 698 /** 699 @brief Set backend data for a Ceed context 700 701 @param ceed Ceed context to set data of 702 @param data Address of data to set 703 704 @return An error code: 0 - success, otherwise - failure 705 706 @ref Advanced 707 **/ 708 int CeedSetData(Ceed ceed, void **data) { 709 ceed->data = *data; 710 return 0; 711 } 712 713 /** 714 @brief Get the full resource name for a Ceed context 715 716 @param ceed Ceed context to get resource name of 717 @param[out] resource Variable to store resource name 718 719 @return An error code: 0 - success, otherwise - failure 720 721 @ref Basic 722 **/ 723 724 int CeedGetResource(Ceed ceed, const char **resource) { 725 *resource = (const char *)ceed->resource; 726 return 0; 727 } 728 729 /** 730 @brief Destroy a Ceed context 731 732 @param ceed Address of Ceed context to destroy 733 734 @return An error code: 0 - success, otherwise - failure 735 736 @ref Basic 737 **/ 738 int CeedDestroy(Ceed *ceed) { 739 int ierr; 740 741 if (!*ceed || --(*ceed)->refcount > 0) 742 return 0; 743 if ((*ceed)->delegate) { 744 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 745 } 746 if ((*ceed)->objdelegatecount > 0) { 747 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 748 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 749 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 750 } 751 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 752 } 753 if ((*ceed)->Destroy) { 754 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 755 } 756 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 757 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 758 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 759 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 760 ierr = CeedFree(ceed); CeedChk(ierr); 761 return 0; 762 } 763 764 /// @} 765