• 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 
17 #include "refbase.h"
18 
19 namespace OHOS {
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     if (curCount >= 0) {
110         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
111         if (curCount == INITIAL_PRIMARY_VALUE) {
112             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
113         }
114     }
115     return curCount;
116 }
117 
DecStrongRefCount(const void *)118 int RefCounter::DecStrongRefCount(const void * /*objectId*/)
119 {
120     int curCount = GetStrongRefCount();
121     if (curCount == INITIAL_PRIMARY_VALUE) {
122         // unexpected case: there had never a strong reference.
123     } else if (curCount > 0) {
124         // we should update the current count here.
125         // it may be changed after last operation.
126         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
127     }
128     return curCount;
129 }
130 
GetStrongRefCount()131 int RefCounter::GetStrongRefCount()
132 {
133     return atomicStrong_.load(std::memory_order_relaxed);
134 }
135 
IncWeakRefCount(const void *)136 int RefCounter::IncWeakRefCount(const void * /*objectId*/)
137 {
138     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
139 }
140 
DecWeakRefCount(const void *)141 int RefCounter::DecWeakRefCount(const void * /*objectId*/)
142 {
143     int curCount = GetWeakRefCount();
144     if (curCount > 0) {
145         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
146     }
147     int strongRefCount = GetStrongRefCount();
148     if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
149         if (callback_) {
150             callback_();
151         }
152     }
153     return curCount;
154 }
155 
GetWeakRefCount()156 int RefCounter::GetWeakRefCount()
157 {
158     return atomicWeak_.load(std::memory_order_relaxed);
159 }
160 
SetAttemptAcquire()161 void RefCounter::SetAttemptAcquire()
162 {
163     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
164 }
165 
IsAttemptAcquireSet()166 bool RefCounter::IsAttemptAcquireSet()
167 {
168     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
169 }
170 
ClearAttemptAcquire()171 void RefCounter::ClearAttemptAcquire()
172 {
173     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
174 }
175 
ExtendObjectLifetime()176 void RefCounter::ExtendObjectLifetime()
177 {
178     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
179 }
180 
IsLifeTimeExtended()181 bool RefCounter::IsLifeTimeExtended()
182 {
183     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
184 }
185 
AttemptIncStrongRef(const void * objectId,int & outCount)186 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
187 {
188     int curCount = GetStrongRefCount();
189     IncWeakRefCount(objectId);
190 
191     // if the object already had strong references.just promoting it.
192     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
193         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
194             goto attempt_success;
195         }
196 
197         // someone else changed the counter.re-acquire the counter value.
198         curCount = atomicStrong_.load(std::memory_order_relaxed);
199     }
200 
201     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
202         // this object has a "normal" life-time,
203         while (curCount > 0) {
204             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
205                 goto attempt_success;
206             }
207 
208             curCount = atomicStrong_.load(std::memory_order_relaxed);
209         }
210     }
211 
212     if (IsLifeTimeExtended()) {
213         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
214     }
215 
216 attempt_success:
217     if (curCount >= INITIAL_PRIMARY_VALUE) {
218         outCount = curCount;
219         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
220         return true;
221     }
222 
223     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
224         // the object destroyed on strong reference count reduce to zero.
225         DecWeakRefCount(objectId);
226         return false;
227     }
228     return true;
229 }
230 
RefBase()231 RefBase::RefBase() : refs_(new RefCounter())
232 {
233     refs_->IncRefCount();
234     refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
235 }
236 
RefBase(const RefBase &)237 RefBase::RefBase(const RefBase& /*other*/)
238 {
239     refs_ = new RefCounter();
240     if (refs_ != nullptr) {
241         refs_->IncRefCount();
242         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
243     }
244 }
245 
RefPtrCallback()246 void RefBase::RefPtrCallback()
247 {
248     delete this;
249 }
250 
251 /*
252  * The two ends of the assignment are two independent and exclusive,
253  * and the application should not share the reference counter.
254  * RISK: If there is a reference count on the left of the equal sign,
255  * it may cause a reference count exception
256  */
operator =(const RefBase &)257 RefBase &RefBase::operator=(const RefBase& /*other*/)
258 {
259     if (refs_ != nullptr) {
260         refs_->RemoveCallback();
261         refs_->DecRefCount();
262     }
263     refs_ = new RefCounter();
264     if (refs_ != nullptr) {
265         refs_->IncRefCount();
266         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
267     }
268     return *this;
269 }
270 
RefBase(RefBase && other)271 RefBase::RefBase(RefBase &&other) noexcept
272 {
273     refs_ = other.refs_;
274     if (other.refs_ != nullptr) {
275         other.refs_ = nullptr;
276     }
277 }
278 
operator =(RefBase && other)279 RefBase &RefBase::operator=(RefBase &&other)  noexcept
280 {
281     if (refs_ == other.refs_) {
282         return *this;
283     }
284     if (refs_ != nullptr) {
285         refs_->RemoveCallback();
286         refs_->DecRefCount();
287     }
288     refs_ = other.refs_;
289     if (other.refs_ != nullptr) {
290         other.refs_ = nullptr;
291     }
292     return *this;
293 }
294 
~RefBase()295 RefBase::~RefBase()
296 {
297     if (refs_ != nullptr) {
298         refs_->RemoveCallback();
299         refs_->DecRefCount();
300         refs_ = nullptr;
301     }
302 }
303 
ExtendObjectLifetime()304 void RefBase::ExtendObjectLifetime()
305 {
306     refs_->ExtendObjectLifetime();
307 }
308 
IncStrongRef(const void * objectId)309 void RefBase::IncStrongRef(const void *objectId)
310 {
311     if (refs_ == nullptr) {
312         return;
313     }
314     const int curCount = refs_->IncStrongRefCount(objectId);
315     IncWeakRef(objectId);
316     if (curCount == INITIAL_PRIMARY_VALUE) {
317         OnFirstStrongRef(objectId);
318     }
319     if (refs_->IsAttemptAcquireSet()) {
320         refs_->ClearAttemptAcquire();
321         refs_->DecStrongRefCount(objectId);
322     }
323 }
324 
DecStrongRef(const void * objectId)325 void RefBase::DecStrongRef(const void *objectId)
326 {
327     if (refs_ == nullptr) {
328         return;
329     }
330     const int curCount = refs_->DecStrongRefCount(objectId);
331     if (curCount == 1) {
332         OnLastStrongRef(objectId);
333     }
334     DecWeakRef(objectId);
335 }
336 
GetSptrRefCount()337 int RefBase::GetSptrRefCount()
338 {
339     if (refs_ != nullptr) {
340         return refs_->GetStrongRefCount();
341     } else {
342         return 0;
343     }
344 }
345 
CreateWeakRef(void * cookie)346 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
347 {
348     if (refs_ != nullptr) {
349         return new WeakRefCounter(refs_, cookie);
350     }
351 
352     return nullptr;
353 }
354 
IncWeakRef(const void * objectId)355 void RefBase::IncWeakRef(const void *objectId)
356 {
357     if (refs_ != nullptr) {
358         refs_->IncWeakRefCount(objectId);
359     }
360 }
361 
DecWeakRef(const void * objectId)362 void RefBase::DecWeakRef(const void *objectId)
363 {
364     if (refs_ != nullptr) {
365         refs_->DecWeakRefCount(objectId);
366     }
367 }
368 
GetWptrRefCount()369 int RefBase::GetWptrRefCount()
370 {
371     if (refs_ != nullptr) {
372         return refs_->GetWeakRefCount();
373     } else {
374         return 0;
375     }
376 }
377 
AttemptAcquire(const void * objectId)378 bool RefBase::AttemptAcquire(const void *objectId)
379 {
380     if (refs_ != nullptr) {
381         int count = 0;
382         if (refs_->AttemptIncStrongRef(objectId, count)) {
383             if (count == INITIAL_PRIMARY_VALUE) {
384                 OnFirstStrongRef(objectId);
385             }
386             refs_->SetAttemptAcquire();
387             return true;
388         }
389     }
390     return false;
391 }
392 
AttemptIncStrongRef(const void * objectId)393 bool RefBase::AttemptIncStrongRef(const void *objectId)
394 {
395     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
396         int count = 0;
397         bool ret = refs_->AttemptIncStrongRef(objectId, count);
398         if (count == INITIAL_PRIMARY_VALUE) {
399             OnFirstStrongRef(objectId);
400         }
401         return ret;
402     }
403     return false;
404 }
405 
IsAttemptAcquireSet()406 bool RefBase::IsAttemptAcquireSet()
407 {
408     if (refs_ != nullptr) {
409         return refs_->IsAttemptAcquireSet();
410     }
411     return false;
412 }
413 
IsExtendLifeTimeSet()414 bool RefBase::IsExtendLifeTimeSet()
415 {
416     if (refs_ != nullptr) {
417         return refs_->IsLifeTimeExtended();
418     }
419     return false;
420 }
421 
OnFirstStrongRef(const void *)422 void RefBase::OnFirstStrongRef(const void * /*objectId*/)
423 {}
424 
OnLastStrongRef(const void *)425 void RefBase::OnLastStrongRef(const void * /*objectId*/)
426 {}
427 
OnLastWeakRef(const void *)428 void RefBase::OnLastWeakRef(const void * /*objectId*/)
429 {}
430 
OnAttemptPromoted(const void *)431 bool RefBase::OnAttemptPromoted(const void * /*objectId*/)
432 {
433     return true;
434 }
435 } // namespace OHOS
436