diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index f9547a4f9ef0..c5edae0b00b2 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -63,6 +63,7 @@ set( LIBRARIES lib-music-information-retrieval lib-crypto lib-fft + lib-concurrency ) if ( ${_OPT}use_lv2 ) diff --git a/libraries/lib-concurrency/CMakeLists.txt b/libraries/lib-concurrency/CMakeLists.txt new file mode 100644 index 000000000000..0ffc97525285 --- /dev/null +++ b/libraries/lib-concurrency/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-FileName: CMakeLists.txt +# SPDX-FileContributor: Dmitry Vedenko +#[[ +A set of concurrency primitives +]] + +set( SOURCES + concurrency/CancellationContext.cpp + concurrency/CancellationContext.h + concurrency/ICancellable.h +) +set( LIBRARIES + PUBLIC +) +audacity_library( lib-concurrency "${SOURCES}" "${LIBRARIES}" + "" "" ) diff --git a/libraries/lib-concurrency/concurrency/CancellationContext.cpp b/libraries/lib-concurrency/concurrency/CancellationContext.cpp new file mode 100644 index 000000000000..828f8eaca699 --- /dev/null +++ b/libraries/lib-concurrency/concurrency/CancellationContext.cpp @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * SPDX-FileName: CancellationContext.cpp + * SPDX-FileContributor: Dmitry Vedenko + */ + +#pragma once + +#include "CancellationContext.h" + +#include + +#include "ICancellable.h" + +namespace audacity::concurrency +{ +CancellationContext::CancellationContext(Tag) +{ +} + +std::shared_ptr CancellationContext::Create() +{ + return std::make_shared(Tag {}); +} + +void CancellationContext::Cancel() +{ + if (mCancelled.exchange(true)) + return; + + std::vector cancellableObjects; + + { + auto lock = std::lock_guard { mCancellableObjectsMutex }; + std::swap(cancellableObjects, mCancellableObjects); + } + + std::for_each( + cancellableObjects.begin(), cancellableObjects.end(), + [](auto& wptr) + { + if (auto lock = wptr.lock()) + lock->Cancel(); + }); +} + +void CancellationContext::OnCancelled(CancellableWPtr cancellable) +{ + auto locked = cancellable.lock(); + if (!locked) + return; + + if (mCancelled.load(std::memory_order_acquire)) + { + locked->Cancel(); + return; + } + + auto lock = std::lock_guard { mCancellableObjectsMutex }; + mCancellableObjects.erase( + std::remove_if( + mCancellableObjects.begin(), mCancellableObjects.end(), + [](auto& wptr) { return wptr.expired(); }), + mCancellableObjects.end()); + + mCancellableObjects.push_back(std::move(cancellable)); +} +} // namespace audacity::concurrency diff --git a/libraries/lib-concurrency/concurrency/CancellationContext.h b/libraries/lib-concurrency/concurrency/CancellationContext.h new file mode 100644 index 000000000000..d27a96cd18db --- /dev/null +++ b/libraries/lib-concurrency/concurrency/CancellationContext.h @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * SPDX-FileName: CancellationContext.h + * SPDX-FileContributor: Dmitry Vedenko + */ + +#pragma once + +#include +#include +#include +#include + +namespace audacity::concurrency +{ +class ICancellable; + +class CancellationContext; +using CancellationContextPtr = std::shared_ptr; + +class CONCURRENCY_API CancellationContext final +{ + struct Tag final + { + }; + +public: + explicit CancellationContext(Tag); + + CancellationContext(const CancellationContext&) = delete; + CancellationContext(CancellationContext&&) = delete; + CancellationContext& operator=(const CancellationContext&) = delete; + CancellationContext& operator=(CancellationContext&&) = delete; + + [[nodiscard]] static CancellationContextPtr Create(); + + void Cancel(); + + using CancellableWPtr = std::weak_ptr; + void OnCancelled(CancellableWPtr cancellable); + +private: + std::atomic mCancelled { false }; + + std::mutex mCancellableObjectsMutex; + std::vector mCancellableObjects; +}; // struct CancellationContext +} // namespace audacity::concurrency diff --git a/libraries/lib-concurrency/concurrency/ICancellable.h b/libraries/lib-concurrency/concurrency/ICancellable.h new file mode 100644 index 000000000000..83be9223b4a4 --- /dev/null +++ b/libraries/lib-concurrency/concurrency/ICancellable.h @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * SPDX-FileName: ICancellable.cpp + * SPDX-FileContributor: Dmitry Vedenko + */ + +#pragma once + +namespace audacity::concurrency +{ +class CONCURRENCY_API ICancellable +{ +public: + virtual ~ICancellable() = default; + + virtual void Cancel() = 0; +}; +} // namespace audacity::concurrency diff --git a/libraries/lib-network-manager/CMakeLists.txt b/libraries/lib-network-manager/CMakeLists.txt index 9799095c2a50..161e35a38dbc 100644 --- a/libraries/lib-network-manager/CMakeLists.txt +++ b/libraries/lib-network-manager/CMakeLists.txt @@ -39,13 +39,14 @@ set( SOURCES set ( LIBRARIES lib-string-utils-interface lib-preferences-interface + lib-concurrency-interface PRIVATE CURL::libcurl threadpool::threadpool lib-exceptions-interface ) -set ( DEFINES INTERFACE "HAS_NETWORKING" ) +set ( DEFINES INTERFACE "HAS_NETWORKING" PRIVATE "WIN32_LEAN_AND_MEAN" ) audacity_library( ${TARGET} "${SOURCES}" "${LIBRARIES}" "${DEFINES}" "" ) diff --git a/libraries/lib-network-manager/IResponse.cpp b/libraries/lib-network-manager/IResponse.cpp new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/libraries/lib-network-manager/IResponse.h b/libraries/lib-network-manager/IResponse.h index 3b00cf1bedef..dba3cad136e2 100644 --- a/libraries/lib-network-manager/IResponse.h +++ b/libraries/lib-network-manager/IResponse.h @@ -17,6 +17,8 @@ #include "NetworkManagerApi.h" +#include "concurrency/ICancellable.h" + namespace audacity { namespace network_manager @@ -107,7 +109,7 @@ enum //! Interface, that provides access to the data from the HTTP response -class NETWORK_MANAGER_API IResponse +class NETWORK_MANAGER_API IResponse : public concurrency::ICancellable { public: using RequestCallback = std::function; @@ -174,6 +176,11 @@ class NETWORK_MANAGER_API IResponse return result; } + + void Cancel() override + { + abort(); + } }; } diff --git a/libraries/lib-network-manager/curl/CurlResponseFactory.cpp b/libraries/lib-network-manager/curl/CurlResponseFactory.cpp index 8c5ba62e6041..26dcacbcb51a 100644 --- a/libraries/lib-network-manager/curl/CurlResponseFactory.cpp +++ b/libraries/lib-network-manager/curl/CurlResponseFactory.cpp @@ -7,15 +7,14 @@ Dmitry Vedenko **********************************************************************/ - #include "CurlResponseFactory.h" -#include - #include "CurlResponse.h" #include "MultipartData.h" #include "RequestPayload.h" +#include "ThreadPool/ThreadPool.h" + namespace audacity { namespace network_manager @@ -33,6 +32,10 @@ CurlResponseFactory::CurlResponseFactory () } +CurlResponseFactory::~CurlResponseFactory () +{ +} + void CurlResponseFactory::setProxy (const std::string& proxy) { mHandleManager->setProxy (proxy); diff --git a/libraries/lib-network-manager/curl/CurlResponseFactory.h b/libraries/lib-network-manager/curl/CurlResponseFactory.h index 40aaa18f339d..c785f6e19892 100644 --- a/libraries/lib-network-manager/curl/CurlResponseFactory.h +++ b/libraries/lib-network-manager/curl/CurlResponseFactory.h @@ -10,15 +10,13 @@ #pragma once -#include -#include #include -#include #include "../IResponseFactory.h" #include "CurlHandleManager.h" -#include "ThreadPool/ThreadPool.h" + +class ThreadPool; namespace audacity { @@ -29,6 +27,7 @@ class CurlResponseFactory final : public IResponseFactory { public: CurlResponseFactory (); + ~CurlResponseFactory (); void setProxy (const std::string& proxy) override;