From 82c9be0b33227d63329f19855519125bd7c21435 Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Fri, 24 Jan 2025 10:22:21 -0800 Subject: [PATCH 1/2] core, proxy, handler: use DeferCall::defer everywhere --- src/core/qzmq/src/qzmqvalve.cpp | 6 ++++-- src/core/zrpcrequest.cpp | 7 ++++--- src/core/zwebsocket.cpp | 9 ++++----- src/handler/deferred.cpp | 3 ++- src/handler/deferred.h | 3 +++ src/handler/handlermain.cpp | 6 +++--- src/handler/httpsession.cpp | 3 ++- src/proxy/domainmap.cpp | 15 ++++++++------- src/proxy/main.cpp | 22 ++++++++++++++-------- src/proxy/requestsession.cpp | 10 ++++++---- src/proxy/sockjssession.cpp | 8 +++++--- src/proxy/testhttprequest.cpp | 10 +++++++--- src/proxy/testwebsocket.cpp | 17 ++++++++++------- src/proxy/websocketoverhttp.cpp | 6 ++++-- 14 files changed, 76 insertions(+), 49 deletions(-) diff --git a/src/core/qzmq/src/qzmqvalve.cpp b/src/core/qzmq/src/qzmqvalve.cpp index e38497df8..4ee26628b 100644 --- a/src/core/qzmq/src/qzmqvalve.cpp +++ b/src/core/qzmq/src/qzmqvalve.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012-2020 Justin Karneges + * Copyright (C) 2025 Fastly, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -25,6 +26,7 @@ #include #include "qzmqsocket.h" +#include "defercall.h" namespace QZmq { @@ -39,6 +41,7 @@ class Valve::Private : public QObject bool pendingRead; int maxReadsPerEvent; boost::signals2::scoped_connection rrConnection; + DeferCall deferCall; Private(Valve *_q) : QObject(_q), @@ -62,7 +65,7 @@ class Valve::Private : public QObject return; pendingRead = true; - QMetaObject::invokeMethod(this, "queuedRead", Qt::QueuedConnection); + deferCall.defer([=] { queuedRead(); }); } void tryRead() @@ -99,7 +102,6 @@ class Valve::Private : public QObject tryRead(); } -private slots: void queuedRead() { pendingRead = false; diff --git a/src/core/zrpcrequest.cpp b/src/core/zrpcrequest.cpp index 4c888c2eb..e83cc4d7a 100644 --- a/src/core/zrpcrequest.cpp +++ b/src/core/zrpcrequest.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2014-2015 Fanout, Inc. - * Copyright (C) 2024 Fastly, Inc. + * Copyright (C) 2024-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -31,6 +31,7 @@ #include "uuidutil.h" #include "log.h" #include "rtimer.h" +#include "defercall.h" using Connection = boost::signals2::scoped_connection; @@ -52,6 +53,7 @@ class ZrpcRequest::Private : public QObject QByteArray conditionString; std::unique_ptr timer; Connection timerConnection; + DeferCall deferCall; Private(ZrpcRequest *_q) : QObject(_q), @@ -136,7 +138,6 @@ class ZrpcRequest::Private : public QObject q->finished(); } -private slots: void doStart() { if(!manager->canWriteImmediately()) @@ -238,7 +239,7 @@ void ZrpcRequest::start(const QString &method, const QVariantHash &args) { d->method = method; d->args = args; - QMetaObject::invokeMethod(d, "doStart", Qt::QueuedConnection); + d->deferCall.defer([=] { d->doStart(); }); } void ZrpcRequest::respond(const QVariant &result) diff --git a/src/core/zwebsocket.cpp b/src/core/zwebsocket.cpp index 644df5409..05079c68e 100644 --- a/src/core/zwebsocket.cpp +++ b/src/core/zwebsocket.cpp @@ -96,6 +96,7 @@ class ZWebSocket::Private : public QObject bool multi; Connection expireTimerConnection; Connection keepAliveTimerConnection; + DeferCall deferCall; Private(ZWebSocket *_q) : QObject(_q), @@ -266,7 +267,7 @@ class ZWebSocket::Private : public QObject if(!pendingUpdate) { pendingUpdate = true; - QMetaObject::invokeMethod(this, "doUpdate", Qt::QueuedConnection); + deferCall.defer([=] { doUpdate(); }); } } @@ -298,7 +299,7 @@ class ZWebSocket::Private : public QObject state = Idle; cleanup(); - QMetaObject::invokeMethod(this, "doClosed", Qt::QueuedConnection); + deferCall.defer([=] { doClosed(); }); } Frame readFrame() @@ -338,7 +339,7 @@ class ZWebSocket::Private : public QObject // if peer was already closed, then we're done! state = Idle; cleanup(); - QMetaObject::invokeMethod(this, "doClosed", Qt::QueuedConnection); + deferCall.defer([=] { doClosed(); }); } else { @@ -977,7 +978,6 @@ class ZWebSocket::Private : public QObject return ErrorGeneric; } -public slots: void doClosed() { q->closed(); @@ -1067,7 +1067,6 @@ public slots: } } -public: void expire_timeout() { state = Idle; diff --git a/src/handler/deferred.cpp b/src/handler/deferred.cpp index 60d309f85..deed5e1ee 100644 --- a/src/handler/deferred.cpp +++ b/src/handler/deferred.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Fanout, Inc. + * Copyright (C) 2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -42,7 +43,7 @@ void Deferred::setFinished(bool ok, const QVariant &value) result_.success = ok; result_.value = value; - QMetaObject::invokeMethod(this, "doFinish", Qt::QueuedConnection); + deferCall_.defer([=] { doFinish(); }); } void Deferred::doFinish() diff --git a/src/handler/deferred.h b/src/handler/deferred.h index 127167685..f25feb412 100644 --- a/src/handler/deferred.h +++ b/src/handler/deferred.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Fanout, Inc. + * Copyright (C) 2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -26,6 +27,7 @@ #include #include #include +#include "defercall.h" class DeferredResult { @@ -68,6 +70,7 @@ private slots: private: DeferredResult result_; + DeferCall deferCall_; }; #endif diff --git a/src/handler/handlermain.cpp b/src/handler/handlermain.cpp index 1bef51d41..b2ea71477 100644 --- a/src/handler/handlermain.cpp +++ b/src/handler/handlermain.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 Fanout, Inc. - * Copyright (C) 2024 Fastly, Inc. + * Copyright (C) 2024-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -22,7 +22,6 @@ */ #include -#include #include "rtimer.h" #include "defercall.h" #include "handlerapp.h" @@ -53,7 +52,8 @@ int handler_main(int argc, char **argv) QCoreApplication qapp(argc, argv); HandlerAppMain appMain; - QTimer::singleShot(0, [&appMain]() {appMain.start();}); + DeferCall deferCall; + deferCall.defer([&] { appMain.start(); }); int ret = qapp.exec(); // ensure deferred deletes are processed diff --git a/src/handler/httpsession.cpp b/src/handler/httpsession.cpp index 14584fa2f..44b4c8682 100644 --- a/src/handler/httpsession.cpp +++ b/src/handler/httpsession.cpp @@ -206,6 +206,7 @@ class HttpSession::Private : public QObject Connection timerConnection; Connection retryTimerConnection; Connection messageFiltersFinishedConnection; + DeferCall deferCall; Private(HttpSession *_q, ZhttpRequest *_req, const HttpSession::AcceptData &_adata, const Instruct &_instruct, ZhttpManager *_outZhttp, StatsManager *_stats, RateLimiter *_updateLimiter, PublishLastIds *_publishLastIds, HttpSessionUpdateManager *_updateManager, int _connectionSubscriptionMax) : QObject(_q), @@ -1164,7 +1165,7 @@ class HttpSession::Private : public QObject if(!outZhttp) { errorMessage = "Instruct contained link, but handler not configured for outbound requests."; - QMetaObject::invokeMethod(this, "doError", Qt::QueuedConnection); + deferCall.defer([=] { doError(); }); return; } diff --git a/src/proxy/domainmap.cpp b/src/proxy/domainmap.cpp index 2109f2966..5119f80ef 100644 --- a/src/proxy/domainmap.cpp +++ b/src/proxy/domainmap.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2012-2022 Fanout, Inc. - * Copyright (C) 2023-2024 Fastly, Inc. + * Copyright (C) 2023-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -205,6 +205,7 @@ class DomainMap::Worker : public QObject RTimer t; Connection tConnection; QFileSystemWatcher watcher; + DeferCall deferCall; Worker() : watcher(this) @@ -292,7 +293,7 @@ class DomainMap::Worker : public QObject log_info("routes loaded with %d entries", allRules.count()); - QMetaObject::invokeMethod(this, "doChanged", Qt::QueuedConnection); + deferCall.defer([=] { doChanged(); }); } // mutex must be locked when calling this method @@ -312,11 +313,6 @@ class DomainMap::Worker : public QObject Signal changed; public slots: - void doChanged() - { - changed(); - } - void start() { if(!fileName.isEmpty()) @@ -719,6 +715,11 @@ public slots: return AddRuleOk; } + + void doChanged() + { + changed(); + } }; class DomainMap::Thread : public QThread diff --git a/src/proxy/main.cpp b/src/proxy/main.cpp index 37f125d47..b50605b92 100644 --- a/src/proxy/main.cpp +++ b/src/proxy/main.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 Fanout, Inc. + * Copyright (C) 2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -22,15 +23,13 @@ #include #include "app.h" +#include "defercall.h" -class AppMain : public QObject +class AppMain { - Q_OBJECT - public: App *app; -public slots: void start() { app = new App; @@ -53,10 +52,17 @@ int proxy_main(int argc, char **argv) QCoreApplication qapp(argc, argv); AppMain appMain; - QMetaObject::invokeMethod(&appMain, "start", Qt::QueuedConnection); - return qapp.exec(); -} + DeferCall deferCall; + deferCall.defer([&] { appMain.start(); }); + int ret = qapp.exec(); + + // ensure deferred deletes are processed + QCoreApplication::instance()->sendPostedEvents(); + // deinit here, after all event loop activity has completed + DeferCall::cleanup(); + + return ret; } -#include "main.moc" +} diff --git a/src/proxy/requestsession.cpp b/src/proxy/requestsession.cpp index 7c67074b2..791380291 100644 --- a/src/proxy/requestsession.cpp +++ b/src/proxy/requestsession.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2012-2023 Fanout, Inc. - * Copyright (C) 2024 Fastly, Inc. + * Copyright (C) 2024-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -36,6 +36,7 @@ #include "qtcompat.h" #include "bufferlist.h" #include "log.h" +#include "defercall.h" #include "layertracker.h" #include "sockjsmanager.h" #include "inspectdata.h" @@ -200,6 +201,7 @@ class RequestSession::Private : public QObject ZhttpReqConnections zhttpReqConnections; Connection inspectFinishedConnection; Connection acceptFinishedConnection; + DeferCall deferCall; Private(RequestSession *_q, int _workerId, DomainMap *_domainMap = 0, SockJsManager *_sockJsManager = 0, ZrpcManager *_inspectManager = 0, ZrpcChecker *_inspectChecker = 0, ZrpcManager *_acceptManager = 0, StatsManager *_stats = 0) : QObject(_q), @@ -308,7 +310,7 @@ class RequestSession::Private : public QObject isSockJs = true; sockJsManager->giveRequest(zhttpRequest, route.sockJsPath.length(), route.sockJsAsPath, route); zhttpRequest = 0; - QMetaObject::invokeMethod(this, "doFinished", Qt::QueuedConnection); + deferCall.defer([=] { doFinished(); }); return; } } @@ -480,7 +482,7 @@ class RequestSession::Private : public QObject if(!inspectRequest) { log_debug("inspect not available"); - QMetaObject::invokeMethod(this, "doInspectError", Qt::QueuedConnection); + deferCall.defer([=] { doInspectError(); }); } } } @@ -559,7 +561,7 @@ class RequestSession::Private : public QObject if(!pendingResponseUpdate) { pendingResponseUpdate = true; - QMetaObject::invokeMethod(this, "doResponseUpdate", Qt::QueuedConnection); + deferCall.defer([=] { doResponseUpdate(); }); } } diff --git a/src/proxy/sockjssession.cpp b/src/proxy/sockjssession.cpp index 3db6ba913..20c316c57 100644 --- a/src/proxy/sockjssession.cpp +++ b/src/proxy/sockjssession.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2015-2021 Fanout, Inc. - * Copyright (C) 2023-2024 Fastly, Inc. + * Copyright (C) 2023-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -34,6 +34,7 @@ #include "bufferlist.h" #include "packet/httprequestdata.h" #include "rtimer.h" +#include "defercall.h" #include "zhttprequest.h" #include "zwebsocket.h" #include "sockjsmanager.h" @@ -166,6 +167,7 @@ class SockJsSession::Private : public QObject map reqConnectionMap; WSConnections wsConnection; Connection keepAliveTimerConnection; + DeferCall deferCall; Private(SockJsSession *_q) : QObject(_q), @@ -589,7 +591,7 @@ class SockJsSession::Private : public QObject state = Idle; applyLinger(); cleanup(); - QMetaObject::invokeMethod(this, "doClosed", Qt::QueuedConnection); + deferCall.defer([=] { doClosed(); }); } else tryWrite(); @@ -850,7 +852,7 @@ class SockJsSession::Private : public QObject if(!updating) { updating = true; - QMetaObject::invokeMethod(this, "doUpdate", Qt::QueuedConnection); + deferCall.defer([=] { doUpdate(); }); } } diff --git a/src/proxy/testhttprequest.cpp b/src/proxy/testhttprequest.cpp index dfe363087..175c5ead0 100644 --- a/src/proxy/testhttprequest.cpp +++ b/src/proxy/testhttprequest.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 Fanout, Inc. + * Copyright (C) 2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -25,6 +26,7 @@ #include #include #include "log.h" +#include "defercall.h" #include "bufferlist.h" #include "packet/httprequestdata.h" #include "packet/httpresponsedata.h" @@ -53,6 +55,7 @@ class TestHttpRequest::Private : public QObject bool requestBodyFinished; BufferList responseBody; ErrorCondition errorCondition; + DeferCall deferCall; Private(TestHttpRequest *_q) : QObject(_q), @@ -209,7 +212,7 @@ void TestHttpRequest::writeBody(const QByteArray &body) if(d->requestBody.size() + body.size() > MAX_REQUEST_SIZE) { d->state = Private::Responding; - QMetaObject::invokeMethod(d, "processRequest", Qt::QueuedConnection); + d->deferCall.defer([=] { d->processRequest(); }); return; } @@ -219,7 +222,8 @@ void TestHttpRequest::writeBody(const QByteArray &body) { d->requestBody += buf; - QMetaObject::invokeMethod(this, "doBytesWritten", Qt::QueuedConnection, Q_ARG(int, buf.size())); + int written = buf.size(); + d->deferCall.defer([=] { d->doBytesWritten(written); }); } } } @@ -231,7 +235,7 @@ void TestHttpRequest::endBody() d->requestBodyFinished = true; d->state = Private::Responding; - QMetaObject::invokeMethod(d, "processRequest", Qt::QueuedConnection); + d->deferCall.defer([=] { d->processRequest(); }); } } diff --git a/src/proxy/testwebsocket.cpp b/src/proxy/testwebsocket.cpp index 417a32585..500861a2d 100644 --- a/src/proxy/testwebsocket.cpp +++ b/src/proxy/testwebsocket.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 Fanout, Inc. - * Copyright (C) 2023 Fastly, Inc. + * Copyright (C) 2023-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -27,6 +27,7 @@ #include #include #include +#include "defercall.h" #include "packet/httprequestdata.h" #include "packet/httpresponsedata.h" #include "statusreasons.h" @@ -55,6 +56,7 @@ class TestWebSocket::Private : public QObject int peerCloseCode; QString peerCloseReason; ErrorCondition errorCondition; + DeferCall deferCall; Private(TestWebSocket *_q) : QObject(_q), @@ -118,7 +120,7 @@ public slots: q->connected(); if(gripEnabled && !channels.isEmpty()) - QMetaObject::invokeMethod(this, "doReadyRead", Qt::QueuedConnection); + deferCall.defer([=] { doReadyRead(); }); } else { @@ -203,7 +205,7 @@ void TestWebSocket::start(const QUrl &uri, const HttpHeaders &headers) d->state = Private::Connecting; - QMetaObject::invokeMethod(d, "handleConnect", Qt::QueuedConnection); + d->deferCall.defer([=] { d->handleConnect(); }); } void TestWebSocket::respondSuccess(const QByteArray &reason, const HttpHeaders &headers) @@ -311,13 +313,14 @@ void TestWebSocket::writeFrame(const Frame &frame) d->inFrames += tmp; - QMetaObject::invokeMethod(d, "doFramesWritten", Qt::QueuedConnection, Q_ARG(int, 1), Q_ARG(int, tmp.data.size())); - QMetaObject::invokeMethod(d, "doReadyRead", Qt::QueuedConnection); + int contentBytesWritten = tmp.data.size(); + d->deferCall.defer([=] { d->doFramesWritten(1, contentBytesWritten); }); + d->deferCall.defer([=] { d->doReadyRead(); }); } WebSocket::Frame TestWebSocket::readFrame() { - QMetaObject::invokeMethod(d, "doWriteBytesChanged", Qt::QueuedConnection); + d->deferCall.defer([=] { d->doWriteBytesChanged(); }); return d->inFrames.takeFirst(); } @@ -328,7 +331,7 @@ void TestWebSocket::close(int code, const QString &reason) d->peerCloseCode = code; d->peerCloseReason = reason; - QMetaObject::invokeMethod(d, "handleClose", Qt::QueuedConnection); + d->deferCall.defer([=] { d->handleClose(); }); } #include "testwebsocket.moc" diff --git a/src/proxy/websocketoverhttp.cpp b/src/proxy/websocketoverhttp.cpp index d2c6abe38..c36672088 100644 --- a/src/proxy/websocketoverhttp.cpp +++ b/src/proxy/websocketoverhttp.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2014-2022 Fanout, Inc. - * Copyright (C) 2023-2024 Fastly, Inc. + * Copyright (C) 2023-2025 Fastly, Inc. * * This file is part of Pushpin. * @@ -34,6 +34,7 @@ #include "zhttpmanager.h" #include "uuidutil.h" #include "rtimer.h" +#include "defercall.h" #define BUFFER_SIZE 200000 #define FRAME_SIZE_MAX 16384 @@ -240,6 +241,7 @@ class WebSocketOverHttp::Private : public QObject ReqConnections reqConnections; Connection keepAliveTimerConnection; Connection retryTimerConnection; + DeferCall deferCall; Private(WebSocketOverHttp *_q) : QObject(_q), @@ -475,7 +477,7 @@ class WebSocketOverHttp::Private : public QObject if((int)pendingErrorCondition == -1) { pendingErrorCondition = e; - QMetaObject::invokeMethod(this, "doError", Qt::QueuedConnection); + deferCall.defer([=] { doError(); }); } } From 2bcd31d1925212b9636d2e3f4b0f084d9d4c7cfc Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Fri, 24 Jan 2025 13:20:15 -0800 Subject: [PATCH 2/2] remove unneeded slots declarations --- src/handler/deferred.h | 5 ++--- src/handler/httpsession.cpp | 2 -- src/proxy/requestsession.cpp | 1 - src/proxy/sockjssession.cpp | 1 - src/proxy/testhttprequest.cpp | 1 - src/proxy/testwebsocket.cpp | 1 - src/proxy/websocketoverhttp.cpp | 1 - 7 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/handler/deferred.h b/src/handler/deferred.h index f25feb412..2934d00ed 100644 --- a/src/handler/deferred.h +++ b/src/handler/deferred.h @@ -65,12 +65,11 @@ class Deferred : public QObject void setFinished(bool ok, const QVariant &value = QVariant()); -private slots: - void doFinish(); - private: DeferredResult result_; DeferCall deferCall_; + + void doFinish(); }; #endif diff --git a/src/handler/httpsession.cpp b/src/handler/httpsession.cpp index 44b4c8682..3fc095eaf 100644 --- a/src/handler/httpsession.cpp +++ b/src/handler/httpsession.cpp @@ -1458,7 +1458,6 @@ class HttpSession::Private : public QObject } } -private slots: void doError() { if(instruct.holdMode == Instruct::ResponseHold) @@ -1622,7 +1621,6 @@ private slots: } } -private: void timer_timeout() { if(instruct.holdMode == Instruct::ResponseHold) diff --git a/src/proxy/requestsession.cpp b/src/proxy/requestsession.cpp index 791380291..be7a4a0c6 100644 --- a/src/proxy/requestsession.cpp +++ b/src/proxy/requestsession.cpp @@ -975,7 +975,6 @@ class RequestSession::Private : public QObject } } -public slots: void doResponseUpdate() { pendingResponseUpdate = false; diff --git a/src/proxy/sockjssession.cpp b/src/proxy/sockjssession.cpp index 20c316c57..a49885a67 100644 --- a/src/proxy/sockjssession.cpp +++ b/src/proxy/sockjssession.cpp @@ -1046,7 +1046,6 @@ class SockJsSession::Private : public QObject q->error(); } -private slots: void doUpdate() { updating = false; diff --git a/src/proxy/testhttprequest.cpp b/src/proxy/testhttprequest.cpp index 175c5ead0..ee97a48cc 100644 --- a/src/proxy/testhttprequest.cpp +++ b/src/proxy/testhttprequest.cpp @@ -66,7 +66,6 @@ class TestHttpRequest::Private : public QObject { } -public slots: void doBytesWritten(int cnt){ q->bytesWritten(cnt); } diff --git a/src/proxy/testwebsocket.cpp b/src/proxy/testwebsocket.cpp index 500861a2d..25365a28a 100644 --- a/src/proxy/testwebsocket.cpp +++ b/src/proxy/testwebsocket.cpp @@ -68,7 +68,6 @@ class TestWebSocket::Private : public QObject { } -public slots: void handleConnect() { QString path = request.uri.path(); diff --git a/src/proxy/websocketoverhttp.cpp b/src/proxy/websocketoverhttp.cpp index c36672088..c8594eb9d 100644 --- a/src/proxy/websocketoverhttp.cpp +++ b/src/proxy/websocketoverhttp.cpp @@ -986,7 +986,6 @@ class WebSocketOverHttp::Private : public QObject q->error(); } -private slots: void keepAliveTimer_timeout() { update();