1//
2// RefPtrTest.cpp
3//
4// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11
12#include "Poco/RefPtr.h"
13#include "Poco/WeakRefPtr.h"
14#include "Poco/NestedDiagnosticContext.h"
15#include "Poco/Stopwatch.h"
16#include "Poco/SharedPtr.h"
17#include "Poco/Thread.h"
18#include "Poco/AtomicCounter.h"
19#include "Poco/Mutex.h"
20#include "Poco/Runnable.h"
21#include "Poco/Event.h"
22#include <iostream>
23
24#include "Poco/CppUnit/TestCase.h"
25#include "RefPtrTest.h"
26#include "Poco/CppUnit/TestCaller.h"
27#include "Poco/CppUnit/TestSuite.h"
28
29using Poco::RefPtr;
30using Poco::RefPtr;
31using Poco::WeakRefPtr;
32using Poco::SharedPtr;
33using Poco::RefCountedObject;
34using Poco::RCO;
35using Poco::WeakRefCountedObject;
36using Poco::WRCO;
37using Poco::RCDC;
38using Poco::AtomicCounter;
39using Poco::Stopwatch;
40using Poco::Thread;
41using Poco::Runnable;
42using Poco::Event;
43using Poco::NullPointerException;
44using Poco::NDC;
45using Poco::Mutex;
46using Poco::WeakRefCounter;
47using Poco::Mutex;
48using Poco::FastMutex;
49using Poco::SpinlockMutex;
50using Poco::NullMutex;
51
52namespace
53{
54 class TestWeakObj: public WeakRefCountedObject
55 {
56 public:
57 TestWeakObj()
58 {
59 ++_count;
60 }
61
62 protected:
63 virtual ~TestWeakObj()
64 {
65 --_count;
66 }
67
68 private:
69 TestWeakObj(const TestWeakObj&);
70 TestWeakObj& operator=(const TestWeakObj&);
71 TestWeakObj(TestWeakObj&&);
72 TestWeakObj& operator=(TestWeakObj&&);
73
74 static AtomicCounter _count;
75 };
76
77 AtomicCounter TestWeakObj::_count(0);
78
79
80 class TestRefObj: public RefCountedObject
81 {
82 public:
83 TestRefObj()
84 {
85 ++_count;
86 }
87
88 protected:
89 virtual ~TestRefObj()
90 {
91 --_count;
92 }
93
94 private:
95 TestRefObj(const TestRefObj&);
96 TestRefObj& operator=(const TestRefObj&);
97 TestRefObj(TestRefObj&&);
98 TestRefObj& operator=(TestRefObj&&);
99
100 static AtomicCounter _count;
101 };
102
103 AtomicCounter TestRefObj::_count(0);
104
105
106 class TestObj
107 {
108 public:
109 TestObj(int id = 0): _rc(1), _id(id)
110 {
111 ++_count;
112 }
113
114 void duplicate()
115 {
116 ++_rc;
117 }
118
119 void release()
120 {
121 if (--_rc == 0) delete this;
122 }
123
124 int rc() const
125 {
126 return _rc;
127 }
128
129 static int count()
130 {
131 return _count;
132 }
133
134 int referenceCount()
135 {
136 return _rc.value();
137 }
138
139 int id()
140 {
141 return _id.load();
142 }
143
144 protected:
145 virtual ~TestObj()
146 {
147 --_count;
148 }
149
150 private:
151 TestObj(const TestObj&);
152 TestObj& operator=(const TestObj&);
153 TestObj(TestObj&&);
154 TestObj& operator=(TestObj&&);
155
156 AtomicCounter _rc;
157 std::atomic<int> _id;
158 static AtomicCounter _count;
159};
160
161AtomicCounter TestObj::_count(0);
162
163
164class TestParent1: virtual public WeakRefCountedObject
165{
166public:
167 typedef RefPtr<TestParent1> Ptr;
168
169 virtual int func() = 0;
170
171protected:
172 ~TestParent1() { }
173};
174
175class TestParent2: virtual public WeakRefCountedObject
176{
177public:
178 typedef RefPtr<TestParent2> Ptr;
179
180 virtual int func() = 0;
181
182protected:
183 ~TestParent2() { }
184};
185
186class TestIntermediate: public TestParent1, public TestParent2
187{
188public:
189 int func() { return 0; }
190 virtual int func1() { return 1; }
191};
192
193class TestChild: public TestIntermediate
194{
195public:
196 typedef RefPtr<TestChild> Ptr;
197
198 int func() { return -1; }
199
200 Ptr getRefPtr()
201 {
202 return Ptr(this, true);
203 }
204
205 void setParent1(TestParent1::Ptr parent1)
206 {
207 _parent1 = parent1;
208 }
209
210 TestParent1::Ptr getParent1()
211 {
212 return _parent1.lock();
213 }
214
215 WeakRefPtr<TestParent1> getWeakParent1()
216 {
217 return _parent1;
218 }
219
220 void setParent2(TestParent2::Ptr parent2)
221 {
222 _parent2 = parent2;
223 }
224
225 TestParent2::Ptr getParent2()
226 {
227 return _parent2.lock();
228 }
229
230 WeakRefPtr<TestParent2> getWeakParent2()
231 {
232 return _parent2;
233 }
234
235 Ptr selfFromThis()
236 {
237 return Ptr(this, true);
238 }
239
240 TestParent1::Ptr parent1FromThis()
241 {
242 return Ptr(this, true).cast<TestParent1>();
243 }
244
245 TestParent2::Ptr parent2FromThis()
246 {
247 return Ptr(this, true).cast<TestParent2>();
248 }
249
250protected:
251 ~TestChild()
252 {
253 int i = 0;
254 }
255
256private:
257 WeakRefPtr<TestParent1> _parent1;
258 WeakRefPtr<TestParent2> _parent2;
259};
260}
261
262
263RefPtrTest::RefPtrTest(const std::string& rName): CppUnit::TestCase(rName)
264{
265}
266
267
268RefPtrTest::~RefPtrTest()
269{
270}
271
272
273void RefPtrTest::testRefPtr()
274{
275 {
276 RefPtr<TestObj> ptr = new TestObj;
277 assertTrue (ptr->rc() == 1);
278 RefPtr<TestObj> ptr2 = ptr;
279 assertTrue (ptr->rc() == 2);
280 ptr2 = new TestObj;
281 assertTrue (ptr->rc() == 1);
282 RefPtr<TestObj> ptr3;
283 ptr3 = ptr2;
284 assertTrue (ptr2->rc() == 2);
285 ptr3 = new TestObj;
286 assertTrue (ptr2->rc() == 1);
287 ptr3 = ptr2;
288 assertTrue (ptr2->rc() == 2);
289 assertTrue (TestObj::count() > 0);
290 }
291 assertTrue (TestObj::count() == 0);
292}
293
294
295void RefPtrTest::testOps()
296{
297 RefPtr<TestObj> ptr1;
298 assertNull(ptr1.get());
299 TestObj* pTO1 = new TestObj;
300 TestObj* pTO2 = new TestObj;
301 if (pTO2 < pTO1)
302 {
303 TestObj* pTmp = pTO1;
304 pTO1 = pTO2;
305 pTO2 = pTmp;
306 }
307 assertTrue (pTO1 < pTO2);
308 ptr1 = pTO1;
309 RefPtr<TestObj> ptr2 = pTO2;
310 RefPtr<TestObj> ptr3 = ptr1;
311 RefPtr<TestObj> ptr4;
312 assertTrue (ptr1.get() == pTO1);
313 assertTrue (ptr1 == pTO1);
314 assertTrue (ptr2.get() == pTO2);
315 assertTrue (ptr2 == pTO2);
316 assertTrue (ptr3.get() == pTO1);
317 assertTrue (ptr3 == pTO1);
318
319 assertTrue (ptr1 == pTO1);
320 assertTrue (ptr1 != pTO2);
321 assertTrue (ptr1 < pTO2);
322 assertTrue (ptr1 <= pTO2);
323 assertTrue (ptr2 > pTO1);
324 assertTrue (ptr2 >= pTO1);
325
326 assertTrue (ptr1 == ptr3);
327 assertTrue (ptr1 != ptr2);
328 assertTrue (ptr1 < ptr2);
329 assertTrue (ptr1 <= ptr2);
330 assertTrue (ptr2 > ptr1);
331 assertTrue (ptr2 >= ptr1);
332
333 ptr1 = pTO1;
334 ptr2 = pTO2;
335 ptr1.swap(ptr2);
336 assertTrue (ptr2.get() == pTO1);
337 assertTrue (ptr1.get() == pTO2);
338
339 try
340 {
341 assertTrue (ptr4->rc() > 0);
342 fail ("must throw NullPointerException");
343 }
344 catch (NullPointerException&)
345 {
346 }
347
348 assertTrue (!(ptr4 == ptr1));
349 assertTrue (!(ptr4 == ptr2));
350 assertTrue (ptr4 != ptr1);
351 assertTrue (ptr4 != ptr2);
352
353 ptr4 = ptr2;
354 assertTrue (ptr4 == ptr2);
355 assertTrue (!(ptr4 != ptr2));
356
357 assertTrue (!(!ptr1));
358 ptr1 = 0;
359 assertTrue (!ptr1);
360}
361
362
363void RefPtrTest::testMove()
364{
365 TestObj* pObj = new TestObj;
366 RefPtr<TestObj> ptr1 = pObj;
367 RefPtr<TestObj> ptr2;
368
369 assertTrue (ptr2.isNull());
370 RefPtr<TestObj> ptr3 = std::move(ptr2);
371 assertTrue (ptr3.isNull());
372 assertTrue (ptr2.isNull());
373
374 assertTrue (!ptr1.isNull());
375 assertTrue (ptr1.get() == pObj);
376 assertTrue (ptr2.isNull());
377 ptr2 = std::move(ptr1);
378
379 assertTrue (ptr1.isNull());
380 assertTrue (ptr2.get() == pObj);
381 assertTrue (!ptr2.isNull());
382}
383
384
385TestChild* ptrChild = 0;
386
387RefPtr<TestChild> getObjPtr()
388{
389 return ptrChild = new TestChild;
390}
391
392RefPtr<TestChild> getObjRefPtr()
393{
394 RefPtr<TestChild> ptr = new TestChild;
395 return ptr;
396}
397
398
399struct AbstractNode : public WeakRefCountedObject
400{
401 RefPtr<AbstractNode> next;
402};
403
404
405struct AbstractContainerNode: public AbstractNode
406{
407 RefPtr<AbstractNode> first;
408};
409
410
411struct Element: public AbstractContainerNode
412{
413
414};
415
416void RefPtrTest::testInheritance()
417{
418 RefPtr<TestChild> child1 = new TestChild;
419 RefPtr<TestChild> child0 = new TestChild;
420
421 RefPtr<TestChild> first = child1;
422 WeakRefPtr<TestChild> next = first;
423 first = child0;
424 first = 0;
425 RefPtr<TestChild> child = new TestChild;
426 RefPtr<TestParent1> parent1;
427 parent1 = child;
428
429 assertTrue (!parent1.isNull());
430 assertTrue (parent1->func() == -1);
431
432 RefPtr<TestParent2> parent2;
433 parent2 = child;
434
435 assertTrue (!parent2.isNull());
436 assertTrue (parent2->func() == -1);
437
438 WeakRefPtr<TestChild> weakChild = child;
439 WeakRefPtr<TestParent1> weakParent1 = parent1;
440 WeakRefPtr<TestParent2> weakParent2(parent2);
441
442 assertTrue (!weakParent1.isNull());
443 assertTrue (weakParent1->func() == -1);
444
445 assertTrue (!weakParent2.isNull());
446 assertTrue (weakParent2->func() == -1);
447
448 parent1 = weakChild.lock();
449 parent2 = weakChild.lock();
450
451 assertTrue (!parent1.isNull());
452 assertTrue (parent1->func() == -1);
453
454 assertTrue (!parent2.isNull());
455 assertTrue (parent2->func() == -1);
456}
457
458
459void RefPtrTest::testMoveInherited()
460{
461 TestChild* pObj = new TestChild;
462 assertTrue (pObj->referenceCount() == 1);
463 RefPtr<TestChild> ptr1 = pObj;
464 ptr1 = ptr1;
465 assertTrue (ptr1->referenceCount() == 1);
466 assertTrue (!ptr1.isNull());
467 assertTrue (pObj->referenceCount() == 1);
468 ptr1 = std::move(ptr1);
469 assertTrue (ptr1->referenceCount() == 1);
470 assertTrue (!ptr1.isNull());
471 assertTrue (pObj->referenceCount() == 1);
472 RefPtr<TestChild> ptr2 = std::move(ptr1);
473 assertTrue (pObj->referenceCount() == 1);
474 assertTrue (ptr2->referenceCount() == 1);
475 assertTrue (ptr1.isNull());
476 ptr2 = std::move(ptr2);
477 assertTrue (pObj->referenceCount() == 1);
478 assertTrue (ptr2->referenceCount() == 1);
479 assertTrue (ptr1.isNull());
480
481 assertTrue (!ptr2.isNull());
482 assertTrue (ptr2.get() == pObj);
483 assertTrue (ptr1.isNull());
484
485 ptr1 = getObjPtr();
486 assertTrue (!ptr1.isNull());
487 assertTrue (ptr1.get() == ptrChild);
488 assertTrue (ptrChild->referenceCount() == 1);
489 ptr2 = ptr1;
490 assertTrue (!ptr2.isNull());
491 assertTrue (ptr2.get() == ptrChild);
492 assertTrue (ptrChild->referenceCount() == 2);
493
494 ptr1 = getObjRefPtr();
495 assertTrue (ptrChild->referenceCount() == 1);
496 assertTrue (ptr1->referenceCount() == 1);
497
498 RefPtr<TestParent1> parent1 = new TestChild;
499 assertTrue (parent1->referenceCount() == 1);
500 RefPtr<TestChild> child = parent1.cast<TestChild>();
501 assertTrue (parent1->referenceCount() == 2);
502 assertTrue (child->referenceCount() == 2);
503 RefPtr<TestParent2> parent2 = std::move(child);
504 assertTrue (child.isNull());
505 assertTrue (parent1->referenceCount() == 2);
506 parent1 = 0;
507 assertTrue (parent1.isNull());
508 assertTrue (parent2->referenceCount() == 1);
509 child = parent2.unsafeCast<TestChild>();
510 assertTrue (parent2->referenceCount() == 2);
511 assertTrue (child->referenceCount() == 2);
512 parent1 = child;
513 assertTrue (parent1->referenceCount() == 3);
514 assertTrue (child->referenceCount() == 3);
515 parent1 = std::move(parent1);
516 assertTrue (parent1->referenceCount() == 3);
517 assertTrue (child->referenceCount() == 3);
518
519 TestChild::Ptr child1 = child->getRefPtr();
520 assertTrue (child->referenceCount() == 4);
521
522 TestChild::Ptr child2 = child1;
523 assertTrue (child->referenceCount() == 5);
524 child1 = child2;
525 assertTrue (child->referenceCount() == 5);
526 assertTrue (child1->referenceCount() == 5);
527 assertTrue (child2->referenceCount() == 5);
528
529 child = 0;
530 assertTrue (child1->referenceCount() == 4);
531 assertTrue (child2->referenceCount() == 4);
532
533 child1 = 0;
534 assertTrue (child2->referenceCount() == 3);
535 assertTrue (parent1->referenceCount() == 3);
536 assertTrue (parent2->referenceCount() == 3);
537
538 child2 = 0;
539 assertTrue (parent1->referenceCount() == 2);
540 assertTrue (parent2->referenceCount() == 2);
541
542 parent1 = 0;
543 assertTrue (parent2->referenceCount() == 1);
544}
545
546
547void RefPtrTest::testWeakRefPtr()
548{
549 WeakRefPtr<TestWeakObj> toWPtr0;
550 assertTrue (toWPtr0.isNull());
551 assertTrue (!toWPtr0.lock());
552 {
553 RefPtr<TestWeakObj> toPtr;
554 assertTrue (toPtr.isNull());
555 toWPtr0 = toPtr;
556 assertTrue (toWPtr0.isNull());
557 {
558 toPtr = new TestWeakObj;
559 assertTrue (toPtr->referenceCount() == 1);
560 toWPtr0 = toPtr;
561 assertTrue (!toWPtr0.isNull());
562 assertTrue (toWPtr0.referenceCount() == 1);
563
564 WeakRefPtr<TestWeakObj> toWPtr = toPtr;
565 assertTrue (toPtr->referenceCount() == 1);
566 {
567 if (auto l = toWPtr.lock())
568 assertTrue (toPtr->referenceCount() == 2);
569 else
570 fail ("1 WeakRefPtr failed to lock!");
571 }
572 assertTrue (toPtr->referenceCount() == 1);
573 }
574 assertTrue (!toPtr.isNull());
575 assertTrue (toPtr->referenceCount() == 1);
576 }
577 assertTrue (toWPtr0.isNull());
578 assertTrue (!toWPtr0.lock());
579
580 TestChild::Ptr child = new TestChild;
581 assertTrue (child->referenceCount() == 1);
582 child->setParent1(child); // be one's self weak parent
583 assertTrue (child->referenceCount() == 1);
584 WeakRefPtr<TestParent1> wp1 = child->getWeakParent1();
585 assertTrue (child->referenceCount() == 1);
586 {
587 if (auto l = wp1.lock())
588 {
589 assertTrue (child->referenceCount() == 2);
590 assertTrue(-1 == wp1->func());
591 }
592 else
593 fail ("2 WeakRefPtr failed to lock!");
594 }
595 assertTrue (child->referenceCount() == 1);
596
597 child->setParent2(child); // another weak self-parent
598 assertTrue (child->referenceCount() == 1);
599 WeakRefPtr<TestParent2> wp2 = child->getWeakParent2();
600 assertTrue (child->referenceCount() == 1);
601 {
602 if (auto l = wp2.lock())
603 {
604 assertTrue (child->referenceCount() == 2);
605 assertTrue(-1 == wp2->func());
606 }
607 else
608 fail ("3 WeakRefPtr failed to lock!");
609 }
610 assertTrue (child->referenceCount() == 1);
611
612 {
613 TestParent1::Ptr ap1 = child->getParent1();
614 assertTrue (ap1 == child.cast<TestParent1>());
615 }
616
617 TestChild::Ptr child2 = new TestChild;
618 assertTrue (child2->referenceCount() == 1);
619 child->setParent1(child2);
620 assertTrue (child2->referenceCount() == 1);
621 TestParent1::Ptr tp1 = child->getParent1();
622 assertTrue (tp1 == child->getParent1());
623
624 WeakRefPtr<TestChild> wpChild = child->selfFromThis();
625 assertTrue (child->referenceCount() == 1);
626 assertTrue (!wpChild.isNull());
627 assertTrue (!wpChild.lock().isNull());
628
629 WeakRefPtr<TestChild> wpChild1 = child->parent1FromThis().cast<TestChild>();
630 assertTrue (child->referenceCount() == 1);
631 assertTrue (!wpChild1.isNull());
632 assertTrue (!wpChild1.lock().isNull());
633
634 WeakRefPtr<TestChild> wpChild2 = child->parent2FromThis().cast<TestChild>();
635 assertTrue (child->referenceCount() == 1);
636 assertTrue (!wpChild2.isNull());
637 assertTrue (!wpChild2.lock().isNull());
638}
639
640
641void RefPtrTest::testWeakSemantics()
642{
643 /// The weak pointer integrity is preserved
644 /// when the holding RefPtr is deleted.
645 {
646 WeakRefPtr<TestWeakObj> weak;
647 assertTrue (weak.isNull());
648 assertTrue (!weak.lock());
649 {
650 RefPtr<TestWeakObj> original = new TestWeakObj;
651 assertTrue (weak.isNull());
652 assertTrue (!weak.lock());
653
654 weak = original;
655 assertTrue(!weak.isNull());
656 RefPtr<TestWeakObj> locked = weak.lock();
657 assertTrue(!locked.isNull());
658 assertTrue(locked == original);
659 }
660 assertTrue (weak.isNull());
661 assertTrue (!weak.lock());
662 }
663
664 // RefPtr does not affect the WeakRefPtr in any
665 // other way, but by invalidating the pointed-to
666 // reference when strong count expires
667
668 // copy/assign
669 {
670 RefPtr<TestWeakObj> original = new TestWeakObj;
671 assertTrue (original->referenceCount() == 1);
672 WeakRefPtr<TestWeakObj> weak = original;
673 assertTrue (original->referenceCount() == 1);
674 RefPtr<TestWeakObj> locked = weak.lock();
675 assertTrue (original->referenceCount() == 2);
676 assertTrue (locked->referenceCount() == 2);
677 assertTrue(!locked.isNull());
678 assertTrue(locked == original);
679
680 RefPtr<TestWeakObj> copied = original;
681 assertTrue (original->referenceCount() == 3);
682 assertTrue (locked->referenceCount() == 3);
683 assertTrue (copied->referenceCount() == 3);
684 assertTrue(!weak.isNull());
685 locked = weak.lock();
686 assertTrue (original->referenceCount() == 3);
687 assertTrue (locked->referenceCount() == 3);
688 assertTrue(!locked.isNull());
689 assertTrue(locked == original);
690 assertTrue(locked.get() == original.get());
691 assertTrue(locked == copied);
692 assertTrue(locked.get() == copied.get());
693 original = 0;
694 assertTrue (locked->referenceCount() == 2);
695 assertTrue (copied->referenceCount() == 2);
696 assertTrue(!weak.isNull());
697 assertTrue(!weak.lock().isNull());
698 copied = 0;
699 assertTrue (locked->referenceCount() == 1);
700 assertTrue(!weak.isNull());
701 assertTrue(!weak.lock().isNull());
702 locked = 0;
703 assertTrue(weak.isNull());
704 assertTrue(weak.lock().isNull());
705
706 }
707
708 // moving
709 {
710 RefPtr<TestWeakObj> original = new TestWeakObj;
711
712 WeakRefPtr<TestWeakObj> weak = original;
713 assertTrue(!weak.isNull());
714 RefPtr<TestWeakObj> locked = weak.lock();
715 assertTrue(!locked.isNull());
716 assertTrue(locked == original);
717
718 RefPtr<TestWeakObj> moved = std::move(original);
719 assertTrue(!weak.isNull());
720 locked = weak.lock();
721 assertTrue(!locked.isNull());
722 assertTrue(locked == moved);
723 }
724}
725
726
727// threads
728
729
730namespace {
731
732 class RefPtrRunnable:public Runnable
733 {
734 public:
735 class Dummy: public RCO {};
736 class WeakDummy: public WeakRefCountedObject {};
737
738 RefPtrRunnable(): _errors(0), _msWeak(0) {}
739
740 void run()
741 {
742 work();
743 work<WeakDummy>(_wrco, _msWeak);
744 }
745
746 int64_t errors() const { return _errors.value(); }
747 int64_t msWeak() const { return _msWeak.load(); }
748
749 static const int _size = 10;
750 static Dummy* _rco[_size];
751 static WeakDummy* _wrco[_size];
752
753 private:
754 typedef std::atomic<unsigned long> TimerType;
755
756 void work()
757 {
758 RefPtr<Dummy> ptr;
759 for (int i = 0; i < _size; ++i)
760 {
761 ptr = RefPtr<Dummy>(_rco[i], true);
762 if (!ptr) ++_errors;
763 RefPtr<Dummy> ptr2 = ptr;
764 if (!ptr2) ++_errors;
765 RefPtr<Dummy> ptr3 = std::move(ptr2);
766 if (!ptr2.isNull()) ++_errors;
767 if (!ptr3) ++_errors;
768 }
769 }
770
771 template <typename T>
772 void work(T** rco, TimerType& timer)
773 {
774 Stopwatch sw; sw.start();
775 WeakRefPtr<T> wptr;
776 {
777 if(wptr.lock()) ++_errors;
778 RefPtr<T> ptr;
779 for(int i = 0; i < _size; ++i)
780 {
781 ptr = RefPtr<T>(rco[i], true);
782 if(!ptr) ++_errors;
783 wptr = ptr;
784 if(!wptr.lock()) ++_errors;
785 }
786 }
787 // originals must be still alive
788 if (!wptr.lock() || wptr.referenceCount() < 1) ++_errors;
789 sw.stop(); timer += sw.elapsed();
790 }
791
792 AtomicCounter _errors;
793 TimerType _msWeak;
794 };
795
796 RefPtrRunnable::Dummy* RefPtrRunnable::_rco[RefPtrRunnable::_size] = {0};
797 RefPtrRunnable::WeakDummy* RefPtrRunnable::_wrco[RefPtrRunnable::_size] = {0};
798}
799
800
801void RefPtrTest::testRefPtrThread()
802{
803 const int num = RefPtrRunnable::_size;
804
805 for (int i = 0; i < num; ++i)
806 {
807 RefPtrRunnable::_rco[i] = new RefPtrRunnable::Dummy;
808 RefPtrRunnable::_wrco[i] = new RefPtrRunnable::WeakDummy;
809 }
810
811 std::vector<Thread*> threads;
812 std::vector<RefPtrRunnable*> runnables;
813 for (int i = 0; i < num; ++i)
814 {
815 threads.push_back(new Thread());
816 runnables.push_back(new RefPtrRunnable());
817 }
818
819 int i = 0;
820 for (auto& t : threads)
821 {
822 t->start(*runnables[i++]);
823 }
824
825 for (auto& t : threads)
826 {
827 t->join();
828 delete t;
829 }
830
831 std::cout << num << " threads, " << num << " loops/thread" << std::endl;
832 double weak = 0;
833 for (auto& r : runnables)
834 {
835 assertTrue(r->errors() == 0);
836 weak += r->msWeak();
837 delete r;
838 }
839 std::cout << "WeakRefPtr (avg. ms): "
840 << weak/num << " us" << std::endl;
841
842 for (int i = 0; i < num; ++i)
843 {
844 assertTrue (RefPtrRunnable::_rco[i]->referenceCount() == 1);
845 assertTrue (RefPtrRunnable::_wrco[i]->referenceCount() == 1);
846 delete RefPtrRunnable::_rco[i];
847 delete RefPtrRunnable::_wrco[i];
848 }
849}
850
851
852// casting with multiple virtual inheritance
853
854namespace {
855
856struct A:public WeakRefCountedObject
857{
858 virtual ~A() { }
859};
860
861struct B:virtual public A { };
862struct C:virtual public A { };
863struct D:public B, public C { };
864struct E:public D { };
865
866}
867
868
869void RefPtrTest::testWeakLeak()
870{
871 {
872 E* e = new E;
873 e->release();
874 e = new E;
875 delete e;
876 WeakRefPtr<E> we(new E);
877 }
878 // there should be no leak reports for this,
879 // valgrind, or refcount DC (if enabled)
880}
881
882
883void RefPtrTest::testWeakCast()
884{
885 RefPtr<E> e = new E;
886 WeakRefPtr<E> weakE = e;
887 RefPtr<A> a = e.cast<A>();
888 WeakRefPtr<A> weakA = a;
889 RefPtr<B> b = e.cast<B>();
890 WeakRefPtr<B> weakB = b;
891 RefPtr<C> c = e.cast<C>();
892 WeakRefPtr<C> weakC = c;
893 RefPtr<D> d = c.cast<D>();
894 WeakRefPtr<D> weakD = d;
895
896 // check construction/assignment/cast locked RefPtr
897 {
898 RefPtr<E> e1(weakE);
899 RefPtr<E> e2 = weakE;
900 e = weakE;
901 e = weakA.lock().cast<E>();
902 e = weakB.lock().cast<E>();
903 e = weakC.lock().cast<E>();
904 e = weakD.lock().cast<E>();
905 a = weakA;
906 b = weakB;
907 c = weakC;
908 d = weakD;
909 }
910
911 // destroy all RefPtr's in random order
912 b = 0;
913 assertTrue (!weakB.isNull());
914 assertTrue (!weakB.lock().isNull());
915 a = 0;
916 assertTrue (!weakA.isNull());
917 assertTrue (!weakA.lock().isNull());
918 e = 0;
919 assertTrue (!weakE.isNull());
920 assertTrue (!weakE.lock().isNull());
921 d = 0;
922 assertTrue (!weakD.isNull());
923 assertTrue (!weakD.lock().isNull());
924 c = 0;
925 assertTrue (weakB.isNull());
926 assertTrue (weakB.lock().isNull());
927 assertTrue (weakC.isNull());
928 assertTrue (weakC.lock().isNull());
929 assertTrue (weakD.isNull());
930 assertTrue (weakD.lock().isNull());
931 assertTrue (weakE.isNull());
932 assertTrue (weakE.lock().isNull());
933}
934
935
936// benchmark
937
938#if (defined(POCO_COMPILER_GCC) || defined(POCO_COMPILER_CLANG)) && (POCO_ARCH == POCO_ARCH_AMD64)
939
940#define REF_PTR_BENCHMARK
941
942#endif
943
944#ifdef REF_PTR_BENCHMARK
945
946namespace {
947
948 template<typename T>
949 void use(T &&t) {
950 __asm__ __volatile__ (""::"g" (t));
951 }
952
953 void escape(void*p) {
954 __asm__ __volatile__ ("" : "+r" (p)::"memory");
955 }
956
957 void clobber() {
958 __asm__ __volatile__ ("" : : : "memory");
959 }
960
961}
962
963namespace unopt {
964
965 extern void unoptimizer();
966
967}
968
969namespace {
970
971 void unoptimize()
972 {
973 int v[1];
974 escape(v);
975 use(v);
976 v[0] = 42;
977 unopt::unoptimizer();
978 clobber();
979 }
980
981 struct DummyImpl
982 {
983 void dummy()
984 {
985 unoptimize();
986 }
987
988 DummyImpl& operator++()
989 {
990 unoptimize();
991 return *this;
992 }
993
994 DummyImpl& operator++(int)
995 {
996 unoptimize();
997 return *this;
998 }
999
1000 DummyImpl& operator--()
1001 {
1002 unoptimize();
1003 return *this;
1004 }
1005
1006 DummyImpl& operator--(int)
1007 {
1008 unoptimize();
1009 return *this;
1010 }
1011 };
1012
1013 struct Dummy: public DummyImpl, public RefCountedObject
1014 {
1015 };
1016
1017 struct WeakDummy: public DummyImpl, public WeakRefCountedObject
1018 {
1019 };
1020
1021 template<typename P>
1022 void ops(P* p)
1023 {
1024 ++(**p);
1025 --(**p);
1026 (**p)++;
1027 (**p)--;
1028 }
1029
1030 template<typename P>
1031 void doWork(P* p)
1032 {
1033 (*p)->dummy();
1034 ops(p);
1035 }
1036
1037 template<>
1038 void doWork(int* p)
1039 {
1040 unoptimize();
1041 ops(&p);
1042 }
1043
1044 template<>
1045 void doWork(std::unique_ptr<int>* p)
1046 {
1047 unoptimize();
1048 ops(p);
1049 }
1050
1051 template<>
1052 void doWork(std::shared_ptr<int>* p)
1053 {
1054 unoptimize();
1055 ops(p);
1056 }
1057
1058 template<>
1059 void doWork(SharedPtr<int>* p)
1060 {
1061 unoptimize();
1062 ops(p);
1063 }
1064
1065
1066 template<typename F, typename T>
1067 void runBenchmark(int reps)
1068 {
1069 Stopwatch sw;
1070 sw.start();
1071 for(int r = 0; r < reps; ++r)
1072 {
1073 T p(new F);
1074 doWork(&p);
1075 }
1076 sw.stop();
1077 std::cout << '\t' << NDC::typeName<T>() << " : " << sw.elapsed() / 1000 << " ms" << std::endl;
1078 }
1079
1080
1081 template<>
1082 void runBenchmark<Dummy, Dummy*>(int reps)
1083 {
1084 Stopwatch sw;
1085 sw.start();
1086 for(int r = 0; r < reps; ++r)
1087 {
1088 Dummy*p = new Dummy;
1089 doWork(&p);
1090 delete p;
1091 }
1092 sw.stop();
1093 std::cout << '\t' << NDC::typeName<Dummy*>() << " : " << sw.elapsed() / 1000 << " ms" << std::endl;
1094 }
1095
1096
1097 template<>
1098 void runBenchmark<int, int*>(int reps)
1099 {
1100 Stopwatch sw;
1101 sw.start();
1102 for(int r = 0; r < reps; ++r)
1103 {
1104 int*p = new int;
1105 doWork(p);
1106 delete p;
1107 }
1108 sw.stop();
1109 std::cout << '\t' << NDC::typeName<int*>() << " : " << sw.elapsed() / 1000 << " ms" << std::endl;
1110 }
1111}
1112
1113#endif // REF_PTR_BENCHMARK
1114
1115
1116void RefPtrTest::pointersBenchmark()
1117{
1118#ifdef REF_PTR_BENCHMARK
1119
1120 int reps = 100;//0000;
1121 std::cout << reps << " repetitions" << std::endl;
1122 std::cout << std::endl;
1123
1124 runBenchmark<int, int*>(reps);
1125 runBenchmark<int, std::unique_ptr<int>>(reps);
1126 runBenchmark<int, std::shared_ptr<int>>(reps);
1127 runBenchmark<int, SharedPtr<int>>(reps);
1128 std::cout << std::endl;
1129
1130 runBenchmark<Dummy, Dummy*>(reps);
1131 runBenchmark<Dummy, RefPtr<Dummy>>(reps);
1132 runBenchmark<WeakDummy, RefPtr<WeakDummy>>(reps);
1133 runBenchmark<Dummy, SharedPtr<Dummy>>(reps);
1134 runBenchmark<Dummy, std::unique_ptr<Dummy>>(reps);
1135 runBenchmark<Dummy, std::shared_ptr<Dummy>>(reps);
1136
1137#endif // REF_PTR_BENCHMARK
1138}
1139
1140
1141void RefPtrTest::setUp()
1142{
1143}
1144
1145
1146void RefPtrTest::tearDown()
1147{
1148}
1149
1150
1151CppUnit::Test* RefPtrTest::suite()
1152{
1153 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RefPtrTest");
1154
1155 CppUnit_addTest(pSuite, RefPtrTest, testRefPtr);
1156 CppUnit_addTest(pSuite, RefPtrTest, testInheritance);
1157 CppUnit_addTest(pSuite, RefPtrTest, testOps);
1158 CppUnit_addTest(pSuite, RefPtrTest, testMove);
1159 CppUnit_addTest(pSuite, RefPtrTest, testMoveInherited);
1160 CppUnit_addTest(pSuite, RefPtrTest, testWeakRefPtr);
1161 CppUnit_addTest(pSuite, RefPtrTest, testWeakSemantics);
1162 CppUnit_addTest(pSuite, RefPtrTest, testWeakLeak);
1163 CppUnit_addTest(pSuite, RefPtrTest, testWeakCast);
1164 CppUnit_addTest(pSuite, RefPtrTest, testRefPtrThread);
1165 //CppUnit_addTest(pSuite, RefPtrTest, pointersBenchmark);
1166
1167 return pSuite;
1168}
1169