From 377f340d0b2ba2284889d09c65422ec124005f2d Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 1 Aug 2024 04:41:27 +0800 Subject: [PATCH] Fix #2060, make http request/respose reference counter thread-safe (#2064) --- core/base/Object.h | 33 ++++++++++++++++++++++++++++----- core/base/RefPtr.h | 11 ++++++----- core/base/Vector.h | 9 +++++---- core/network/HttpRequest.h | 22 +++++++++++++++++++++- core/network/HttpResponse.h | 2 +- 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/core/base/Object.h b/core/base/Object.h index a29383c52dcf..b617ffb0bd7c 100644 --- a/core/base/Object.h +++ b/core/base/Object.h @@ -163,15 +163,38 @@ typedef void (Object::*SEL_CallFuncO)(Object*); typedef void (Object::*SEL_MenuHandler)(Object*); typedef void (Object::*SEL_SCHEDULE)(float); -#define AX_CALLFUNC_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) -#define AX_CALLFUNCN_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) +#define AX_CALLFUNC_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) +#define AX_CALLFUNCN_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) #define AX_CALLFUNCND_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) -#define AX_CALLFUNCO_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) -#define AX_MENU_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) -#define AX_SCHEDULE_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) +#define AX_CALLFUNCO_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) +#define AX_MENU_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) +#define AX_SCHEDULE_SELECTOR(_SELECTOR) static_cast(&_SELECTOR) NS_AX_END // end of base group /** @} */ +namespace axstd +{ +template +struct is_ref_counted : std::false_type +{}; + +template +struct is_ref_counted_helper +{}; + +template +struct is_ref_counted<_Ty, + std::conditional_t().retain()), + decltype(std::declval<_Ty>().release()), + decltype(std::declval<_Ty>().getReferenceCount())>, + void>> : public std::true_type +{}; + +template +inline constexpr bool is_ref_counted_v = is_ref_counted>::value; +} // namespace axstd + #endif // __BASE_CCREF_H__ diff --git a/core/base/RefPtr.h b/core/base/RefPtr.h index 6a96f15c2e15..47be8c6304e9 100644 --- a/core/base/RefPtr.h +++ b/core/base/RefPtr.h @@ -2,6 +2,7 @@ Copyright (c) 2014 PlayFirst Inc. Copyright (c) 2014-2016 Chukong Technologies Inc. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). https://axmol.dev/ @@ -45,7 +46,7 @@ NS_AX_BEGIN { \ if (ptr) \ { \ - const_cast(static_cast(ptr))->retain(); \ + (ptr)->retain(); \ } \ \ } while (0); @@ -56,7 +57,7 @@ NS_AX_BEGIN { \ if (ptr) \ { \ - const_cast(static_cast(ptr))->release(); \ + (ptr)->release(); \ } \ \ } while (0); @@ -67,7 +68,7 @@ NS_AX_BEGIN { \ if (ptr) \ { \ - const_cast(static_cast(ptr))->release(); \ + (ptr)->release(); \ ptr = nullptr; \ } \ \ @@ -118,9 +119,9 @@ class RefPtr { if (other._ptr != _ptr) { - AX_REF_PTR_SAFE_RETAIN(other._ptr); AX_REF_PTR_SAFE_RELEASE(_ptr); _ptr = other._ptr; + AX_REF_PTR_SAFE_RETAIN(_ptr); } return *this; @@ -250,7 +251,7 @@ class RefPtr T* _ptr; // NOTE: We can ensure T is derived from ax::Object at compile time here. - static_assert(std::is_base_of::type>::value, "T must be derived from Object"); + static_assert(axstd::is_ref_counted_v::type>, "T must be derived from Object"); }; template diff --git a/core/base/Vector.h b/core/base/Vector.h index 55517e9cd89a..22c020fb04b1 100644 --- a/core/base/Vector.h +++ b/core/base/Vector.h @@ -3,6 +3,7 @@ Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2013-2017 Chukong Technologies Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. +Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). https://axmol.dev/ @@ -110,7 +111,7 @@ class Vector /** Constructor. */ Vector() : _data() { - static_assert(std::is_convertible::value, "Invalid Type for ax::Vector!"); + static_assert(axstd::is_ref_counted_v, "Invalid Type for ax::Vector!"); } /** @@ -119,7 +120,7 @@ class Vector */ explicit Vector(ssize_t capacity) : _data() { - static_assert(std::is_convertible::value, "Invalid Type for ax::Vector!"); + static_assert(axstd::is_ref_counted_v, "Invalid Type for ax::Vector!"); AXLOGV("In the default constructor with capacity of Vector."); reserve(capacity); } @@ -143,7 +144,7 @@ class Vector /** Copy constructor. */ Vector(const Vector& other) { - static_assert(std::is_convertible::value, "Invalid Type for ax::Vector!"); + static_assert(axstd::is_ref_counted_v, "Invalid Type for ax::Vector!"); AXLOGV("In the copy constructor!"); _data = other._data; addRefForAllObjects(); @@ -152,7 +153,7 @@ class Vector /** Constructor with std::move semantic. */ Vector(Vector&& other) { - static_assert(std::is_convertible::value, "Invalid Type for ax::Vector!"); + static_assert(axstd::is_ref_counted_v, "Invalid Type for ax::Vector!"); AXLOGV("In the move constructor of Vector!"); _data = std::move(other._data); } diff --git a/core/network/HttpRequest.h b/core/network/HttpRequest.h index 4d02abc29a25..985e0c9d960d 100644 --- a/core/network/HttpRequest.h +++ b/core/network/HttpRequest.h @@ -52,6 +52,26 @@ class HttpResponse; typedef std::function ccHttpRequestCallback; +class TSFRefCountedBase +{ +public: + TSFRefCountedBase() : _refCount(1) {} + virtual ~TSFRefCountedBase() {} + + void retain() { ++_refCount; } + + void release() + { + if (--_refCount == 0) + delete this; + } + + int getReferenceCount() const { return _refCount; } + +protected: + std::atomic_int _refCount; +}; + /** * Defines the object which users must packed for HttpClient::send(HttpRequest*) method. * Please refer to tests/test-cpp/Classes/ExtensionTest/NetworkTest/HttpClientTest.cpp as a sample @@ -60,7 +80,7 @@ typedef std::function ccHttpRe * @lua NA */ -class AX_DLL HttpRequest : public Object +class AX_DLL HttpRequest : public TSFRefCountedBase { friend class HttpClient; diff --git a/core/network/HttpResponse.h b/core/network/HttpResponse.h index e5991775e04f..dc2ce1ee919d 100644 --- a/core/network/HttpResponse.h +++ b/core/network/HttpResponse.h @@ -51,7 +51,7 @@ class HttpClient; * @since v2.0.2. * @lua NA */ -class AX_DLL HttpResponse : public ax::Object +class AX_DLL HttpResponse : public TSFRefCountedBase { friend class HttpClient;