weak_ptr_ut.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #include <library/cpp/testing/gtest/gtest.h>
  2. #include <library/cpp/yt/memory/new.h>
  3. #include <library/cpp/yt/memory/weak_ptr.h>
  4. #include <array>
  5. namespace NYT {
  6. namespace {
  7. using ::testing::IsNull;
  8. using ::testing::NotNull;
  9. using ::testing::InSequence;
  10. using ::testing::MockFunction;
  11. using ::testing::StrictMock;
  12. ////////////////////////////////////////////////////////////////////////////////
  13. // Auxiliary types and functions.
  14. ////////////////////////////////////////////////////////////////////////////////
  15. static int ConstructorShadowState = 0;
  16. static int DestructorShadowState = 0;
  17. void ResetShadowState()
  18. {
  19. ConstructorShadowState = 0;
  20. DestructorShadowState = 0;
  21. }
  22. class TIntricateObject
  23. : public TRefCounted
  24. {
  25. public:
  26. TIntricateObject()
  27. {
  28. ++ConstructorShadowState;
  29. }
  30. virtual ~TIntricateObject()
  31. {
  32. ++DestructorShadowState;
  33. }
  34. // Prevent the counter from destruction by holding an additional
  35. // reference to the counter.
  36. void LockCounter()
  37. {
  38. WeakRef();
  39. }
  40. // Release an additional reference to the reference counter acquired by
  41. // #LockCounter().
  42. void UnlockCounter()
  43. {
  44. WeakUnref();
  45. }
  46. private:
  47. // Explicitly non-copyable.
  48. TIntricateObject(const TIntricateObject&);
  49. TIntricateObject(TIntricateObject&&);
  50. TIntricateObject& operator=(const TIntricateObject&);
  51. TIntricateObject& operator=(TIntricateObject&&);
  52. };
  53. using TIntricateObjectPtr = TIntrusivePtr<TIntricateObject>;
  54. using TIntricateObjectWkPtr = TWeakPtr<TIntricateObject>;
  55. class TDerivedIntricateObject
  56. : public TIntricateObject
  57. {
  58. private:
  59. // Payload.
  60. [[maybe_unused]] std::array<char, 32> Payload;
  61. };
  62. using TDerivedIntricateObjectPtr = TIntrusivePtr<TDerivedIntricateObject>;
  63. using TDerivedIntricateObjectWkPtr = TWeakPtr<TDerivedIntricateObject>;
  64. MATCHER_P2(HasRefCounts, strongRefs, weakRefs,
  65. "The object has "
  66. + ::testing::PrintToString(strongRefs) + " strong and "
  67. + ::testing::PrintToString(weakRefs) + " weak references")
  68. {
  69. Y_UNUSED(result_listener);
  70. return
  71. arg.GetRefCount() == strongRefs &&
  72. arg.GetWeakRefCount() == weakRefs;
  73. }
  74. template <class T>
  75. void PrintExtrinsicRefCounted(const T& arg, ::std::ostream* os)
  76. {
  77. *os << arg.GetRefCount() << " strong and "
  78. << arg.GetWeakRefCount() << " weak references";
  79. }
  80. void PrintTo(const TIntricateObject& arg, ::std::ostream* os)
  81. {
  82. PrintExtrinsicRefCounted(arg, os);
  83. }
  84. ////////////////////////////////////////////////////////////////////////////////
  85. class TWeakPtrTest
  86. : public ::testing::Test
  87. {
  88. public:
  89. virtual void SetUp()
  90. {
  91. ResetShadowState();
  92. }
  93. };
  94. TEST_F(TWeakPtrTest, Empty)
  95. {
  96. TIntricateObjectWkPtr emptyPointer;
  97. EXPECT_EQ(TIntricateObjectPtr(), emptyPointer.Lock());
  98. }
  99. TEST_F(TWeakPtrTest, Basic)
  100. {
  101. TIntricateObjectPtr object = New<TIntricateObject>();
  102. TIntricateObject* objectPtr = object.Get();
  103. EXPECT_THAT(*object, HasRefCounts(1, 1));
  104. {
  105. TIntricateObjectWkPtr ptr(objectPtr);
  106. EXPECT_THAT(*object, HasRefCounts(1, 2));
  107. EXPECT_EQ(object, ptr.Lock());
  108. }
  109. EXPECT_THAT(*object, HasRefCounts(1, 1));
  110. {
  111. TIntricateObjectWkPtr ptr(object);
  112. EXPECT_THAT(*object, HasRefCounts(1, 2));
  113. EXPECT_EQ(object, ptr.Lock());
  114. }
  115. EXPECT_THAT(*object, HasRefCounts(1, 1));
  116. object.Reset();
  117. EXPECT_EQ(1, ConstructorShadowState);
  118. EXPECT_EQ(1, DestructorShadowState);
  119. }
  120. TEST_F(TWeakPtrTest, ResetToNull)
  121. {
  122. TIntricateObjectPtr object = New<TIntricateObject>();
  123. TIntricateObjectWkPtr ptr(object);
  124. EXPECT_THAT(*object, HasRefCounts(1, 2));
  125. EXPECT_EQ(object, ptr.Lock());
  126. ptr.Reset();
  127. EXPECT_THAT(*object, HasRefCounts(1, 1));
  128. EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
  129. }
  130. TEST_F(TWeakPtrTest, ResetToOtherObject)
  131. {
  132. TIntricateObjectPtr firstObject = New<TIntricateObject>();
  133. TIntricateObjectPtr secondObject = New<TIntricateObject>();
  134. {
  135. TIntricateObjectWkPtr ptr(firstObject);
  136. EXPECT_THAT(*firstObject, HasRefCounts(1, 2));
  137. EXPECT_THAT(*secondObject, HasRefCounts(1, 1));
  138. EXPECT_EQ(firstObject, ptr.Lock());
  139. ptr.Reset(secondObject);
  140. EXPECT_THAT(*firstObject, HasRefCounts(1, 1));
  141. EXPECT_THAT(*secondObject, HasRefCounts(1, 2));
  142. EXPECT_EQ(secondObject, ptr.Lock());
  143. }
  144. TIntricateObject* firstObjectPtr = firstObject.Get();
  145. TIntricateObject* secondObjectPtr = secondObject.Get();
  146. {
  147. TIntricateObjectWkPtr ptr(firstObjectPtr);
  148. EXPECT_THAT(*firstObject, HasRefCounts(1, 2));
  149. EXPECT_THAT(*secondObject, HasRefCounts(1, 1));
  150. EXPECT_EQ(firstObject, ptr.Lock());
  151. ptr.Reset(secondObjectPtr);
  152. EXPECT_THAT(*firstObject, HasRefCounts(1, 1));
  153. EXPECT_THAT(*secondObject, HasRefCounts(1, 2));
  154. EXPECT_EQ(secondObject, ptr.Lock());
  155. }
  156. }
  157. TEST_F(TWeakPtrTest, CopySemantics)
  158. {
  159. TIntricateObjectPtr object = New<TIntricateObject>();
  160. TIntricateObjectWkPtr foo(object);
  161. {
  162. EXPECT_THAT(*object, HasRefCounts(1, 2));
  163. TIntricateObjectWkPtr bar(foo);
  164. EXPECT_THAT(*object, HasRefCounts(1, 3));
  165. EXPECT_EQ(object, foo.Lock());
  166. EXPECT_EQ(object, bar.Lock());
  167. }
  168. {
  169. EXPECT_THAT(*object, HasRefCounts(1, 2));
  170. TIntricateObjectWkPtr bar;
  171. bar = foo;
  172. EXPECT_THAT(*object, HasRefCounts(1, 3));
  173. EXPECT_EQ(object, foo.Lock());
  174. EXPECT_EQ(object, bar.Lock());
  175. }
  176. }
  177. TEST_F(TWeakPtrTest, MoveSemantics)
  178. {
  179. TIntricateObjectPtr object = New<TIntricateObject>();
  180. TIntricateObjectWkPtr foo(object);
  181. {
  182. EXPECT_THAT(*object, HasRefCounts(1, 2));
  183. TIntricateObjectWkPtr bar(std::move(foo));
  184. EXPECT_THAT(*object, HasRefCounts(1, 2));
  185. EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
  186. EXPECT_EQ(object, bar.Lock());
  187. }
  188. foo.Reset(object);
  189. {
  190. EXPECT_THAT(*object, HasRefCounts(1, 2));
  191. TIntricateObjectWkPtr bar;
  192. bar = std::move(foo);
  193. EXPECT_THAT(*object, HasRefCounts(1, 2));
  194. EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
  195. EXPECT_EQ(object, bar.Lock());
  196. }
  197. }
  198. TEST_F(TWeakPtrTest, OutOfScope)
  199. {
  200. TIntricateObjectWkPtr ptr;
  201. EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
  202. {
  203. TIntricateObjectPtr object = New<TIntricateObject>();
  204. ptr = object;
  205. EXPECT_EQ(object, ptr.Lock());
  206. }
  207. EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
  208. }
  209. TEST_F(TWeakPtrTest, OutOfNestedScope)
  210. {
  211. TIntricateObjectWkPtr foo;
  212. EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
  213. {
  214. TIntricateObjectPtr object = New<TIntricateObject>();
  215. foo = object;
  216. EXPECT_EQ(object, foo.Lock());
  217. {
  218. TIntricateObjectWkPtr bar;
  219. bar = object;
  220. EXPECT_EQ(object, bar.Lock());
  221. }
  222. EXPECT_EQ(object, foo.Lock());
  223. }
  224. EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
  225. EXPECT_EQ(1, ConstructorShadowState);
  226. EXPECT_EQ(1, DestructorShadowState);
  227. }
  228. TEST_F(TWeakPtrTest, IsExpired)
  229. {
  230. TIntricateObjectWkPtr ptr;
  231. EXPECT_TRUE(ptr.IsExpired());
  232. {
  233. TIntricateObjectPtr object = New<TIntricateObject>();
  234. ptr = object;
  235. EXPECT_FALSE(ptr.IsExpired());
  236. }
  237. EXPECT_TRUE(ptr.IsExpired());
  238. }
  239. TEST_F(TWeakPtrTest, IsEmpty)
  240. {
  241. TIntricateObjectWkPtr ptr;
  242. EXPECT_TRUE(ptr == nullptr);
  243. }
  244. TEST_F(TWeakPtrTest, UpCast)
  245. {
  246. TDerivedIntricateObjectPtr object = New<TDerivedIntricateObject>();
  247. TIntricateObjectWkPtr ptr = object;
  248. EXPECT_EQ(object.Get(), ptr.Lock().Get());
  249. }
  250. class TIntricateObjectVirtual
  251. : public virtual TRefCounted
  252. {
  253. public:
  254. TIntricateObjectVirtual()
  255. {
  256. ++ConstructorShadowState;
  257. }
  258. virtual ~TIntricateObjectVirtual()
  259. {
  260. ++DestructorShadowState;
  261. }
  262. // Prevent the counter from destruction by holding an additional
  263. // reference to the counter.
  264. void LockCounter()
  265. {
  266. WeakRef();
  267. }
  268. // Release an additional reference to the reference counter acquired by
  269. // #LockCounter().
  270. void UnlockCounter()
  271. {
  272. WeakUnref();
  273. }
  274. private:
  275. // Explicitly non-copyable.
  276. TIntricateObjectVirtual(const TIntricateObjectVirtual&);
  277. TIntricateObjectVirtual(TIntricateObjectVirtual&&);
  278. TIntricateObjectVirtual& operator=(const TIntricateObjectVirtual&);
  279. TIntricateObjectVirtual& operator=(TIntricateObjectVirtual&&);
  280. };
  281. TEST_F(TWeakPtrTest, VirtualBase)
  282. {
  283. auto object = New<TIntricateObjectVirtual>();
  284. TWeakPtr<TIntricateObjectVirtual> ptr = object;
  285. object.Reset();
  286. ptr.Reset();
  287. }
  288. #if 0
  289. class TSlowlyDyingObject
  290. : public TRefCounted
  291. {
  292. public:
  293. TSlowlyDyingObject()
  294. {
  295. ++ConstructorShadowState;
  296. }
  297. virtual ~TSlowlyDyingObject()
  298. {
  299. ++DestructorShadowState;
  300. DeathEvent->Wait();
  301. ++DestructorShadowState;
  302. }
  303. };
  304. void PrintTo(const TSlowlyDyingObject& arg, ::std::ostream* os)
  305. {
  306. PrintExtrinsicRefCounted(arg, os);
  307. }
  308. using TSlowlyDyingObjectPtr = TIntrusivePtr<TSlowlyDyingObject>;
  309. using TSlowlyDyingObjectWkPtr = TWeakPtr<TSlowlyDyingObject>;
  310. static void* AsynchronousDeleter(void* param)
  311. {
  312. TSlowlyDyingObjectPtr* indirectObject =
  313. reinterpret_cast<TSlowlyDyingObjectPtr*>(param);
  314. indirectObject->Reset();
  315. return nullptr;
  316. }
  317. std::unique_ptr<NThreading::TEvent> DeathEvent;
  318. TEST_F(TWeakPtrTest, DISABLED_AcquisionOfSlowlyDyingObject)
  319. {
  320. DeathEvent.reset(new NThreading::TEvent());
  321. TSlowlyDyingObjectPtr object = New<TSlowlyDyingObject>();
  322. TSlowlyDyingObjectWkPtr ptr(object);
  323. TSlowlyDyingObject* objectPtr = object.Get();
  324. EXPECT_EQ(object, ptr.Lock());
  325. EXPECT_THAT(*objectPtr, HasRefCounts(1, 2));
  326. ASSERT_EQ(1, ConstructorShadowState);
  327. ASSERT_EQ(0, DestructorShadowState);
  328. // Kick off object deletion in the background.
  329. TThread thread(&AsynchronousDeleter, &object);
  330. thread.Start();
  331. Sleep(TDuration::Seconds(0.100));
  332. ASSERT_EQ(1, ConstructorShadowState);
  333. ASSERT_EQ(1, DestructorShadowState);
  334. EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock());
  335. EXPECT_THAT(*objectPtr, HasRefCounts(0, 2));
  336. // Finalize object destruction.
  337. DeathEvent->NotifyAll();
  338. thread.Join();
  339. ASSERT_EQ(1, ConstructorShadowState);
  340. ASSERT_EQ(2, DestructorShadowState);
  341. EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock());
  342. }
  343. #endif
  344. ////////////////////////////////////////////////////////////////////////////////
  345. } // namespace
  346. } // namespace NYT