Skip to content

Commit

Permalink
Add helper to get errno and error message (#20324)
Browse files Browse the repository at this point in the history
### Description
<!-- Describe your changes. -->
Add platform aware helper to fetch errno message string.


### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->
For usage in #20077

---------

Co-authored-by: Edward Chen <[email protected]>
  • Loading branch information
skottmckay and edgchen1 authored Apr 17, 2024
1 parent 4d2b981 commit 8143b0d
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 41 deletions.
25 changes: 25 additions & 0 deletions onnxruntime/core/platform/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,29 @@ std::ostream& operator<<(std::ostream& os, gsl::span<const LogicalProcessors> af

Env::Env() = default;

std::pair<int, std::string> GetErrnoInfo() {
auto err = errno;
std::string msg;

if (err != 0) {
char buf[512];

#if defined(_WIN32)
auto ret = strerror_s(buf, sizeof(buf), err);
msg = ret == 0 ? buf : "Failed to get error message"; // buf is guaranteed to be null terminated by strerror_s
#else
// strerror_r return type differs by platform.
auto ret = strerror_r(err, buf, sizeof(buf));
if constexpr (std::is_same_v<decltype(ret), int>) { // POSIX returns int
msg = ret == 0 ? buf : "Failed to get error message";
} else {
// GNU returns char*
msg = ret;
}
#endif
}

return {err, msg};
}

} // namespace onnxruntime
6 changes: 6 additions & 0 deletions onnxruntime/core/platform/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ struct ThreadOptions {
std::ostream& operator<<(std::ostream& os, const LogicalProcessors&);
std::ostream& operator<<(std::ostream& os, gsl::span<const LogicalProcessors>);

/// <summary>
/// Get errno and the corresponding error message.
/// </summary>
/// <returns>errno and the error message string if errno indicates an error.</returns>
std::pair<int, std::string> GetErrnoInfo();

/// \brief An interface used by the onnxruntime implementation to
/// access operating system functionality like the filesystem etc.
///
Expand Down
48 changes: 11 additions & 37 deletions onnxruntime/core/platform/posix/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,39 +62,11 @@ class UnmapFileParam {
size_t len;
};

/**
* @brief Get System Error
*
* @return a pair of {errno, error message}
*/
static std::pair<int, std::string> GetSystemError(int e) {
char buf[1024];
const char* msg = "";
if (e > 0) {
#if defined(__GLIBC__) && defined(_GNU_SOURCE) && !defined(__ANDROID__)
msg = strerror_r(e, buf, sizeof(buf));
#else
// for Mac OS X and Android lower than API 23
if (strerror_r(e, buf, sizeof(buf)) != 0) {
buf[0] = '\0';
}
msg = buf;
#endif
}

return std::make_pair(e, msg);
}

static std::pair<int, std::string> GetSystemError() {
auto e = errno;
return GetSystemError(e);
}

static void UnmapFile(void* param) noexcept {
std::unique_ptr<UnmapFileParam> p(reinterpret_cast<UnmapFileParam*>(param));
int ret = munmap(p->addr, p->len);
if (ret != 0) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
LOGS_DEFAULT(ERROR) << "munmap failed. error code: " << err_no << " error msg: " << err_msg;
}
}
Expand All @@ -104,8 +76,9 @@ struct FileDescriptorTraits {
static Handle GetInvalidHandleValue() { return -1; }
static void CleanUp(Handle h) {
if (close(h) == -1) {
auto [err_no, err_msg] = GetSystemError();
LOGS_DEFAULT(ERROR) << "Failed to close file descriptor " << h << " - error code: " << err_no << " error msg: " << err_msg;
auto [err_no, err_msg] = GetErrnoInfo();
LOGS_DEFAULT(ERROR) << "Failed to close file descriptor " << h << " - error code: " << err_no
<< " error msg: " << err_msg;
}
}
};
Expand All @@ -131,7 +104,7 @@ int nftw_remove(
int /*typeflag*/, struct FTW* /*ftwbuf*/) {
const auto result = remove(fpath);
if (result != 0) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
LOGS_DEFAULT(WARNING) << "remove() failed. Error code: " << err_no << " error msg: " << err_msg
<< ", path: " << fpath;
}
Expand Down Expand Up @@ -188,22 +161,22 @@ class PosixThread : public EnvThread {
pthread_attr_t attr;
int s = pthread_attr_init(&attr);
if (s != 0) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
ORT_THROW("pthread_attr_init failed, error code: ", err_no, " error msg: ", err_msg);
}

size_t stack_size = thread_options.stack_size;
if (stack_size > 0) {
s = pthread_attr_setstacksize(&attr, stack_size);
if (s != 0) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
ORT_THROW("pthread_attr_setstacksize failed, error code: ", err_no, " error msg: ", err_msg);
}
}

s = pthread_create(&hThread, &attr, ThreadMain, param_ptr.get());
if (s != 0) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
ORT_THROW("pthread_create failed, error code: ", err_no, " error msg: ", err_msg);
}
param_ptr.release();
Expand Down Expand Up @@ -249,7 +222,8 @@ class PosixThread : public EnvThread {
<< ", index: " << p->index
<< ", mask: " << *p->affinity;
} else {
auto [err_no, err_msg] = GetSystemError(ret);
errno = ret;
auto [err_no, err_msg] = GetErrnoInfo();
#if !defined(USE_MIGRAPHX)
LOGS_DEFAULT(ERROR) << "pthread_setaffinity_np failed for thread: " << syscall(SYS_gettid)
<< ", index: " << p->index
Expand Down Expand Up @@ -461,7 +435,7 @@ class PosixEnv : public Env {
}

static common::Status ReportSystemError(const char* operation_name, const std::string& path) {
auto [err_no, err_msg] = GetSystemError();
auto [err_no, err_msg] = GetErrnoInfo();
std::ostringstream oss;
oss << operation_name << " file \"" << path << "\" failed: " << err_msg;
return common::Status(common::SYSTEM, err_no, oss.str());
Expand Down
7 changes: 3 additions & 4 deletions onnxruntime/core/platform/windows/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,10 @@ class WindowsThread : public EnvThread {
local_param.get(), 0,
&threadID);
if (th_handle == 0) {
auto err = errno;
auto dos_error = _doserrno;
char message_buf[256];
strerror_s(message_buf, sizeof(message_buf), err);
ORT_THROW("WindowThread:_beginthreadex failed with message: ", message_buf, " doserrno: ", dos_error);
auto [err, msg] = GetErrnoInfo();
ORT_THROW("WindowThread:_beginthreadex failed with errno:", err, " message:", msg,
" doserrno:", dos_error);
}
local_param.release();
hThread.reset(reinterpret_cast<HANDLE>(th_handle));
Expand Down
20 changes: 20 additions & 0 deletions onnxruntime/test/platform/env_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,25 @@ TEST(PlatformEnvTest, DirectoryCreationAndDeletion) {
ASSERT_FALSE(env.FolderExists(root_dir));
}

TEST(PlatformEnvTest, GetErrnoInfo) {
// command that should generate an errno error
std::ifstream file("non_existent_file");
ASSERT_TRUE(file.fail());
auto [err, msg] = GetErrnoInfo();
ASSERT_EQ(err, ENOENT);

#if defined(_WIN32)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

// GetErrnoInfo uses strerror_r or strerror_s depending on the platform. use the unsafe std::sterror to get the
// expected value given this is a unit test so doesn't have to be as robust.
ASSERT_EQ(msg, std::strerror(ENOENT));

#if defined(_WIN32)
#pragma warning(pop)
#endif
}
} // namespace test
} // namespace onnxruntime

0 comments on commit 8143b0d

Please sign in to comment.