• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "refbase.h"
17 
18 namespace OHOS {
19 
WeakRefCounter(RefCounter * counter,void * cookie)20 WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie)
21     : atomicWeak_(0), refCounter_(counter), cookie_(cookie)
22 {
23     if (refCounter_ != nullptr) {
24         refCounter_->IncRefCount();
25     }
26 }
27 
~WeakRefCounter()28 WeakRefCounter::~WeakRefCounter()
29 {
30     if (refCounter_ != nullptr) {
31         refCounter_->DecRefCount();
32     }
33 }
34 
GetRefPtr()35 void* WeakRefCounter::GetRefPtr()
36 {
37     if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())){
38         cookie_ = nullptr;
39     }
40     return cookie_;
41 }
42 
IncWeakRefCount(const void * objectId)43 void WeakRefCounter::IncWeakRefCount(const void *objectId)
44 {
45     if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
46         refCounter_->IncWeakRefCount(objectId);
47     }
48 }
49 
DecWeakRefCount(const void * objectId)50 void WeakRefCounter::DecWeakRefCount(const void *objectId)
51 {
52     if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
53         refCounter_->DecWeakRefCount(objectId);
54         delete this;
55     }
56 }
57 
AttemptIncStrongRef(const void * objectId)58 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
59 {
60     int unuse = 0;
61     return refCounter_->AttemptIncStrongRef(objectId, unuse);
62 }
63 
RefCounter()64 RefCounter::RefCounter()
65     : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
66 {
67 }
GetRefCount()68 int RefCounter::GetRefCount()
69 {
70     return atomicRefCount_.load(std::memory_order_relaxed);
71 }
72 
IncRefCount()73 void RefCounter::IncRefCount()
74 {
75     atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
76 }
77 
DecRefCount()78 void RefCounter::DecRefCount()
79 {
80     if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
81         if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
82             delete (this);
83         }
84     }
85 }
86 
SetCallback(const RefPtrCallback & callback)87 void RefCounter::SetCallback(const RefPtrCallback& callback)
88 {
89     callback_ = callback;
90 }
91 
RemoveCallback()92 void RefCounter::RemoveCallback()
93 {
94     callback_ = nullptr;
95 }
96 
IsRefPtrValid()97 bool RefCounter::IsRefPtrValid()
98 {
99     return callback_ != nullptr;
100 }
101 
~RefCounter()102 RefCounter::~RefCounter()
103 {
104 }
105 
IncStrongRefCount(const void *)106 int RefCounter::IncStrongRefCount(const void* /*objectId*/)
107 {
108     int curCount = atomicStrong_.load(std::memory_order_relaxed);
109 
110     if (curCount >= 0) {
111         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
112         if (curCount == INITIAL_PRIMARY_VALUE) {
113             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
114         }
115     }
116 
117     return curCount;
118 }
119 
DecStrongRefCount(const void *)120 int RefCounter::DecStrongRefCount(const void* /*objectId*/)
121 {
122     int curCount = GetStrongRefCount();
123     if (curCount == INITIAL_PRIMARY_VALUE) {
124         // unexpected case: there had never a strong reference.
125     } else if (curCount > 0) {
126         // we should update the current count here.
127         // it may be changed after last operation.
128         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
129     }
130 
131     return curCount;
132 }
133 
GetStrongRefCount()134 int RefCounter::GetStrongRefCount()
135 {
136     return atomicStrong_.load(std::memory_order_relaxed);
137 }
138 
IncWeakRefCount(const void *)139 int RefCounter::IncWeakRefCount(const void* /*objectId*/)
140 {
141     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
142 }
143 
DecWeakRefCount(const void *)144 int RefCounter::DecWeakRefCount(const void* /*objectId*/)
145 {
146     int curCount = GetWeakRefCount();
147     if (curCount > 0) {
148         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
149     }
150 
151     int strongRefCount = GetStrongRefCount();
152     if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
153         if (callback_) {
154             callback_();
155         }
156     }
157     return curCount;
158 }
159 
GetWeakRefCount()160 int RefCounter::GetWeakRefCount()
161 {
162     return atomicWeak_.load(std::memory_order_relaxed);
163 }
164 
SetAttemptAcquire()165 void RefCounter::SetAttemptAcquire()
166 {
167     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
168 }
169 
IsAttemptAcquireSet()170 bool RefCounter::IsAttemptAcquireSet()
171 {
172     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
173 }
174 
ClearAttemptAcquire()175 void RefCounter::ClearAttemptAcquire()
176 {
177     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
178 }
179 
ExtendObjectLifetime()180 void RefCounter::ExtendObjectLifetime()
181 {
182     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
183 }
184 
IsLifeTimeExtended()185 bool RefCounter::IsLifeTimeExtended()
186 {
187     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
188 }
189 
AttemptIncStrongRef(const void * objectId,int & outCount)190 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
191 {
192     int curCount = GetStrongRefCount();
193     IncWeakRefCount(objectId);
194 
195     // if the object already had strong references.just promoting it.
196     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
197         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
198             goto ATTEMPT_SUCCESS;
199         }
200         // someone else changed the counter.re-acquire the counter value.
201         curCount = atomicStrong_.load(std::memory_order_relaxed);
202     }
203 
204     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
205         // this object has a "normal" life-time,
206         while (curCount > 0) {
207             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
208                 goto ATTEMPT_SUCCESS;
209             }
210             curCount = atomicStrong_.load(std::memory_order_relaxed);
211         }
212     }
213 
214     if (IsLifeTimeExtended()) {
215         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
216     }
217 
218 ATTEMPT_SUCCESS:
219     if (curCount >= INITIAL_PRIMARY_VALUE) {
220         outCount = curCount;
221         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
222         return true;
223     }
224 
225     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
226         // the object destroyed on strong reference count reduce to zero.
227         DecWeakRefCount(objectId);
228         return false;
229     }
230 
231     return true;
232 }
233 
RefBase()234 RefBase::RefBase() : refs_(new RefCounter())
235 {
236     refs_->IncRefCount();
237     refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
238 }
239 
RefBase(const RefBase &)240 RefBase::RefBase(const RefBase &/*other*/)
241 {
242     refs_ = new RefCounter();
243     if (refs_ != nullptr) {
244         refs_->IncRefCount();
245         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
246     }
247 }
248 
RefPtrCallback()249 void RefBase::RefPtrCallback()
250 {
251     delete this;
252 }
253 
254 /*
255  * The two ends of the assignment are two independent and exclusive,
256  * and the application should not share the reference counter.
257  * RISK: If there is a reference count on the left of the equal sign,
258  * it may cause a reference count exception
259  */
operator =(const RefBase &)260 RefBase &RefBase::operator=(const RefBase &/*other*/)
261 {
262     if (refs_ != nullptr) {
263         refs_->RemoveCallback();
264         refs_->DecRefCount();
265     }
266 
267     refs_ = new RefCounter();
268     if (refs_ != nullptr) {
269         refs_->IncRefCount();
270         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
271     }
272 
273     return *this;
274 }
275 
RefBase(RefBase && other)276 RefBase::RefBase(RefBase &&other) noexcept
277 {
278     refs_ = other.refs_;
279     if (other.refs_ != nullptr) {
280         other.refs_ = nullptr;
281     }
282 }
283 
operator =(RefBase && other)284 RefBase &RefBase::operator=(RefBase &&other) noexcept
285 {
286     if (refs_ == other.refs_) {
287         return *this;
288     }
289 
290     if (refs_ != nullptr) {
291         refs_->RemoveCallback();
292         refs_->DecRefCount();
293     }
294 
295     refs_ = other.refs_;
296     if (other.refs_ != nullptr) {
297         other.refs_ = nullptr;
298     }
299     return *this;
300 }
301 
~RefBase()302 RefBase::~RefBase()
303 {
304     if (refs_ != nullptr) {
305         refs_->RemoveCallback();
306         refs_->DecRefCount();
307         refs_ = nullptr;
308     }
309 }
310 
ExtendObjectLifetime()311 void RefBase::ExtendObjectLifetime()
312 {
313     refs_->ExtendObjectLifetime();
314 }
315 
IncStrongRef(const void * objectId)316 void RefBase::IncStrongRef(const void *objectId)
317 {
318     if (refs_ == nullptr) {
319         return;
320     }
321 
322     const int curCount = refs_->IncStrongRefCount(objectId);
323     IncWeakRef(objectId);
324     if (curCount == INITIAL_PRIMARY_VALUE) {
325         OnFirstStrongRef(objectId);
326     }
327     if (refs_->IsAttemptAcquireSet()) {
328         refs_->ClearAttemptAcquire();
329         refs_->DecStrongRefCount(objectId);
330         refs_->DecWeakRefCount(objectId);
331     }
332 }
333 
DecStrongRef(const void * objectId)334 void RefBase::DecStrongRef(const void *objectId)
335 {
336     if (refs_ == nullptr) {
337         return;
338     }
339 
340     const int curCount = refs_->DecStrongRefCount(objectId);
341     if (curCount == 1) {
342         OnLastStrongRef(objectId);
343     }
344     DecWeakRef(objectId);
345 }
346 
GetSptrRefCount()347 int RefBase::GetSptrRefCount()
348 {
349     if (refs_ == nullptr) {
350         return 0;
351     }
352     return refs_->GetStrongRefCount();
353 }
354 
CreateWeakRef(void * cookie)355 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
356 {
357     if (refs_ != nullptr) {
358         return new WeakRefCounter(refs_, cookie);
359     }
360     return nullptr;
361 }
362 
IncWeakRef(const void * objectId)363 void RefBase::IncWeakRef(const void *objectId)
364 {
365     if (refs_ != nullptr) {
366         refs_->IncWeakRefCount(objectId);
367     }
368 }
369 
DecWeakRef(const void * objectId)370 void RefBase::DecWeakRef(const void *objectId)
371 {
372     if (refs_ != nullptr) {
373         refs_->DecWeakRefCount(objectId);
374     }
375 }
376 
GetWptrRefCount()377 int RefBase::GetWptrRefCount()
378 {
379     if (refs_ == nullptr) {
380         return 0;
381     }
382     return refs_->GetWeakRefCount();
383 }
384 
AttemptAcquire(const void * objectId)385 bool RefBase::AttemptAcquire(const void *objectId)
386 {
387     if (refs_ == nullptr) {
388         return false;
389     }
390 
391     int count = 0;
392     if (refs_->AttemptIncStrongRef(objectId, count)) {
393         refs_->SetAttemptAcquire();
394         if (count == INITIAL_PRIMARY_VALUE) {
395             OnFirstStrongRef(objectId);
396         }
397 
398         return true;
399     }
400     return false;
401 }
402 
AttemptIncStrongRef(const void * objectId)403 bool RefBase::AttemptIncStrongRef(const void *objectId)
404 {
405     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
406         int count = 0;
407         bool ret = refs_->AttemptIncStrongRef(objectId, count);
408         if (count == INITIAL_PRIMARY_VALUE) {
409             OnFirstStrongRef(objectId);
410         }
411         return ret;
412     }
413 
414     return false;
415 }
416 
IsAttemptAcquireSet()417 bool RefBase::IsAttemptAcquireSet()
418 {
419     if (refs_ == nullptr) {
420         return false;
421     }
422     return refs_->IsAttemptAcquireSet();
423 }
424 
IsExtendLifeTimeSet()425 bool RefBase::IsExtendLifeTimeSet()
426 {
427     if (refs_ == nullptr) {
428         return false;
429     }
430     return refs_->IsLifeTimeExtended();
431 }
432 
OnFirstStrongRef(const void *)433 void RefBase::OnFirstStrongRef(const void* /*objectId*/)
434 {}
435 
OnLastStrongRef(const void *)436 void RefBase::OnLastStrongRef(const void* /*objectId*/)
437 {}
438 
OnLastWeakRef(const void *)439 void RefBase::OnLastWeakRef(const void* /*objectId*/)
440 {}
441 
OnAttemptPromoted(const void *)442 bool RefBase::OnAttemptPromoted(const void* /*objectId*/)
443 {
444     return true;
445 }
446 
447 }  // namespace OHOS
448