Skip to content

Commit

Permalink
Add IoScheduler to enable epoll-based Task scheduling (#448)
Browse files Browse the repository at this point in the history
Add the io_scheduler from libcoro, rename to IoScheduler, use standard code styles, and adjust implementation to support MRC's other libcoro port details.

Authors:
  - Christopher Harris (https://github.com/cwharris)

Approvers:
  - Michael Demoret (https://github.com/mdemoret-nv)

URL: #448
  • Loading branch information
cwharris authored Feb 29, 2024
1 parent 6c4256d commit 3010601
Show file tree
Hide file tree
Showing 14 changed files with 1,421 additions and 19 deletions.
1 change: 1 addition & 0 deletions cpp/mrc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ add_library(libmrc
src/public/core/logging.cpp
src/public/core/thread.cpp
src/public/coroutines/event.cpp
src/public/coroutines/io_scheduler.cpp
src/public/coroutines/sync_wait.cpp
src/public/coroutines/task_container.cpp
src/public/coroutines/thread_local_context.cpp
Expand Down
118 changes: 118 additions & 0 deletions cpp/mrc/include/mrc/coroutines/detail/poll_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/

/**
* Original Source: https://github.com/jbaldwin/libcoro
* Original License: Apache License, Version 2.0; included below
*/

/**
* Copyright 2021 Josh Baldwin
*
* 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.
*/

#pragma once

#include "mrc/coroutines/fd.hpp"
#include "mrc/coroutines/poll.hpp"
#include "mrc/coroutines/time.hpp"

#include <atomic>
#include <coroutine>
#include <map>
#include <optional>

namespace mrc::coroutines::detail {
/**
* Poll Info encapsulates everything about a poll operation for the event as well as its paired
* timeout. This is important since coroutines that are waiting on an event or timeout do not
* immediately execute, they are re-scheduled onto the thread pool, so its possible its pair
* event or timeout also triggers while the coroutine is still waiting to resume. This means that
* the first one to happen, the event itself or its timeout, needs to disable the other pair item
* prior to resuming the coroutine.
*
* Finally, its also important to note that the event and its paired timeout could happen during
* the same epoll_wait and possibly trigger the coroutine to start twice. Only one can win, so the
* first one processed sets m_processed to true and any subsequent events in the same epoll batch
* are effectively discarded.
*/
struct PollInfo
{
using timed_events_t = std::multimap<mrc::coroutines::time_point_t, detail::PollInfo*>;

PollInfo() = default;
~PollInfo() = default;

PollInfo(const PollInfo&) = delete;
PollInfo(PollInfo&&) = delete;
auto operator=(const PollInfo&) -> PollInfo& = delete;
auto operator=(PollInfo&&) -> PollInfo& = delete;

struct PollAwaiter
{
explicit PollAwaiter(PollInfo& pi) noexcept : m_pi(pi) {}

static auto await_ready() noexcept -> bool
{
return false;
}
auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> void
{
m_pi.m_awaiting_coroutine = awaiting_coroutine;
std::atomic_thread_fence(std::memory_order::release);
}
auto await_resume() const noexcept -> mrc::coroutines::PollStatus
{
return m_pi.m_poll_status;
}

PollInfo& m_pi;
};

auto operator co_await() noexcept -> PollAwaiter
{
return PollAwaiter{*this};
}

/// The file descriptor being polled on. This is needed so that if the timeout occurs first then
/// the event loop can immediately disable the event within epoll.
fd_t m_fd{-1};
/// The timeout's position in the timeout map. A poll() with no timeout or yield() this is empty.
/// This is needed so that if the event occurs first then the event loop can immediately disable
/// the timeout within epoll.
std::optional<timed_events_t::iterator> m_timer_pos{std::nullopt};
/// The awaiting coroutine for this poll info to resume upon event or timeout.
std::coroutine_handle<> m_awaiting_coroutine;
/// The status of the poll operation.
mrc::coroutines::PollStatus m_poll_status{mrc::coroutines::PollStatus::error};
/// Did the timeout and event trigger at the same time on the same epoll_wait call?
/// Once this is set to true all future events on this poll info are null and void.
bool m_processed{false};
};

} // namespace mrc::coroutines::detail
44 changes: 44 additions & 0 deletions cpp/mrc/include/mrc/coroutines/fd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/

/**
* Original Source: https://github.com/jbaldwin/libcoro
* Original License: Apache License, Version 2.0; included below
*/

/**
* Copyright 2021 Josh Baldwin
*
* 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.
*/

#pragma once

namespace mrc::coroutines {
using fd_t = int;

} // namespace mrc::coroutines
Loading

0 comments on commit 3010601

Please sign in to comment.