Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate more interface and definition. Add comments on std::future. Mark noexcept to compat mode-related functions #588

Merged
merged 6 commits into from
Jan 22, 2025

Conversation

kingcrimsontianyu
Copy link
Contributor

@kingcrimsontianyu kingcrimsontianyu commented Jan 20, 2025

This PR performs makes the following three improvements:

  • Separates interface and definition for file_handle.hpp that was missed in the previous PR Continue to make KvikIO a shared library by moving code from hpp to cpp #581.
  • To help avoid UB (e.g. program crash) for downstream applications, adds the following qualifying remark to the returned future object of pread/pwrite:

    The std::future object's wait() or get() should not be called after the lifetime of the FileHandle object ends. Otherwise, the behavior is undefined.

  • Add noexcept specifier to compatibility mode-related functions.

@kingcrimsontianyu kingcrimsontianyu added improvement Improves an existing functionality non-breaking Introduces a non-breaking change c++ Affects the C++ API of KvikIO labels Jan 20, 2025
@kingcrimsontianyu kingcrimsontianyu self-assigned this Jan 20, 2025
Copy link

copy-pr-bot bot commented Jan 20, 2025

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@kingcrimsontianyu
Copy link
Contributor Author

/ok to test

@kingcrimsontianyu
Copy link
Contributor Author

/ok to test

@kingcrimsontianyu kingcrimsontianyu marked this pull request as ready for review January 20, 2025 16:59
@kingcrimsontianyu kingcrimsontianyu requested a review from a team as a code owner January 20, 2025 16:59
Copy link
Member

@madsbk madsbk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I only have a minor suggestion

{
if (closed()) { return; }

if (!is_compat_mode_preferred()) { cuFileAPI::instance().HandleDeregister(_handle); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this refactoring, but might make sense to fix in this PR:
We need an exception catch or make is_compat_mode_preferred() and compat_mode() noexcept as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting: defaults::compat_mode() can't be noexcept because it calls defaults::instance() and defaults's constructor is potentially throwing. One workaround is:

CompatMode defaults::compat_mode() noexcept { 
    try {
        return instance()->_compat_mode; 
    } catch(...) {}
    return CompatMode::ON; // Or we may add an CompatMode::Invalid?
}

But is it worth the hassle to make it noexcept at all?
@wence- @madsbk

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is it worth the hassle to make it noexcept at all?

Heh, maybe not :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note, we can use noexcept on functions that might throw exceptions, it just makes them fatal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's UB, rather than just making things fatal

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's UB, rather than just making things fatal

It is UB in the sense that calling std::terminate() is UB (it is implementation-defined whether any stack unwinding).
But std::terminate() is guaranteed to be called when violating noexcept: https://en.cppreference.com/w/cpp/error/terminate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I was wrong, it is not UB, so all good.

@kingcrimsontianyu kingcrimsontianyu changed the title Separate more interface and definition. Add comments on std::future Separate more interface and definition. Add comments on std::future. Mark noexcept wherever applicable Jan 21, 2025
@kingcrimsontianyu kingcrimsontianyu changed the title Separate more interface and definition. Add comments on std::future. Mark noexcept wherever applicable Separate more interface and definition. Add comments on std::future. Mark noexcept to compat mode-related functions Jan 21, 2025
{
try {
cuFileAPI::instance();
} catch (const std::runtime_error&) {
} catch (...) {
Copy link
Contributor Author

@kingcrimsontianyu kingcrimsontianyu Jan 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho ... is better since it simplifies the effort to cover all possible exception types that the try block may generate (the exact types can be documented in cuFileAPI::instance()'s @throw section) while satisfying the noexcept promise. But I'm ready to revert if there's any other consideration I'm not aware of. @madsbk @vuule @wence-

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, ... is better!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+2

_fd_direct_on = -1;
_fd_direct_off = -1;
_initialized = false;
} catch (...) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cuFileAPI constructor (hence cuFileAPI::instance()) is potentially throwing. So to satisfy the noexcept promise, the try-catch block has to be here.

Copy link
Member

@madsbk madsbk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

Comment on lines +48 to +58
bool is_running_in_wsl() noexcept
{
struct utsname buf {};
int err = ::uname(&buf);
if (err == 0) {
const std::string name(static_cast<char*>(buf.release));
// 'Microsoft' for WSL1 and 'microsoft' for WSL2
return name.find("icrosoft") != std::string::npos;
try {
struct utsname buf {};
int err = ::uname(&buf);
if (err == 0) {
const std::string name(static_cast<char*>(buf.release));
// 'Microsoft' for WSL1 and 'microsoft' for WSL2
return name.find("icrosoft") != std::string::npos;
}
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: what might throw here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a bit paranoid about STL function calls. Here the string's constructor basic_string(const charT* s, const Allocator& a = Allocator()); should be potentially throwing, because it does not have a "Throws" section in its specs. According to the specs:

Functions defined in the C++ standard library that do not have a Throws: paragraph but do have a potentially-throwing exception specification may throw implementation-defined exceptions.

In particular, they can report a failure to allocate storage by throwing an exception of type bad_alloc, or a class derived from bad_alloc

I would imagine the rare but not impossible case in practice, where the stack may overflow (when short string optimization is in effect), or the heap may run out of memory.

The string find overload size_type F(const charT* s, size_type pos) const; is on the same boat.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks!

Copy link
Contributor

@wence- wence- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One query about the catch in is_running_in_wsl, otherwise looks good!

@kingcrimsontianyu
Copy link
Contributor Author

/merge

@rapids-bot rapids-bot bot merged commit 716a99f into rapidsai:branch-25.02 Jan 22, 2025
59 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Affects the C++ API of KvikIO improvement Improves an existing functionality non-breaking Introduces a non-breaking change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants