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