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