1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #define _POSIX_C_SOURCE 200112 9 #include <ceed-impl.h> 10 #include <ceed.h> 11 #include <ceed/backend.h> 12 #include <limits.h> 13 #include <stdarg.h> 14 #include <stdbool.h> 15 #include <stddef.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 /// @cond DOXYGEN_SKIP 21 static CeedRequest ceed_request_immediate; 22 static CeedRequest ceed_request_ordered; 23 24 static struct { 25 char prefix[CEED_MAX_RESOURCE_LEN]; 26 int (*init)(const char *resource, Ceed f); 27 unsigned int priority; 28 } backends[32]; 29 static size_t num_backends; 30 31 #define CEED_FTABLE_ENTRY(class, method) \ 32 { \ 33 #class #method, offsetof(struct class##_private, method) \ 34 } 35 /// @endcond 36 37 /// @file 38 /// Implementation of core components of Ceed library 39 40 /// @addtogroup CeedUser 41 /// @{ 42 43 /** 44 @brief Request immediate completion 45 46 This predefined constant is passed as the \ref CeedRequest argument to interfaces when the caller wishes for the operation to be performed 47 immediately. The code 48 49 @code 50 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 51 @endcode 52 53 is semantically equivalent to 54 55 @code 56 CeedRequest request; 57 CeedOperatorApply(op, ..., &request); 58 CeedRequestWait(&request); 59 @endcode 60 61 @sa CEED_REQUEST_ORDERED 62 **/ 63 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 64 65 /** 66 @brief Request ordered completion 67 68 This predefined constant is passed as the \ref CeedRequest argument to interfaces when the caller wishes for the operation to be completed in the 69 order that it is submitted to the device. It is typically used in a construct such as: 70 71 @code 72 CeedRequest request; 73 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 74 CeedOperatorApply(op2, ..., &request); 75 // other optional work 76 CeedRequestWait(&request); 77 @endcode 78 79 which allows the sequence to complete asynchronously but does not start `op2` until `op1` has completed. 80 81 @todo The current implementation is overly strict, offering equivalent semantics to @ref CEED_REQUEST_IMMEDIATE. 82 83 @sa CEED_REQUEST_IMMEDIATE 84 */ 85 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 86 87 /** 88 @brief Wait for a CeedRequest to complete. 89 90 Calling CeedRequestWait on a NULL request is a no-op. 91 92 @param req Address of CeedRequest to wait for; zeroed on completion. 93 94 @return An error code: 0 - success, otherwise - failure 95 96 @ref User 97 **/ 98 int CeedRequestWait(CeedRequest *req) { 99 if (!*req) return CEED_ERROR_SUCCESS; 100 return CeedError(NULL, CEED_ERROR_UNSUPPORTED, "CeedRequestWait not implemented"); 101 } 102 103 /// @} 104 105 /// ---------------------------------------------------------------------------- 106 /// Ceed Library Internal Functions 107 /// ---------------------------------------------------------------------------- 108 /// @addtogroup CeedDeveloper 109 /// @{ 110 111 /** 112 @brief Register a Ceed backend internally. 113 114 Note: Backends should call `CeedRegister` instead. 115 116 @param[in] prefix Prefix of resources for this backend to respond to. 117 For example, the reference backend responds to "/cpu/self". 118 @param[in] init Initialization function called by CeedInit() when the backend is selected to drive the requested resource. 119 @param[in] priority Integer priority. 120 Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match. 121 122 @return An error code: 0 - success, otherwise - failure 123 124 @ref Developer 125 **/ 126 int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) { 127 CeedCheck(num_backends < sizeof(backends) / sizeof(backends[0]), NULL, CEED_ERROR_MAJOR, "Too many backends"); 128 129 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 130 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN - 1] = 0; 131 backends[num_backends].init = init; 132 backends[num_backends].priority = priority; 133 num_backends++; 134 return CEED_ERROR_SUCCESS; 135 } 136 137 /// @} 138 139 /// ---------------------------------------------------------------------------- 140 /// Ceed Backend API 141 /// ---------------------------------------------------------------------------- 142 /// @addtogroup CeedBackend 143 /// @{ 144 145 /** 146 @brief Return value of CEED_DEBUG environment variable 147 148 @param[in] ceed Ceed context 149 150 @return boolean value: true - debugging mode enabled 151 false - debugging mode disabled 152 153 @ref Backend 154 **/ 155 // LCOV_EXCL_START 156 bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; } 157 // LCOV_EXCL_STOP 158 159 /** 160 @brief Return value of CEED_DEBUG environment variable 161 162 @return boolean value: true - debugging mode enabled 163 false - debugging mode disabled 164 165 @ref Backend 166 **/ 167 // LCOV_EXCL_START 168 bool CeedDebugFlagEnv(void) { return !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG"); } 169 // LCOV_EXCL_STOP 170 171 /** 172 @brief Print debugging information in color 173 174 @param color Color to print 175 @param format Printing format 176 177 @ref Backend 178 **/ 179 // LCOV_EXCL_START 180 void CeedDebugImpl256(const unsigned char color, const char *format, ...) { 181 va_list args; 182 va_start(args, format); 183 fflush(stdout); 184 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color); 185 vfprintf(stdout, format, args); 186 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m"); 187 fprintf(stdout, "\n"); 188 fflush(stdout); 189 va_end(args); 190 } 191 // LCOV_EXCL_STOP 192 193 /** 194 @brief Allocate an array on the host; use CeedMalloc() 195 196 Memory usage can be tracked by the library. 197 This ensures sufficient alignment for vectorization and should be used for large allocations. 198 199 @param[in] n Number of units to allocate 200 @param[in] unit Size of each unit 201 @param[out] p Address of pointer to hold the result. 202 203 @return An error code: 0 - success, otherwise - failure 204 205 @sa CeedFree() 206 207 @ref Backend 208 **/ 209 int CeedMallocArray(size_t n, size_t unit, void *p) { 210 int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit); 211 CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit); 212 return CEED_ERROR_SUCCESS; 213 } 214 215 /** 216 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 217 218 Memory usage can be tracked by the library. 219 220 @param[in] n Number of units to allocate 221 @param[in] unit Size of each unit 222 @param[out] p Address of pointer to hold the result. 223 224 @return An error code: 0 - success, otherwise - failure 225 226 @sa CeedFree() 227 228 @ref Backend 229 **/ 230 int CeedCallocArray(size_t n, size_t unit, void *p) { 231 *(void **)p = calloc(n, unit); 232 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit); 233 return CEED_ERROR_SUCCESS; 234 } 235 236 /** 237 @brief Reallocate an array on the host; use CeedRealloc() 238 239 Memory usage can be tracked by the library. 240 241 @param[in] n Number of units to allocate 242 @param[in] unit Size of each unit 243 @param[out] p Address of pointer to hold the result. 244 245 @return An error code: 0 - success, otherwise - failure 246 247 @sa CeedFree() 248 249 @ref Backend 250 **/ 251 int CeedReallocArray(size_t n, size_t unit, void *p) { 252 *(void **)p = realloc(*(void **)p, n * unit); 253 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit); 254 return CEED_ERROR_SUCCESS; 255 } 256 257 /** 258 @brief Allocate a cleared string buffer on the host 259 260 Memory usage can be tracked by the library. 261 262 @param[in] source Pointer to string to be copied 263 @param[out] copy Pointer to variable to hold newly allocated string copy 264 265 @return An error code: 0 - success, otherwise - failure 266 267 @sa CeedFree() 268 269 @ref Backend 270 **/ 271 int CeedStringAllocCopy(const char *source, char **copy) { 272 size_t len = strlen(source); 273 CeedCall(CeedCalloc(len + 1, copy)); 274 memcpy(*copy, source, len); 275 return CEED_ERROR_SUCCESS; 276 } 277 278 /** Free memory allocated using CeedMalloc() or CeedCalloc() 279 280 @param[in,out] p address of pointer to memory. 281 This argument is of type void* to avoid needing a cast, but is the address of the pointer (which is zeroed) rather than the 282 pointer. 283 **/ 284 int CeedFree(void *p) { 285 free(*(void **)p); 286 *(void **)p = NULL; 287 return CEED_ERROR_SUCCESS; 288 } 289 290 /** 291 @brief Register a Ceed backend 292 293 @param[in] prefix Prefix of resources for this backend to respond to. 294 For example, the reference backend responds to "/cpu/self". 295 @param[in] init Initialization function called by CeedInit() when the backend is selected to drive the requested resource. 296 @param[in] priority Integer priority. 297 Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match. 298 299 @return An error code: 0 - success, otherwise - failure 300 301 @ref Backend 302 **/ 303 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) { 304 CeedDebugEnv("Backend Register: %s", prefix); 305 CeedRegisterImpl(prefix, init, priority); 306 return CEED_ERROR_SUCCESS; 307 } 308 309 /** 310 @brief Return debugging status flag 311 312 @param[in] ceed Ceed context to get debugging flag 313 @param[out] is_debug Variable to store debugging flag 314 315 @return An error code: 0 - success, otherwise - failure 316 317 @ref Backend 318 **/ 319 int CeedIsDebug(Ceed ceed, bool *is_debug) { 320 *is_debug = ceed->is_debug; 321 return CEED_ERROR_SUCCESS; 322 } 323 324 /** 325 @brief Get the root of the requested resource 326 327 @param[in] ceed Ceed context to get resource name of 328 @param[in] resource ull user specified resource 329 @param[in] delineator Delinator to break resource_root and resource_spec 330 @param[out] resource_root Variable to store resource root 331 332 @return An error code: 0 - success, otherwise - failure 333 334 @ref Backend 335 **/ 336 int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) { 337 char *device_spec = strstr(resource, delineator); 338 size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1; 339 CeedCall(CeedCalloc(resource_root_len, resource_root)); 340 memcpy(*resource_root, resource, resource_root_len - 1); 341 342 return CEED_ERROR_SUCCESS; 343 } 344 345 /** 346 @brief Retrieve a parent Ceed context 347 348 @param[in] ceed Ceed context to retrieve parent of 349 @param[out] parent Address to save the parent to 350 351 @return An error code: 0 - success, otherwise - failure 352 353 @ref Backend 354 **/ 355 int CeedGetParent(Ceed ceed, Ceed *parent) { 356 if (ceed->parent) { 357 CeedCall(CeedGetParent(ceed->parent, parent)); 358 return CEED_ERROR_SUCCESS; 359 } 360 *parent = ceed; 361 return CEED_ERROR_SUCCESS; 362 } 363 364 /** 365 @brief Retrieve a delegate Ceed context 366 367 @param[in] ceed Ceed context to retrieve delegate of 368 @param[out] delegate Address to save the delegate to 369 370 @return An error code: 0 - success, otherwise - failure 371 372 @ref Backend 373 **/ 374 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 375 *delegate = ceed->delegate; 376 return CEED_ERROR_SUCCESS; 377 } 378 379 /** 380 @brief Set a delegate Ceed context 381 382 This function allows a Ceed context to set a delegate Ceed context. 383 All backend implementations default to the delegate Ceed context, unless overridden. 384 385 @param[in] ceed Ceed context to set delegate of 386 @param[out] delegate Address to set the delegate to 387 388 @return An error code: 0 - success, otherwise - failure 389 390 @ref Backend 391 **/ 392 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 393 ceed->delegate = delegate; 394 delegate->parent = ceed; 395 return CEED_ERROR_SUCCESS; 396 } 397 398 /** 399 @brief Retrieve a delegate Ceed context for a specific object type 400 401 @param[in] ceed Ceed context to retrieve delegate of 402 @param[out] delegate Address to save the delegate to 403 @param[in] obj_name Name of the object type to retrieve delegate for 404 405 @return An error code: 0 - success, otherwise - failure 406 407 @ref Backend 408 **/ 409 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) { 410 // Check for object delegate 411 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) { 412 if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) { 413 *delegate = ceed->obj_delegates->delegate; 414 return CEED_ERROR_SUCCESS; 415 } 416 } 417 418 // Use default delegate if no object delegate 419 CeedCall(CeedGetDelegate(ceed, delegate)); 420 return CEED_ERROR_SUCCESS; 421 } 422 423 /** 424 @brief Set a delegate Ceed context for a specific object type 425 426 This function allows a Ceed context to set a delegate Ceed context for a given type of Ceed object. 427 All backend implementations default to the delegate Ceed context for this object. 428 For example, CeedSetObjectDelegate(ceed, refceed, "Basis") uses refceed implementations for all CeedBasis backend functions. 429 430 @param[in,out] ceed Ceed context to set delegate of 431 @param[out] delegate Address to set the delegate to 432 @param[in] obj_name Name of the object type to set delegate for 433 434 @return An error code: 0 - success, otherwise - failure 435 436 @ref Backend 437 **/ 438 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) { 439 CeedInt count = ceed->obj_delegate_count; 440 441 // Malloc or Realloc 442 if (count) { 443 CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates)); 444 } else { 445 CeedCall(CeedCalloc(1, &ceed->obj_delegates)); 446 } 447 ceed->obj_delegate_count++; 448 449 // Set object delegate 450 ceed->obj_delegates[count].delegate = delegate; 451 CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name)); 452 453 // Set delegate parent 454 delegate->parent = ceed; 455 return CEED_ERROR_SUCCESS; 456 } 457 458 /** 459 @brief Get the fallback resource for CeedOperators 460 461 @param[in] ceed Ceed context 462 @param[out] resource Variable to store fallback resource 463 464 @return An error code: 0 - success, otherwise - failure 465 466 @ref Backend 467 **/ 468 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 469 *resource = (const char *)ceed->op_fallback_resource; 470 return CEED_ERROR_SUCCESS; 471 } 472 473 /** 474 @brief Get the fallback Ceed for CeedOperators 475 476 @param[in] ceed Ceed context 477 @param[out] fallback_ceed Variable to store fallback Ceed 478 479 @return An error code: 0 - success, otherwise - failure 480 481 @ref Backend 482 **/ 483 int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) { 484 if (ceed->has_valid_op_fallback_resource) { 485 CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- CeedOperator Fallback ----------\n"); 486 CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource); 487 } 488 489 // Create fallback Ceed if uninitalized 490 if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) { 491 CeedDebug(ceed, "Creating fallback Ceed"); 492 493 Ceed fallback_ceed; 494 const char *fallback_resource; 495 496 CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource)); 497 CeedCall(CeedInit(fallback_resource, &fallback_ceed)); 498 fallback_ceed->op_fallback_parent = ceed; 499 fallback_ceed->Error = ceed->Error; 500 ceed->op_fallback_ceed = fallback_ceed; 501 } 502 *fallback_ceed = ceed->op_fallback_ceed; 503 504 return CEED_ERROR_SUCCESS; 505 } 506 507 /** 508 @brief Set the fallback resource for CeedOperators. 509 510 The current resource, if any, is freed by calling this function. 511 This string is freed upon the destruction of the Ceed context. 512 513 @param[in,out] ceed Ceed context 514 @param[in] resource Fallback resource to set 515 516 @return An error code: 0 - success, otherwise - failure 517 518 @ref Backend 519 **/ 520 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 521 // Free old 522 CeedCall(CeedFree(&ceed->op_fallback_resource)); 523 524 // Set new 525 CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource)); 526 527 // Check validity 528 ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource); 529 530 return CEED_ERROR_SUCCESS; 531 } 532 533 /** 534 @brief Get the parent Ceed context associated with a fallback Ceed context for a CeedOperator 535 536 @param[in] ceed Ceed context 537 @param[out] parent Variable to store parent Ceed context 538 539 @return An error code: 0 - success, otherwise - failure 540 541 @ref Backend 542 **/ 543 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 544 *parent = ceed->op_fallback_parent; 545 return CEED_ERROR_SUCCESS; 546 } 547 548 /** 549 @brief Flag Ceed context as deterministic 550 551 @param[in] ceed Ceed to flag as deterministic 552 @param[out] is_deterministic Deterministic status to set 553 554 @return An error code: 0 - success, otherwise - failure 555 556 @ref Backend 557 **/ 558 int CeedSetDeterministic(Ceed ceed, bool is_deterministic) { 559 ceed->is_deterministic = is_deterministic; 560 return CEED_ERROR_SUCCESS; 561 } 562 563 /** 564 @brief Set a backend function 565 566 This function is used for a backend to set the function associated with the Ceed objects. 567 For example, CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) sets the backend implementation of 'CeedVectorCreate' 568 and CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) sets the backend implementation of 'CeedBasisApply'. 569 Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis"). 570 571 @param[in] ceed Ceed context for error handling 572 @param[in] type Type of Ceed object to set function for 573 @param[out] object Ceed object to set function for 574 @param[in] func_name Name of function to set 575 @param[in] f Function to set 576 577 @return An error code: 0 - success, otherwise - failure 578 579 @ref Backend 580 **/ 581 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, const char *func_name, int (*f)()) { 582 char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = ""; 583 584 // Build lookup name 585 if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN); 586 strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN); 587 strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN); 588 589 // Find and use offset 590 for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) { 591 if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) { 592 size_t offset = ceed->f_offsets[i].offset; 593 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 594 *fpointer = f; 595 return CEED_ERROR_SUCCESS; 596 } 597 } 598 599 // LCOV_EXCL_START 600 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type); 601 // LCOV_EXCL_STOP 602 } 603 604 /** 605 @brief Retrieve backend data for a Ceed context 606 607 @param[in] ceed Ceed context to retrieve data of 608 @param[out] data Address to save data to 609 610 @return An error code: 0 - success, otherwise - failure 611 612 @ref Backend 613 **/ 614 int CeedGetData(Ceed ceed, void *data) { 615 *(void **)data = ceed->data; 616 return CEED_ERROR_SUCCESS; 617 } 618 619 /** 620 @brief Set backend data for a Ceed context 621 622 @param[in,out] ceed Ceed context to set data of 623 @param[in] data Address of data to set 624 625 @return An error code: 0 - success, otherwise - failure 626 627 @ref Backend 628 **/ 629 int CeedSetData(Ceed ceed, void *data) { 630 ceed->data = data; 631 return CEED_ERROR_SUCCESS; 632 } 633 634 /** 635 @brief Increment the reference counter for a Ceed context 636 637 @param[in,out] ceed Ceed context to increment the reference counter 638 639 @return An error code: 0 - success, otherwise - failure 640 641 @ref Backend 642 **/ 643 int CeedReference(Ceed ceed) { 644 ceed->ref_count++; 645 return CEED_ERROR_SUCCESS; 646 } 647 648 /// @} 649 650 /// ---------------------------------------------------------------------------- 651 /// Ceed Public API 652 /// ---------------------------------------------------------------------------- 653 /// @addtogroup CeedUser 654 /// @{ 655 656 /** 657 @brief Get the list of available resource names for Ceed contexts 658 659 Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources 660 array. 661 662 @param[out] n Number of available resources 663 @param[out] resources List of available resource names 664 @param[out] priorities Resource name prioritization values, lower is better 665 666 @return An error code: 0 - success, otherwise - failure 667 668 @ref User 669 **/ 670 // LCOV_EXCL_START 671 int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) { 672 *n = 0; 673 *resources = malloc(num_backends * sizeof(**resources)); 674 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 675 if (priorities) { 676 *priorities = malloc(num_backends * sizeof(**priorities)); 677 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 678 } 679 for (size_t i = 0; i < num_backends; i++) { 680 // Only report compiled backends 681 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) { 682 *resources[i] = backends[i].prefix; 683 if (priorities) *priorities[i] = backends[i].priority; 684 *n += 1; 685 } 686 } 687 CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed"); 688 *resources = realloc(*resources, *n * sizeof(**resources)); 689 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 690 if (priorities) { 691 *priorities = realloc(*priorities, *n * sizeof(**priorities)); 692 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 693 } 694 return CEED_ERROR_SUCCESS; 695 } 696 // LCOV_EXCL_STOP 697 698 /** 699 @brief Initialize a \ref Ceed context to use the specified resource. 700 701 Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") will result in CeedInt printing the current libCEED version number and a 702 list of current available backend resources to stderr. 703 704 @param[in] resource Resource to use, e.g., "/cpu/self" 705 @param[out] ceed The library context 706 @sa CeedRegister() CeedDestroy() 707 708 @return An error code: 0 - success, otherwise - failure 709 710 @ref User 711 **/ 712 int CeedInit(const char *resource, Ceed *ceed) { 713 size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority; 714 715 // Find matching backend 716 CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided"); 717 CeedCall(CeedRegisterAll()); 718 719 // Check for help request 720 const char *help_prefix = "help"; 721 size_t match_help = 0; 722 while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++; 723 if (match_help == 4) { 724 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH, 725 CEED_VERSION_RELEASE ? "" : "+development"); 726 fprintf(stderr, "Available backend resources:\n"); 727 for (size_t i = 0; i < num_backends; i++) { 728 // Only report compiled backends 729 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, " %s\n", backends[i].prefix); 730 } 731 fflush(stderr); 732 match_help = 5; // Delineating character expected 733 } else { 734 match_help = 0; 735 } 736 737 // Find best match, computed as number of matching characters from requested resource stem 738 size_t stem_length = 0; 739 while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++; 740 for (size_t i = 0; i < num_backends; i++) { 741 size_t n = 0; 742 const char *prefix = backends[i].prefix; 743 while (prefix[n] && prefix[n] == resource[n + match_help]) n++; 744 priority = backends[i].priority; 745 if (n > match_len || (n == match_len && match_priority > priority)) { 746 match_len = n; 747 match_priority = priority; 748 match_index = i; 749 } 750 } 751 // Using Levenshtein distance to find closest match 752 if (match_len <= 1 || match_len != stem_length) { 753 // LCOV_EXCL_START 754 size_t lev_dis = UINT_MAX; 755 size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY; 756 for (size_t i = 0; i < num_backends; i++) { 757 const char *prefix = backends[i].prefix; 758 size_t prefix_length = strlen(backends[i].prefix); 759 size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length; 760 size_t column[min_len + 1]; 761 for (size_t j = 0; j <= min_len; j++) column[j] = j; 762 for (size_t j = 1; j <= min_len; j++) { 763 column[0] = j; 764 for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) { 765 size_t old_diag = column[k]; 766 size_t min_1 = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1; 767 size_t min_2 = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1); 768 column[k] = (min_1 < min_2) ? min_1 : min_2; 769 last_diag = old_diag; 770 } 771 } 772 size_t n = column[min_len]; 773 priority = backends[i].priority; 774 if (n < lev_dis || (n == lev_dis && lev_priority > priority)) { 775 lev_dis = n; 776 lev_priority = priority; 777 lev_index = i; 778 } 779 } 780 const char *prefix_lev = backends[lev_index].prefix; 781 size_t lev_length = 0; 782 while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++; 783 size_t m = (lev_length < stem_length) ? lev_length : stem_length; 784 if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource); 785 else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix); 786 // LCOV_EXCL_STOP 787 } 788 789 // Setup Ceed 790 CeedCall(CeedCalloc(1, ceed)); 791 CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots)); 792 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 793 if (!ceed_error_handler) ceed_error_handler = "abort"; 794 if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit; 795 else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore; 796 else (*ceed)->Error = CeedErrorAbort; 797 memcpy((*ceed)->err_msg, "No error message stored", 24); 798 (*ceed)->ref_count = 1; 799 (*ceed)->data = NULL; 800 801 // Set lookup table 802 FOffset f_offsets[] = { 803 CEED_FTABLE_ENTRY(Ceed, Error), 804 CEED_FTABLE_ENTRY(Ceed, SetStream), 805 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 806 CEED_FTABLE_ENTRY(Ceed, Destroy), 807 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 808 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 809 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 810 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 811 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 812 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 813 CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl), 814 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 815 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 816 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 817 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 818 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 819 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 820 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 821 CEED_FTABLE_ENTRY(CeedVector, SetArray), 822 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 823 CEED_FTABLE_ENTRY(CeedVector, SetValue), 824 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 825 CEED_FTABLE_ENTRY(CeedVector, GetArray), 826 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 827 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 828 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 829 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 830 CEED_FTABLE_ENTRY(CeedVector, Norm), 831 CEED_FTABLE_ENTRY(CeedVector, Scale), 832 CEED_FTABLE_ENTRY(CeedVector, AXPY), 833 CEED_FTABLE_ENTRY(CeedVector, AXPBY), 834 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 835 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 836 CEED_FTABLE_ENTRY(CeedVector, Destroy), 837 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 838 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned), 839 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented), 840 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 841 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 842 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations), 843 CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations), 844 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 845 CEED_FTABLE_ENTRY(CeedBasis, Apply), 846 CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints), 847 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 848 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 849 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 850 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 851 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 852 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 853 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 854 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 855 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 856 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 857 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 858 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 859 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 860 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 861 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 862 CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy), 863 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 864 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 865 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 866 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 867 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 868 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 869 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 870 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 871 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 872 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle), 873 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 874 CEED_FTABLE_ENTRY(CeedOperator, Apply), 875 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 876 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 877 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 878 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 879 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 880 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 881 }; 882 883 CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets)); 884 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 885 886 // Set fallback for advanced CeedOperator functions 887 const char fallbackresource[] = ""; 888 CeedCall(CeedSetOperatorFallbackResource(*ceed, fallbackresource)); 889 890 // Record env variables CEED_DEBUG or DBG 891 (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG"); 892 893 // Copy resource prefix, if backend setup successful 894 CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource)); 895 896 // Set default JiT source root 897 // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent 898 CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault)); 899 900 // Backend specific setup 901 CeedCall(backends[match_index].init(&resource[match_help], *ceed)); 902 903 return CEED_ERROR_SUCCESS; 904 } 905 906 /** 907 @brief Set the GPU stream for a Ceed context 908 909 @param[in,out] ceed Ceed context to set the stream 910 @param[in] handle Handle to GPU stream 911 912 @return An error code: 0 - success, otherwise - failure 913 914 @ref User 915 **/ 916 int CeedSetStream(Ceed ceed, void *handle) { 917 CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-null"); 918 if (ceed->SetStream) { 919 CeedCall(ceed->SetStream(ceed, handle)); 920 } else { 921 Ceed delegate; 922 CeedCall(CeedGetDelegate(ceed, &delegate)); 923 924 if (delegate) CeedCall(CeedSetStream(delegate, handle)); 925 else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream"); 926 } 927 return CEED_ERROR_SUCCESS; 928 } 929 930 /** 931 @brief Copy the pointer to a Ceed context. 932 933 Both pointers should be destroyed with `CeedDestroy()`. 934 935 Note: If the value of `ceed_copy` passed to this function is non-NULL, then it is assumed that `ceed_copy` is a pointer to a Ceed context. 936 This Ceed context will be destroyed if `ceed_copy` is the only reference to this Ceed context. 937 938 @param[in] ceed Ceed context to copy reference to 939 @param[in,out] ceed_copy Variable to store copied reference 940 941 @return An error code: 0 - success, otherwise - failure 942 943 @ref User 944 **/ 945 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 946 CeedCall(CeedReference(ceed)); 947 CeedCall(CeedDestroy(ceed_copy)); 948 *ceed_copy = ceed; 949 return CEED_ERROR_SUCCESS; 950 } 951 952 /** 953 @brief Get the full resource name for a Ceed context 954 955 @param[in] ceed Ceed context to get resource name of 956 @param[out] resource Variable to store resource name 957 958 @return An error code: 0 - success, otherwise - failure 959 960 @ref User 961 **/ 962 int CeedGetResource(Ceed ceed, const char **resource) { 963 *resource = (const char *)ceed->resource; 964 return CEED_ERROR_SUCCESS; 965 } 966 967 /** 968 @brief Return Ceed context preferred memory type 969 970 @param[in] ceed Ceed context to get preferred memory type of 971 @param[out] mem_type Address to save preferred memory type to 972 973 @return An error code: 0 - success, otherwise - failure 974 975 @ref User 976 **/ 977 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 978 if (ceed->GetPreferredMemType) { 979 CeedCall(ceed->GetPreferredMemType(mem_type)); 980 } else { 981 Ceed delegate; 982 CeedCall(CeedGetDelegate(ceed, &delegate)); 983 984 if (delegate) { 985 CeedCall(CeedGetPreferredMemType(delegate, mem_type)); 986 } else { 987 *mem_type = CEED_MEM_HOST; 988 } 989 } 990 return CEED_ERROR_SUCCESS; 991 } 992 993 /** 994 @brief Get deterministic status of Ceed 995 996 @param[in] ceed Ceed 997 @param[out] is_deterministic Variable to store deterministic status 998 999 @return An error code: 0 - success, otherwise - failure 1000 1001 @ref User 1002 **/ 1003 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 1004 *is_deterministic = ceed->is_deterministic; 1005 return CEED_ERROR_SUCCESS; 1006 } 1007 1008 /** 1009 @brief Set additional JiT source root for Ceed 1010 1011 @param[in,out] ceed Ceed 1012 @param[in] jit_source_root Absolute path to additional JiT source directory 1013 1014 @return An error code: 0 - success, otherwise - failure 1015 1016 @ref User 1017 **/ 1018 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1019 Ceed ceed_parent; 1020 1021 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1022 1023 CeedInt index = ceed_parent->num_jit_source_roots; 1024 size_t path_length = strlen(jit_source_root); 1025 CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots)); 1026 CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index])); 1027 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1028 ceed_parent->num_jit_source_roots++; 1029 1030 return CEED_ERROR_SUCCESS; 1031 } 1032 1033 /** 1034 @brief View a Ceed 1035 1036 @param[in] ceed Ceed to view 1037 @param[in] stream Filestream to write to 1038 1039 @return An error code: 0 - success, otherwise - failure 1040 1041 @ref User 1042 **/ 1043 int CeedView(Ceed ceed, FILE *stream) { 1044 CeedMemType mem_type; 1045 1046 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 1047 1048 fprintf(stream, 1049 "Ceed\n" 1050 " Ceed Resource: %s\n" 1051 " Preferred MemType: %s\n", 1052 ceed->resource, CeedMemTypes[mem_type]); 1053 return CEED_ERROR_SUCCESS; 1054 } 1055 1056 /** 1057 @brief Destroy a Ceed context 1058 1059 @param[in,out] ceed Address of Ceed context to destroy 1060 1061 @return An error code: 0 - success, otherwise - failure 1062 1063 @ref User 1064 **/ 1065 int CeedDestroy(Ceed *ceed) { 1066 if (!*ceed || --(*ceed)->ref_count > 0) { 1067 *ceed = NULL; 1068 return CEED_ERROR_SUCCESS; 1069 } 1070 if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate)); 1071 1072 if ((*ceed)->obj_delegate_count > 0) { 1073 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1074 CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate))); 1075 CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name)); 1076 } 1077 CeedCall(CeedFree(&(*ceed)->obj_delegates)); 1078 } 1079 1080 if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed)); 1081 1082 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1083 CeedCall(CeedFree(&(*ceed)->jit_source_roots[i])); 1084 } 1085 CeedCall(CeedFree(&(*ceed)->jit_source_roots)); 1086 1087 CeedCall(CeedFree(&(*ceed)->f_offsets)); 1088 CeedCall(CeedFree(&(*ceed)->resource)); 1089 CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed)); 1090 CeedCall(CeedFree(&(*ceed)->op_fallback_resource)); 1091 CeedCall(CeedFree(ceed)); 1092 return CEED_ERROR_SUCCESS; 1093 } 1094 1095 // LCOV_EXCL_START 1096 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1097 if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args); 1098 if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args); 1099 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1100 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1101 return ceed->err_msg; 1102 } 1103 // LCOV_EXCL_STOP 1104 1105 /** 1106 @brief Error handling implementation; use \ref CeedError instead. 1107 1108 @ref Developer 1109 **/ 1110 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) { 1111 va_list args; 1112 int ret_val; 1113 va_start(args, format); 1114 if (ceed) { 1115 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1116 } else { 1117 // LCOV_EXCL_START 1118 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1119 if (!ceed_error_handler) ceed_error_handler = "abort"; 1120 if (!strcmp(ceed_error_handler, "return")) ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1121 else 1122 // This function will not return 1123 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1124 } 1125 va_end(args); 1126 return ret_val; 1127 // LCOV_EXCL_STOP 1128 } 1129 1130 /** 1131 @brief Error handler that returns without printing anything. 1132 1133 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1134 1135 @ref Developer 1136 **/ 1137 // LCOV_EXCL_START 1138 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1139 return err_code; 1140 } 1141 // LCOV_EXCL_STOP 1142 1143 /** 1144 @brief Error handler that stores the error message for future use and returns the error. 1145 1146 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1147 1148 @ref Developer 1149 **/ 1150 // LCOV_EXCL_START 1151 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1152 if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args); 1153 if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args); 1154 1155 // Build message 1156 int len; 1157 len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func); 1158 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1159 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1160 return err_code; 1161 } 1162 // LCOV_EXCL_STOP 1163 1164 /** 1165 @brief Error handler that prints to stderr and aborts 1166 1167 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1168 1169 @ref Developer 1170 **/ 1171 // LCOV_EXCL_START 1172 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1173 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1174 vfprintf(stderr, format, *args); 1175 fprintf(stderr, "\n"); 1176 abort(); 1177 return err_code; 1178 } 1179 // LCOV_EXCL_STOP 1180 1181 /** 1182 @brief Error handler that prints to stderr and exits 1183 1184 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1185 1186 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() handlers (e.g., as used by gcov) are run. 1187 1188 @ref Developer 1189 **/ 1190 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1191 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1192 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1193 vfprintf(stderr, format, *args); // NOLINT 1194 fprintf(stderr, "\n"); 1195 exit(err_code); 1196 return err_code; 1197 } 1198 1199 /** 1200 @brief Set error handler 1201 1202 A default error handler is set in CeedInit(). 1203 Use this function to change the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined error handler. 1204 1205 @ref Developer 1206 **/ 1207 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1208 ceed->Error = handler; 1209 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1210 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1211 return CEED_ERROR_SUCCESS; 1212 } 1213 1214 /** 1215 @brief Get error message 1216 1217 The error message is only stored when using the error handler CeedErrorStore() 1218 1219 @param[in] ceed Ceed context to retrieve error message 1220 @param[out] err_msg Char pointer to hold error message 1221 1222 @ref Developer 1223 **/ 1224 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1225 if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg); 1226 if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg); 1227 *err_msg = ceed->err_msg; 1228 return CEED_ERROR_SUCCESS; 1229 } 1230 1231 /** 1232 @brief Restore error message 1233 1234 The error message is only stored when using the error handler CeedErrorStore() 1235 1236 @param[in] ceed Ceed context to restore error message 1237 @param[out] err_msg Char pointer that holds error message 1238 1239 @ref Developer 1240 **/ 1241 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1242 if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg); 1243 if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg); 1244 *err_msg = NULL; 1245 memcpy(ceed->err_msg, "No error message stored", 24); 1246 return CEED_ERROR_SUCCESS; 1247 } 1248 1249 /** 1250 @brief Get libCEED library version info 1251 1252 libCEED version numbers have the form major.minor.patch. 1253 Non-release versions may contain unstable interfaces. 1254 1255 @param[out] major Major version of the library 1256 @param[out] minor Minor version of the library 1257 @param[out] patch Patch (subminor) version of the library 1258 @param[out] release True for releases; false for development branches. 1259 1260 The caller may pass NULL for any arguments that are not needed. 1261 1262 @sa CEED_VERSION_GE() 1263 1264 @ref Developer 1265 */ 1266 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1267 if (major) *major = CEED_VERSION_MAJOR; 1268 if (minor) *minor = CEED_VERSION_MINOR; 1269 if (patch) *patch = CEED_VERSION_PATCH; 1270 if (release) *release = CEED_VERSION_RELEASE; 1271 return 0; 1272 } 1273 1274 int CeedGetScalarType(CeedScalarType *scalar_type) { 1275 *scalar_type = CEED_SCALAR_TYPE; 1276 return 0; 1277 } 1278 1279 /// @} 1280