atomic_intrusive_ptr_ut.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #include <library/cpp/testing/gtest/gtest.h>
  2. #include <library/cpp/yt/memory/new.h>
  3. #include <library/cpp/yt/memory/ref_counted.h>
  4. #include <library/cpp/yt/memory/atomic_intrusive_ptr.h>
  5. namespace NYT {
  6. namespace {
  7. ////////////////////////////////////////////////////////////////////////////////
  8. using ::testing::IsNull;
  9. using ::testing::NotNull;
  10. using ::testing::InSequence;
  11. using ::testing::MockFunction;
  12. using ::testing::StrictMock;
  13. ////////////////////////////////////////////////////////////////////////////////
  14. // Auxiliary types and functions.
  15. ////////////////////////////////////////////////////////////////////////////////
  16. // This object tracks number of increments and decrements
  17. // to the reference counter (see traits specialization below).
  18. struct TIntricateObject
  19. : private TNonCopyable
  20. {
  21. mutable int Increments = 0;
  22. mutable int Decrements = 0;
  23. mutable int Zeros = 0;
  24. void Ref(int n) const
  25. {
  26. Increments += n;
  27. }
  28. void Unref(int n) const
  29. {
  30. Decrements += n;
  31. if (Increments == Decrements) {
  32. ++Zeros;
  33. }
  34. }
  35. };
  36. using TIntricateObjectPtr = TIntrusivePtr<TIntricateObject>;
  37. using TConstIntricateObjectPtr = TIntrusivePtr<const TIntricateObject>;
  38. void Ref(TIntricateObject* obj, int n = 1)
  39. {
  40. obj->Ref(n);
  41. }
  42. void Unref(TIntricateObject* obj, int n = 1)
  43. {
  44. obj->Unref(n);
  45. }
  46. void Ref(const TIntricateObject* obj, int n = 1)
  47. {
  48. obj->Ref(n);
  49. }
  50. void Unref(const TIntricateObject* obj, int n = 1)
  51. {
  52. obj->Unref(n);
  53. }
  54. MATCHER_P3(HasRefCounts, increments, decrements, zeros,
  55. "Reference counter " \
  56. "was incremented " + ::testing::PrintToString(increments) + " times, " +
  57. "was decremented " + ::testing::PrintToString(decrements) + " times, " +
  58. "vanished to zero " + ::testing::PrintToString(zeros) + " times")
  59. {
  60. Y_UNUSED(result_listener);
  61. return
  62. arg.Increments == increments &&
  63. arg.Decrements == decrements &&
  64. arg.Zeros == zeros;
  65. }
  66. void PrintTo(const TIntricateObject& arg, ::std::ostream* os)
  67. {
  68. *os << arg.Increments << " increments, "
  69. << arg.Decrements << " decrements and "
  70. << arg.Zeros << " times vanished";
  71. }
  72. // This is an object which creates intrusive pointers to the self
  73. // during its construction.
  74. class TObjectWithSelfPointers
  75. : public TRefCounted
  76. {
  77. public:
  78. explicit TObjectWithSelfPointers(IOutputStream* output)
  79. : Output_(output)
  80. {
  81. *Output_ << "Cb";
  82. for (int i = 0; i < 3; ++i) {
  83. *Output_ << '!';
  84. TIntrusivePtr<TObjectWithSelfPointers> ptr(this);
  85. }
  86. *Output_ << "Ca";
  87. }
  88. virtual ~TObjectWithSelfPointers()
  89. {
  90. *Output_ << 'D';
  91. }
  92. private:
  93. IOutputStream* const Output_;
  94. };
  95. // This is a simple object with simple reference counting.
  96. class TObjectWithSimpleRC
  97. : public TRefCounted
  98. {
  99. public:
  100. explicit TObjectWithSimpleRC(IOutputStream* output)
  101. : Output_(output)
  102. {
  103. *Output_ << 'C';
  104. }
  105. virtual ~TObjectWithSimpleRC()
  106. {
  107. *Output_ << 'D';
  108. }
  109. void DoSomething()
  110. {
  111. *Output_ << '!';
  112. }
  113. private:
  114. IOutputStream* const Output_;
  115. };
  116. // This is a simple object with full-fledged reference counting.
  117. class TObjectWithFullRC
  118. : public TRefCounted
  119. {
  120. public:
  121. explicit TObjectWithFullRC(IOutputStream* output)
  122. : Output_(output)
  123. {
  124. *Output_ << 'C';
  125. }
  126. virtual ~TObjectWithFullRC()
  127. {
  128. *Output_ << 'D';
  129. }
  130. void DoSomething()
  131. {
  132. *Output_ << '!';
  133. }
  134. private:
  135. IOutputStream* const Output_;
  136. };
  137. ////////////////////////////////////////////////////////////////////////////////
  138. TEST(TAtomicPtrTest, Empty)
  139. {
  140. TIntricateObjectPtr emptyPointer;
  141. EXPECT_EQ(nullptr, emptyPointer.Get());
  142. }
  143. // Reserved ref count.
  144. constexpr int RRC = 65535;
  145. TEST(TAtomicPtrTest, Basic)
  146. {
  147. TIntricateObject object;
  148. EXPECT_THAT(object, HasRefCounts(0, 0, 0));
  149. {
  150. TIntricateObjectPtr owningPointer(&object);
  151. EXPECT_THAT(object, HasRefCounts(1, 0, 0));
  152. EXPECT_EQ(&object, owningPointer.Get());
  153. }
  154. EXPECT_THAT(object, HasRefCounts(1, 1, 1));
  155. {
  156. TIntricateObjectPtr owningPointer(&object);
  157. TAtomicIntrusivePtr<TIntricateObject> atomicPointer(owningPointer);
  158. EXPECT_THAT(object, HasRefCounts(2 + RRC, 1, 1));
  159. EXPECT_EQ(&object, owningPointer.Get());
  160. auto p1 = atomicPointer.Acquire();
  161. EXPECT_THAT(object, HasRefCounts(2 + RRC, 1, 1));
  162. p1.Reset();
  163. EXPECT_THAT(object, HasRefCounts(2 + RRC, 2, 1));
  164. owningPointer.Reset();
  165. EXPECT_THAT(object, HasRefCounts(2 + RRC, 3, 1));
  166. }
  167. EXPECT_THAT(object, HasRefCounts(2 + RRC, 2 + RRC, 2));
  168. }
  169. TEST(TAtomicPtrTest, BasicConst)
  170. {
  171. const TIntricateObject object;
  172. EXPECT_THAT(object, HasRefCounts(0, 0, 0));
  173. {
  174. TConstIntricateObjectPtr owningPointer(&object);
  175. EXPECT_THAT(object, HasRefCounts(1, 0, 0));
  176. EXPECT_EQ(&object, owningPointer.Get());
  177. }
  178. EXPECT_THAT(object, HasRefCounts(1, 1, 1));
  179. {
  180. TConstIntricateObjectPtr owningPointer(&object);
  181. TAtomicIntrusivePtr<const TIntricateObject> atomicPointer(owningPointer);
  182. EXPECT_THAT(object, HasRefCounts(2 + RRC, 1, 1));
  183. EXPECT_EQ(&object, owningPointer.Get());
  184. auto p1 = atomicPointer.Acquire();
  185. EXPECT_THAT(object, HasRefCounts(2 + RRC, 1, 1));
  186. p1.Reset();
  187. EXPECT_THAT(object, HasRefCounts(2 + RRC, 2, 1));
  188. owningPointer.Reset();
  189. EXPECT_THAT(object, HasRefCounts(2 + RRC, 3, 1));
  190. }
  191. EXPECT_THAT(object, HasRefCounts(2 + RRC, 2 + RRC, 2));
  192. }
  193. TEST(TAtomicPtrTest, Acquire)
  194. {
  195. TIntricateObject object;
  196. {
  197. TAtomicIntrusivePtr<TIntricateObject> atomicPtr{TIntricateObjectPtr(&object)};
  198. EXPECT_THAT(object, HasRefCounts(RRC, 0, 0));
  199. for (int i = 0; i < RRC / 2; ++i) {
  200. {
  201. auto tmp = atomicPtr.Acquire();
  202. EXPECT_THAT(object, HasRefCounts(RRC, i, 0));
  203. }
  204. EXPECT_THAT(object, HasRefCounts(RRC, i + 1, 0));
  205. }
  206. {
  207. auto tmp = atomicPtr.Acquire();
  208. EXPECT_THAT(object, HasRefCounts( RRC + RRC / 2, RRC - 1, 0));
  209. }
  210. EXPECT_THAT(object, HasRefCounts(RRC + RRC / 2, RRC, 0));
  211. }
  212. EXPECT_THAT(object, HasRefCounts(RRC + RRC / 2, RRC + RRC / 2, 1));
  213. }
  214. TEST(TAtomicPtrTest, AcquireConst)
  215. {
  216. const TIntricateObject object;
  217. {
  218. TAtomicIntrusivePtr<const TIntricateObject> atomicPtr{TConstIntricateObjectPtr(&object)};
  219. EXPECT_THAT(object, HasRefCounts(RRC, 0, 0));
  220. for (int i = 0; i < RRC / 2; ++i) {
  221. {
  222. auto tmp = atomicPtr.Acquire();
  223. EXPECT_THAT(object, HasRefCounts(RRC, i, 0));
  224. }
  225. EXPECT_THAT(object, HasRefCounts(RRC, i + 1, 0));
  226. }
  227. {
  228. auto tmp = atomicPtr.Acquire();
  229. EXPECT_THAT(object, HasRefCounts( RRC + RRC / 2, RRC - 1, 0));
  230. }
  231. EXPECT_THAT(object, HasRefCounts(RRC + RRC / 2, RRC, 0));
  232. }
  233. EXPECT_THAT(object, HasRefCounts(RRC + RRC / 2, RRC + RRC / 2, 1));
  234. }
  235. TEST(TAtomicPtrTest, CAS)
  236. {
  237. TIntricateObject o1;
  238. TIntricateObject o2;
  239. {
  240. TAtomicIntrusivePtr<TIntricateObject> atomicPtr{TIntricateObjectPtr(&o1)};
  241. EXPECT_THAT(o1, HasRefCounts(RRC, 0, 0));
  242. TIntricateObjectPtr p2(&o2);
  243. EXPECT_THAT(o2, HasRefCounts(1, 0, 0));
  244. void* rawPtr = &o1;
  245. EXPECT_TRUE(atomicPtr.CompareAndSwap(rawPtr, std::move(p2)));
  246. EXPECT_EQ(rawPtr, &o1);
  247. EXPECT_THAT(o1, HasRefCounts(RRC, RRC, 1));
  248. EXPECT_THAT(o2, HasRefCounts(RRC, 0, 0));
  249. rawPtr = nullptr;
  250. EXPECT_FALSE(atomicPtr.CompareAndSwap(rawPtr, TIntricateObjectPtr(&o1)));
  251. EXPECT_EQ(rawPtr, &o2);
  252. EXPECT_THAT(o1, HasRefCounts(2 * RRC, 2 * RRC, 2));
  253. EXPECT_THAT(o2, HasRefCounts(RRC, 0, 0));
  254. }
  255. EXPECT_THAT(o2, HasRefCounts(RRC, RRC, 1));
  256. }
  257. TEST(TAtomicPtrTest, CASConst)
  258. {
  259. const TIntricateObject o1;
  260. const TIntricateObject o2;
  261. {
  262. TAtomicIntrusivePtr<const TIntricateObject> atomicPtr{TConstIntricateObjectPtr(&o1)};
  263. EXPECT_THAT(o1, HasRefCounts(RRC, 0, 0));
  264. TConstIntricateObjectPtr p2(&o2);
  265. EXPECT_THAT(o2, HasRefCounts(1, 0, 0));
  266. const void* rawPtr = &o1;
  267. EXPECT_TRUE(atomicPtr.CompareAndSwap(rawPtr, std::move(p2)));
  268. EXPECT_EQ(rawPtr, &o1);
  269. EXPECT_THAT(o1, HasRefCounts(RRC, RRC, 1));
  270. EXPECT_THAT(o2, HasRefCounts(RRC, 0, 0));
  271. rawPtr = nullptr;
  272. EXPECT_FALSE(atomicPtr.CompareAndSwap(rawPtr, TConstIntricateObjectPtr(&o1)));
  273. EXPECT_EQ(rawPtr, &o2);
  274. EXPECT_THAT(o1, HasRefCounts(2 * RRC, 2 * RRC, 2));
  275. EXPECT_THAT(o2, HasRefCounts(RRC, 0, 0));
  276. }
  277. EXPECT_THAT(o2, HasRefCounts(RRC, RRC, 1));
  278. }
  279. ////////////////////////////////////////////////////////////////////////////////
  280. } // namespace
  281. } // namespace NYT