TestThreadSafeWeakPtr.cpp (3928B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/RefPtr.h" 8 #include "mozilla/ThreadSafeWeakPtr.h" 9 10 using mozilla::SupportsThreadSafeWeakPtr; 11 using mozilla::ThreadSafeWeakPtr; 12 13 // To have a class C support weak pointers, inherit from 14 // SupportsThreadSafeWeakPtr<C>. 15 class C : public SupportsThreadSafeWeakPtr<C> { 16 public: 17 MOZ_DECLARE_REFCOUNTED_TYPENAME(C) 18 19 int mNum; 20 21 C() : mNum(0) {} 22 23 ~C() { 24 // Setting mNum in the destructor allows us to test against use-after-free 25 // below 26 mNum = 0xDEAD; 27 } 28 29 void act() {} 30 }; 31 32 // Test that declaring a ThreadSafeWeakPtr pointing to an incomplete type 33 // builds. 34 class Incomplete; 35 class D { 36 ThreadSafeWeakPtr<Incomplete> mMember; 37 }; 38 39 int main() { 40 RefPtr<C> c1 = new C; 41 MOZ_RELEASE_ASSERT(c1->mNum == 0); 42 43 // Get weak pointers to c1. The first time, 44 // a reference-counted ThreadSafeWeakReference object is created that 45 // can live beyond the lifetime of 'c1'. The ThreadSafeWeakReference 46 // object will be notified of 'c1's destruction. 47 ThreadSafeWeakPtr<C> w1(c1); 48 { 49 RefPtr<C> s1(w1); 50 // Test a weak pointer for validity before using it. 51 MOZ_RELEASE_ASSERT(s1); 52 MOZ_RELEASE_ASSERT(s1 == c1); 53 s1->mNum = 1; 54 s1->act(); 55 } 56 57 // Test taking another ThreadSafeWeakPtr<C> to c1 58 ThreadSafeWeakPtr<C> w2(c1); 59 { 60 RefPtr<C> s2(w2); 61 MOZ_RELEASE_ASSERT(s2); 62 MOZ_RELEASE_ASSERT(s2 == c1); 63 MOZ_RELEASE_ASSERT(w1 == s2); 64 MOZ_RELEASE_ASSERT(s2->mNum == 1); 65 } 66 67 // Test that when a ThreadSafeWeakPtr is destroyed, it does not destroy the 68 // object that it points to, and it does not affect other ThreadSafeWeakPtrs 69 // pointing to the same object (e.g. it does not destroy the 70 // ThreadSafeWeakReference object). 71 { 72 ThreadSafeWeakPtr<C> w4local(c1); 73 MOZ_RELEASE_ASSERT(w4local == c1); 74 } 75 // Now w4local has gone out of scope. If that had destroyed c1, then the 76 // following would fail for sure (see C::~C()). 77 MOZ_RELEASE_ASSERT(c1->mNum == 1); 78 // Check that w4local going out of scope hasn't affected other 79 // ThreadSafeWeakPtr's pointing to c1 80 MOZ_RELEASE_ASSERT(w1 == c1); 81 MOZ_RELEASE_ASSERT(w2 == c1); 82 83 // Now construct another C object and test changing what object a 84 // ThreadSafeWeakPtr points to 85 RefPtr<C> c2 = new C; 86 c2->mNum = 2; 87 { 88 RefPtr<C> s2(w2); 89 MOZ_RELEASE_ASSERT(s2->mNum == 1); // w2 was pointing to c1 90 } 91 w2 = c2; 92 { 93 RefPtr<C> s2(w2); 94 MOZ_RELEASE_ASSERT(s2); 95 MOZ_RELEASE_ASSERT(s2 == c2); 96 MOZ_RELEASE_ASSERT(s2 != c1); 97 MOZ_RELEASE_ASSERT(w1 != s2); 98 MOZ_RELEASE_ASSERT(s2->mNum == 2); 99 } 100 101 // Destroying the underlying object clears weak pointers to it. 102 // It should not affect pointers that are not currently pointing to it. 103 c1 = nullptr; 104 { 105 RefPtr<C> s1(w1); 106 MOZ_RELEASE_ASSERT( 107 !s1, "Deleting an object should clear ThreadSafeWeakPtr's to it."); 108 MOZ_RELEASE_ASSERT(w1.IsDead(), "The weak pointer is now dead"); 109 MOZ_RELEASE_ASSERT(!w1.IsNull(), "The weak pointer isn't null"); 110 111 RefPtr<C> s2(w2); 112 MOZ_RELEASE_ASSERT(s2, 113 "Deleting an object should not clear ThreadSafeWeakPtr " 114 "that are not pointing to it."); 115 MOZ_RELEASE_ASSERT(!w2.IsDead(), "The weak pointer isn't dead"); 116 MOZ_RELEASE_ASSERT(!w2.IsNull(), "The weak pointer isn't null"); 117 } 118 119 c2 = nullptr; 120 { 121 RefPtr<C> s2(w2); 122 MOZ_RELEASE_ASSERT( 123 !s2, "Deleting an object should clear ThreadSafeWeakPtr's to it."); 124 MOZ_RELEASE_ASSERT(w2.IsDead(), "The weak pointer is now dead"); 125 MOZ_RELEASE_ASSERT(!w2.IsNull(), "The weak pointer isn't null"); 126 } 127 }