-
Notifications
You must be signed in to change notification settings - Fork 630
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Michał Zientkiewicz <[email protected]>
- Loading branch information
Showing
6 changed files
with
417 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
# Get all the source files | ||
|
||
# The headers here are private and should not be installed. | ||
# collect_headers(DALI_INST_HDRS PARENT_SCOPE) | ||
|
||
collect_sources(DALI_SRCS PARENT_SCOPE) | ||
collect_test_sources(DALI_TEST_SRCS PARENT_SCOPE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include <gtest/gtest.h> | ||
#include <stdexcept> | ||
#define DALI_ALLOW_NEW_C_API | ||
#include "dali/dali.h" | ||
#include "dali/c_api_2/error_handling.h" | ||
#include "dali/core/cuda_error.h" | ||
|
||
namespace dali { | ||
|
||
template <typename ExceptionType> | ||
daliResult_t ThrowAndTranslate(ExceptionType &&ex) { | ||
DALI_PROLOG(); | ||
throw std::forward<ExceptionType>(ex); | ||
DALI_EPILOG(); | ||
} | ||
|
||
template <typename ExceptionType> | ||
void CheckException(ExceptionType &&ex, daliResult_t expected_result) { | ||
std::string message(ex.what()); | ||
daliResult_t ret = ThrowAndTranslate(std::forward<ExceptionType>(ex)); | ||
EXPECT_EQ(ret, expected_result); | ||
EXPECT_EQ(daliGetLastError(), expected_result); | ||
EXPECT_EQ(daliGetLastErrorMessage(), message); | ||
std::cout << daliGetErrorName(ret) << " " | ||
<< daliGetLastErrorMessage() << std::endl; | ||
daliClearLastError(); | ||
EXPECT_EQ(daliGetLastError(), DALI_SUCCESS); | ||
EXPECT_STREQ(daliGetLastErrorMessage(), ""); | ||
} | ||
|
||
TEST(CAPI2InternalTest, ErrorTranslation) { | ||
CheckException(std::runtime_error("Runtime Error"), DALI_ERROR_INVALID_OPERATION); | ||
CheckException(std::bad_alloc(), DALI_ERROR_OUT_OF_MEMORY); | ||
CheckException(CUDABadAlloc(), DALI_ERROR_OUT_OF_MEMORY); | ||
CheckException(std::logic_error("Logic dictates that it's an error"), DALI_ERROR_INTERNAL); | ||
CheckException(std::out_of_range("Bullet left the shooting range"), DALI_ERROR_OUT_OF_RANGE); | ||
CheckException(invalid_key("This key doesn't fit into the keyhole."), DALI_ERROR_INVALID_KEY); | ||
|
||
CheckException(std::system_error(std::make_error_code(std::errc::no_such_file_or_directory)), | ||
DALI_ERROR_PATH_NOT_FOUND); | ||
CheckException(std::system_error(std::make_error_code(std::errc::no_such_device_or_address)), | ||
DALI_ERROR_PATH_NOT_FOUND); | ||
|
||
CheckException(std::system_error(std::make_error_code(std::errc::no_space_on_device)), | ||
DALI_ERROR_IO_ERROR); | ||
CheckException(std::system_error( | ||
std::make_error_code(std::errc::inappropriate_io_control_operation)), | ||
DALI_ERROR_IO_ERROR); | ||
CheckException(std::system_error(std::make_error_code(std::io_errc::stream)), | ||
DALI_ERROR_IO_ERROR); | ||
|
||
CheckException(std::system_error(std::make_error_code(std::errc::not_enough_memory)), | ||
DALI_ERROR_OUT_OF_MEMORY); | ||
|
||
CheckException(std::system_error(std::make_error_code(std::errc::bad_file_descriptor)), | ||
DALI_ERROR_SYSTEM); | ||
CheckException(std::system_error(std::make_error_code(std::errc::too_many_files_open)), | ||
DALI_ERROR_SYSTEM); | ||
} | ||
|
||
} // namespace dali |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include <stdexcept> | ||
#include <string> | ||
#include <utility> | ||
#include "dali/c_api_2/error_handling.h" | ||
#include "dali/core/error_handling.h" | ||
#include "dali/core/cuda_error.h" | ||
|
||
namespace dali::c_api { | ||
|
||
struct ErrorInfo { | ||
inline ErrorInfo() { | ||
message.reserve(1024); // should help with properly reporting OOMs | ||
} | ||
daliResult_t result = DALI_SUCCESS; | ||
std::string message; | ||
}; | ||
|
||
thread_local ErrorInfo g_daliLastError; | ||
|
||
struct ErrorDesc { | ||
const char *name, *description; | ||
}; | ||
|
||
ErrorDesc GetErrorDesc(daliResult_t result) { | ||
#define RESULT_DESC(name, desc) case DALI_##name: return { "DALI_" #name, desc } | ||
#define ERROR_DESC(name, desc) RESULT_DESC(ERROR_##name, desc) | ||
|
||
switch (result) { | ||
RESULT_DESC(SUCCESS, "The operation was successful."); | ||
RESULT_DESC(NO_DATA, "The operation was successful, but didn't return any data."); | ||
RESULT_DESC(NOT_READY, "The query succeeded, but the operation queried is still pending."); | ||
ERROR_DESC(INVALID_HANDLE, "The operation received an invalid DALI handle."); | ||
ERROR_DESC(INVALID_ARGUMENT, "An invalid argument was specified."); | ||
ERROR_DESC(INVALID_TYPE, "An argument of invalid type encountered."); | ||
ERROR_DESC(INVALID_OPERATION, "An invalid operation was requested."); | ||
ERROR_DESC(OUT_OF_RANGE, "An argument is out of valid range."); | ||
ERROR_DESC(INVALID_KEY, "The operation received an invalid dictionary key."); | ||
|
||
ERROR_DESC(SYSTEM, "An operating system routine failed."); | ||
ERROR_DESC(PATH_NOT_FOUND, "A non-existent or non-accessible file path was encountered."); | ||
ERROR_DESC(IO_ERROR, "An I/O operation failed"); | ||
ERROR_DESC(OUT_OF_MEMORY, "Cannot allocate memory"); | ||
ERROR_DESC(INTERNAL, "An internal error occurred"); | ||
ERROR_DESC(UNLOADING, "DALI is unloading - either daliShutdown was called or " | ||
"the process is shutting down."); | ||
ERROR_DESC(CUDA_ERROR, "A CUDA call has failed."); | ||
default: | ||
return { "<invalid>", "<invalid>" }; | ||
} | ||
} | ||
|
||
daliResult_t SetLastError(daliResult_t result, const char *message) { | ||
g_daliLastError.result = result; | ||
g_daliLastError.message = message; | ||
return result; | ||
} | ||
|
||
daliResult_t HandleError(std::exception_ptr ex) { | ||
try { | ||
std::rethrow_exception(std::move(ex)); | ||
} catch (dali::c_api::InvalidHandle &e) { | ||
return SetLastError(DALI_ERROR_INVALID_HANDLE, e.what()); | ||
} catch (std::invalid_argument &e) { | ||
return SetLastError(DALI_ERROR_INVALID_ARGUMENT, e.what()); | ||
} catch (dali::CUDAError &e) { | ||
if (e.is_rt_api()) { | ||
if (e.rt_error() == cudaErrorNotReady) | ||
return SetLastError(DALI_NOT_READY, e.what()); | ||
} else if (e.is_drv_api()) { | ||
if (e.drv_error() == CUDA_ERROR_NOT_READY) | ||
return SetLastError(DALI_NOT_READY, e.what()); | ||
} | ||
return SetLastError(DALI_ERROR_CUDA_ERROR, e.what()); | ||
} catch (dali::CUDABadAlloc &e) { | ||
return SetLastError(DALI_ERROR_OUT_OF_MEMORY, e.what()); | ||
} catch (std::bad_alloc &e) { | ||
return SetLastError(DALI_ERROR_OUT_OF_MEMORY, e.what()); | ||
} catch (dali::invalid_key &e) { | ||
return SetLastError(DALI_ERROR_INVALID_KEY, e.what()); | ||
} catch (std::out_of_range &e) { | ||
return SetLastError(DALI_ERROR_OUT_OF_RANGE, e.what()); | ||
} catch (std::system_error &e) { | ||
if (e.code().category() == std::generic_category()) { | ||
daliResult_t result = [&]() { | ||
switch (static_cast<std::errc>(e.code().value())) { | ||
case std::errc::no_such_file_or_directory: | ||
case std::errc::no_such_device: | ||
case std::errc::no_such_device_or_address: | ||
return DALI_ERROR_PATH_NOT_FOUND; | ||
case std::errc::not_enough_memory: | ||
return DALI_ERROR_OUT_OF_MEMORY; | ||
case std::errc::timed_out: | ||
return DALI_ERROR_TIMEOUT; | ||
case std::errc::address_family_not_supported: | ||
case std::errc::address_in_use: | ||
case std::errc::address_not_available: | ||
case std::errc::already_connected: | ||
case std::errc::broken_pipe: | ||
case std::errc::connection_aborted: | ||
case std::errc::connection_already_in_progress: | ||
case std::errc::connection_refused: | ||
case std::errc::connection_reset: | ||
case std::errc::device_or_resource_busy: | ||
case std::errc::directory_not_empty: | ||
case std::errc::file_exists: | ||
case std::errc::file_too_large: | ||
case std::errc::filename_too_long: | ||
case std::errc::host_unreachable: | ||
case std::errc::inappropriate_io_control_operation: | ||
case std::errc::io_error: | ||
case std::errc::is_a_directory: | ||
case std::errc::message_size: | ||
case std::errc::network_down: | ||
case std::errc::network_reset: | ||
case std::errc::network_unreachable: | ||
case std::errc::no_buffer_space: | ||
case std::errc::no_message: | ||
case std::errc::no_space_on_device: | ||
case std::errc::not_a_directory: | ||
case std::errc::not_a_socket: | ||
case std::errc::read_only_file_system: | ||
return DALI_ERROR_IO_ERROR; | ||
default: | ||
return DALI_ERROR_SYSTEM; | ||
} | ||
}(); | ||
return SetLastError(result, e.what()); | ||
} else if (e.code().category() == std::iostream_category()) { | ||
return SetLastError(DALI_ERROR_IO_ERROR, e.what()); | ||
} else { | ||
return SetLastError(DALI_ERROR_SYSTEM, e.what()); | ||
} | ||
} catch (std::runtime_error &e) { | ||
return SetLastError(DALI_ERROR_INVALID_OPERATION, e.what()); | ||
} catch (std::exception &e) { | ||
return SetLastError(DALI_ERROR_INTERNAL, e.what()); | ||
} catch (const char *e) { // handle strings thrown as exceptions | ||
return SetLastError(DALI_ERROR_INTERNAL, e); | ||
} catch (const std::string &e) { // handle strings thrown as exceptions | ||
return SetLastError(DALI_ERROR_INTERNAL, e.c_str()); | ||
} catch (...) { | ||
return SetLastError(DALI_ERROR_INTERNAL, "<unknown error>"); | ||
} | ||
} | ||
|
||
} // namespace dali::c_api | ||
|
||
using namespace dali; // NOLINT | ||
|
||
daliResult_t daliGetLastError() { | ||
return c_api::g_daliLastError.result; | ||
} | ||
|
||
const char *daliGetLastErrorMessage() { | ||
return c_api::g_daliLastError.message.c_str(); | ||
} | ||
|
||
void daliClearLastError() { | ||
c_api::g_daliLastError = {}; | ||
} | ||
|
||
const char *daliGetErrorName(daliResult_t result) { | ||
return c_api::GetErrorDesc(result).name; | ||
} | ||
|
||
const char *daliGetErrorDescription(daliResult_t result) { | ||
return c_api::GetErrorDesc(result).description; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#ifndef DALI_C_API_2_ERROR_HANDLING_H_ | ||
#define DALI_C_API_2_ERROR_HANDLING_H_ | ||
|
||
#include <stdexcept> | ||
#include <iostream> | ||
#include <string> | ||
#include <sstream> | ||
#define DALI_ALLOW_NEW_C_API | ||
#include "dali/dali.h" | ||
#include "dali/core/error_handling.h" | ||
|
||
inline std::ostream &operator<<(std::ostream &os, daliResult_t result) { | ||
const char *e = daliGetErrorName(result); | ||
if (e[0] == '<') | ||
os << "<unknown: " << static_cast<int>(result) << ">"; | ||
else | ||
os << e; | ||
return os; | ||
} | ||
|
||
inline std::string to_string(daliResult_t result) { | ||
std::stringstream ss; | ||
ss << result; | ||
return ss.str(); | ||
} | ||
|
||
namespace dali { | ||
namespace c_api { | ||
|
||
DLL_PUBLIC daliResult_t HandleError(std::exception_ptr ex); | ||
DLL_PUBLIC daliResult_t CheckInit(); | ||
|
||
class InvalidHandle : public std::invalid_argument { | ||
public: | ||
InvalidHandle() : std::invalid_argument("The handle is invalid") {} | ||
explicit InvalidHandle(const std::string &what) : std::invalid_argument(what) {} | ||
explicit InvalidHandle(const char *what) : std::invalid_argument(what) {} | ||
}; | ||
|
||
inline InvalidHandle NullHandle() { return InvalidHandle("The handle must not be NULL."); } | ||
|
||
inline InvalidHandle NullHandle(const char *what_handle) { | ||
return InvalidHandle(make_string("The ", what_handle, " handle must not be NULL.")); | ||
} | ||
|
||
} // namespace c_api | ||
} // namespace dali | ||
|
||
#define DALI_PROLOG() try { if (auto err = dali::c_api::CheckInit()) return err; else; | ||
#define DALI_EPILOG() return DALI_SUCCESS; } catch (...) { \ | ||
return ::dali::c_api::HandleError(std::current_exception()); \ | ||
} | ||
|
||
#endif // DALI_C_API_2_ERROR_HANDLING_H_ |
Oops, something went wrong.