mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-11-09 10:00:57 +03:00
Summary: This is the major transition that updates mvfst code to use the new interfaces. The new Folly implementations of the interfaces maintain all the existing behavior of folly types so this should not introduce any functional change. The core changes are: - Update the BatchWriters to use the new interfaces. - Update the FunctionLooper to use the new interfaces. - Change QuicServerTransport to take the folly types and wrap them in the new types for use in the QuicTransportBase. The rest of the diff is for updating all the existing uses of the QuicTrasnport to initialize the necessary types and pass them to the QUIC transport instead of directly passing folly types. Reviewed By: mjoras Differential Revision: D51413481 fbshipit-source-id: 5ed607e12b9a52b96148ad9b4f8f43899655d936
181 lines
4.7 KiB
C++
181 lines
4.7 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include <folly/ScopeGuard.h>
|
|
#include <glog/logging.h>
|
|
#include <quic/common/FunctionLooper.h>
|
|
|
|
namespace quic {
|
|
using namespace std::chrono_literals;
|
|
|
|
FunctionLooper::FunctionLooper(
|
|
std::shared_ptr<QuicEventBase> evb,
|
|
folly::Function<void()>&& func,
|
|
LooperType type)
|
|
: evb_(std::move(evb)), func_(std::move(func)), type_(type) {}
|
|
|
|
void FunctionLooper::setPacingTimer(QuicTimer::SharedPtr pacingTimer) noexcept {
|
|
pacingTimer_ = std::move(pacingTimer);
|
|
}
|
|
|
|
bool FunctionLooper::hasPacingTimer() const noexcept {
|
|
return pacingTimer_ != nullptr;
|
|
}
|
|
|
|
void FunctionLooper::setPacingFunction(
|
|
folly::Function<std::chrono::microseconds()>&& pacingFunc) {
|
|
pacingFunc_ = std::move(pacingFunc);
|
|
}
|
|
|
|
void FunctionLooper::commonLoopBody() noexcept {
|
|
inLoopBody_ = true;
|
|
SCOPE_EXIT {
|
|
inLoopBody_ = false;
|
|
};
|
|
auto hasBeenRunning = running_;
|
|
func_();
|
|
// callback could cause us to stop ourselves.
|
|
// Someone could have also called run() in the callback.
|
|
VLOG(10) << __func__ << ": " << type_ << " hasBeenRunning=" << hasBeenRunning
|
|
<< " running_=" << running_;
|
|
if (!running_) {
|
|
return;
|
|
}
|
|
if (!schedulePacingTimeout()) {
|
|
evb_->runInLoop(this);
|
|
}
|
|
}
|
|
|
|
bool FunctionLooper::schedulePacingTimeout() noexcept {
|
|
if (pacingFunc_ && pacingTimer_ &&
|
|
!pacingTimer_->isTimerCallbackScheduled(this)) {
|
|
auto timeUntilWrite = (*pacingFunc_)();
|
|
if (timeUntilWrite != 0us) {
|
|
nextPacingTime_ = Clock::now() + timeUntilWrite;
|
|
pacingTimer_->scheduleTimeout(this, timeUntilWrite);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FunctionLooper::runLoopCallback() noexcept {
|
|
folly::DelayedDestruction::DestructorGuard dg(this);
|
|
commonLoopBody();
|
|
}
|
|
|
|
void FunctionLooper::run(bool thisIteration) noexcept {
|
|
VLOG(10) << __func__ << ": " << type_;
|
|
running_ = true;
|
|
// Caller can call run() in func_. But if we are in pacing mode, we should
|
|
// prevent such loop.
|
|
if (pacingTimer_ && inLoopBody_) {
|
|
VLOG(4) << __func__ << ": " << type_
|
|
<< " in loop body and using pacing - not rescheduling";
|
|
return;
|
|
}
|
|
if (evb_->isLoopCallbackScheduled(this) ||
|
|
(!fireLoopEarly_ && pacingTimer_ &&
|
|
pacingTimer_->isTimerCallbackScheduled(this))) {
|
|
VLOG(10) << __func__ << ": " << type_ << " already scheduled";
|
|
return;
|
|
}
|
|
// If we are pacing, we're about to write again, if it's close, just write
|
|
// now.
|
|
if (pacingTimer_ && pacingTimer_->isTimerCallbackScheduled(this)) {
|
|
auto n = Clock::now();
|
|
auto timeUntilWrite = nextPacingTime_ < n
|
|
? 0us
|
|
: std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
nextPacingTime_ - n);
|
|
if (timeUntilWrite <= 1ms) {
|
|
pacingTimer_->cancelTimeout(this);
|
|
// The next loop is good enough
|
|
thisIteration = false;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
evb_->runInLoop(this, thisIteration);
|
|
}
|
|
|
|
void FunctionLooper::stop() noexcept {
|
|
VLOG(10) << __func__ << ": " << type_;
|
|
running_ = false;
|
|
if (evb_) {
|
|
evb_->cancelLoopCallback(this);
|
|
}
|
|
if (pacingTimer_) {
|
|
pacingTimer_->cancelTimeout(this);
|
|
}
|
|
}
|
|
|
|
bool FunctionLooper::isRunning() const {
|
|
return running_;
|
|
}
|
|
|
|
bool FunctionLooper::isPacingScheduled() {
|
|
return pacingTimer_ && pacingTimer_->isTimerCallbackScheduled(this);
|
|
}
|
|
|
|
bool FunctionLooper::isLoopCallbackScheduled() {
|
|
return evb_->isLoopCallbackScheduled(this);
|
|
}
|
|
|
|
void FunctionLooper::attachEventBase(std::shared_ptr<QuicEventBase> evb) {
|
|
VLOG(10) << __func__ << ": " << type_;
|
|
DCHECK(!evb_);
|
|
DCHECK(evb && evb->isInEventBaseThread());
|
|
evb_ = std::move(evb);
|
|
}
|
|
|
|
void FunctionLooper::detachEventBase() {
|
|
VLOG(10) << __func__ << ": " << type_;
|
|
DCHECK(evb_ && evb_->isInEventBaseThread());
|
|
stop();
|
|
if (pacingTimer_) {
|
|
pacingTimer_->cancelTimeout(this);
|
|
}
|
|
evb_ = nullptr;
|
|
}
|
|
|
|
void FunctionLooper::timeoutExpired() noexcept {
|
|
folly::DelayedDestruction::DestructorGuard dg(this);
|
|
commonLoopBody();
|
|
}
|
|
|
|
void FunctionLooper::callbackCanceled() noexcept {
|
|
return;
|
|
}
|
|
|
|
folly::Optional<std::chrono::microseconds>
|
|
FunctionLooper::getTimerTickInterval() noexcept {
|
|
if (pacingTimer_) {
|
|
return pacingTimer_->getTickInterval();
|
|
}
|
|
return folly::none;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& out, const LooperType& rhs) {
|
|
switch (rhs) {
|
|
case LooperType::ReadLooper:
|
|
out << "ReadLooper";
|
|
break;
|
|
case LooperType::PeekLooper:
|
|
out << "PeekLooper";
|
|
break;
|
|
case LooperType::WriteLooper:
|
|
out << "WriteLooper";
|
|
break;
|
|
default:
|
|
out << "unknown";
|
|
break;
|
|
}
|
|
return out;
|
|
}
|
|
} // namespace quic
|