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 (refCounter_ == nullptr) {
38         return nullptr;
39     }
40     if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) {
41         cookie_ = nullptr;
42     }
43     return cookie_;
44 }
45 
IncWeakRefCount(const void * objectId)46 void WeakRefCounter::IncWeakRefCount(const void *objectId)
47 {
48     if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
49         refCounter_->IncWeakRefCount(objectId);
50     }
51 }
52 
DecWeakRefCount(const void * objectId)53 void WeakRefCounter::DecWeakRefCount(const void *objectId)
54 {
55     if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
56         refCounter_->DecWeakRefCount(objectId);
57         delete this;
58     }
59 }
60 
AttemptIncStrongRef(const void * objectId)61 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
62 {
63     int unuse = 0;
64     return refCounter_->AttemptIncStrongRef(objectId, unuse);
65 }
66 
RefCounter()67 RefCounter::RefCounter()
68     : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
69 {
70 }
GetRefCount()71 int RefCounter::GetRefCount()
72 {
73     return atomicRefCount_.load(std::memory_order_relaxed);
74 }
75 
IncRefCount()76 void RefCounter::IncRefCount()
77 {
78     atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
79 }
80 
DecRefCount()81 void RefCounter::DecRefCount()
82 {
83     if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
84         if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
85             delete (this);
86         }
87     }
88 }
89 
SetCallback(const RefPtrCallback & callback)90 void RefCounter::SetCallback(const RefPtrCallback& callback)
91 {
92     callback_ = callback;
93 }
94 
RemoveCallback()95 void RefCounter::RemoveCallback()
96 {
97     callback_ = nullptr;
98 }
99 
IsRefPtrValid()100 bool RefCounter::IsRefPtrValid()
101 {
102     return callback_ != nullptr;
103 }
104 
~RefCounter()105 RefCounter::~RefCounter()
106 {
107 }
108 
IncStrongRefCount(const void *)109 int RefCounter::IncStrongRefCount(const void * /*objectId*/)
110 {
111     int curCount = atomicStrong_.load(std::memory_order_relaxed);
112     if (curCount >= 0) {
113         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
114         if (curCount == INITIAL_PRIMARY_VALUE) {
115             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
116         }
117     }
118     return curCount;
119 }
120 
DecStrongRefCount(const void *)121 int RefCounter::DecStrongRefCount(const void * /*objectId*/)
122 {
123     int curCount = GetStrongRefCount();
124     if (curCount == INITIAL_PRIMARY_VALUE) {
125         // unexpected case: there had never a strong reference.
126     } else if (curCount > 0) {
127         // we should update the current count here.
128         // it may be changed after last operation.
129         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
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     int strongRefCount = GetStrongRefCount();
151     if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
152         if (callback_) {
153             callback_();
154         }
155     }
156     return curCount;
157 }
158 
GetWeakRefCount()159 int RefCounter::GetWeakRefCount()
160 {
161     return atomicWeak_.load(std::memory_order_relaxed);
162 }
163 
SetAttemptAcquire()164 void RefCounter::SetAttemptAcquire()
165 {
166     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
167 }
168 
IsAttemptAcquireSet()169 bool RefCounter::IsAttemptAcquireSet()
170 {
171     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
172 }
173 
ClearAttemptAcquire()174 void RefCounter::ClearAttemptAcquire()
175 {
176     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
177 }
178 
ExtendObjectLifetime()179 void RefCounter::ExtendObjectLifetime()
180 {
181     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
182 }
183 
IsLifeTimeExtended()184 bool RefCounter::IsLifeTimeExtended()
185 {
186     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
187 }
188 
AttemptIncStrongRef(const void * objectId,int & outCount)189 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
190 {
191     int curCount = GetStrongRefCount();
192     IncWeakRefCount(objectId);
193 
194     // if the object already had strong references.just promoting it.
195     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
196         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
197             goto attempt_success;
198         }
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 
211             curCount = atomicStrong_.load(std::memory_order_relaxed);
212         }
213     }
214 
215     if (IsLifeTimeExtended()) {
216         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
217     }
218 
219 attempt_success:
220     if (curCount >= INITIAL_PRIMARY_VALUE) {
221         outCount = curCount;
222         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
223         return true;
224     }
225 
226     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
227         // the object destroyed on strong reference count reduce to zero.
228         DecWeakRefCount(objectId);
229         return false;
230     }
231     return true;
232 }
233 
RefBase()234 RefBase::RefBase() : refs_(new RefCounter())
235 {
236     refs_->IncRefCount();
237     refs_->SetCallback([this] {
238         this->RefPtrCallback();
239     });
240 }
241 
RefBase(const RefBase &)242 RefBase::RefBase(const RefBase& /*other*/)
243 {
244     refs_ = new RefCounter();
245     if (refs_ != nullptr) {
246         refs_->IncRefCount();
247         refs_->SetCallback([this] {
248             this->RefPtrCallback();
249         });
250     }
251 }
252 
RefPtrCallback()253 void RefBase::RefPtrCallback()
254 {
255     delete this;
256 }
257 
258 /*
259  * The two ends of the assignment are two independent and exclusive,
260  * and the application should not share the reference counter.
261  * RISK: If there is a reference count on the left of the equal sign,
262  * it may cause a reference count exception
263  */
operator =(const RefBase &)264 RefBase &RefBase::operator=(const RefBase& /*other*/)
265 {
266     if (refs_ != nullptr) {
267         refs_->RemoveCallback();
268         refs_->DecRefCount();
269     }
270     refs_ = new RefCounter();
271     if (refs_ != nullptr) {
272         refs_->IncRefCount();
273         refs_->SetCallback([this] {
274             this->RefPtrCallback();
275         });
276     }
277     return *this;
278 }
279 
RefBase(RefBase && other)280 RefBase::RefBase(RefBase &&other) noexcept
281 {
282     refs_ = other.refs_;
283     other.refs_ = nullptr;
284 }
285 
operator =(RefBase && other)286 RefBase &RefBase::operator=(RefBase &&other)  noexcept
287 {
288     if (refs_ == other.refs_) {
289         return *this;
290     }
291     if (refs_ != nullptr) {
292         refs_->RemoveCallback();
293         refs_->DecRefCount();
294     }
295     refs_ = other.refs_;
296     other.refs_ = nullptr;
297     return *this;
298 }
299 
~RefBase()300 RefBase::~RefBase()
301 {
302     if (refs_ != nullptr) {
303         refs_->RemoveCallback();
304         refs_->DecRefCount();
305         refs_ = nullptr;
306     }
307 }
308 
ExtendObjectLifetime()309 void RefBase::ExtendObjectLifetime()
310 {
311     refs_->ExtendObjectLifetime();
312 }
313 
IncStrongRef(const void * objectId)314 void RefBase::IncStrongRef(const void *objectId)
315 {
316     if (refs_ == nullptr) {
317         return;
318     }
319     const int curCount = refs_->IncStrongRefCount(objectId);
320     IncWeakRef(objectId);
321     if (curCount == INITIAL_PRIMARY_VALUE) {
322         OnFirstStrongRef(objectId);
323     }
324     if (refs_->IsAttemptAcquireSet()) {
325         refs_->ClearAttemptAcquire();
326         refs_->DecStrongRefCount(objectId);
327     }
328 }
329 
DecStrongRef(const void * objectId)330 void RefBase::DecStrongRef(const void *objectId)
331 {
332     if (refs_ == nullptr) {
333         return;
334     }
335     const int curCount = refs_->DecStrongRefCount(objectId);
336     if (curCount == 1) {
337         OnLastStrongRef(objectId);
338     }
339     DecWeakRef(objectId);
340 }
341 
GetSptrRefCount()342 int RefBase::GetSptrRefCount()
343 {
344     if (refs_ != nullptr) {
345         return refs_->GetStrongRefCount();
346     } else {
347         return 0;
348     }
349 }
350 
CreateWeakRef(void * cookie)351 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
352 {
353     if (refs_ != nullptr) {
354         return new WeakRefCounter(refs_, cookie);
355     }
356 
357     return nullptr;
358 }
359 
IncWeakRef(const void * objectId)360 void RefBase::IncWeakRef(const void *objectId)
361 {
362     if (refs_ != nullptr) {
363         refs_->IncWeakRefCount(objectId);
364     }
365 }
366 
DecWeakRef(const void * objectId)367 void RefBase::DecWeakRef(const void *objectId)
368 {
369     if (refs_ != nullptr) {
370         refs_->DecWeakRefCount(objectId);
371     }
372 }
373 
GetWptrRefCount()374 int RefBase::GetWptrRefCount()
375 {
376     if (refs_ != nullptr) {
377         return refs_->GetWeakRefCount();
378     } else {
379         return 0;
380     }
381 }
382 
AttemptAcquire(const void * objectId)383 bool RefBase::AttemptAcquire(const void *objectId)
384 {
385     if (refs_ != nullptr) {
386         int count = 0;
387         if (refs_->AttemptIncStrongRef(objectId, count)) {
388             if (count == INITIAL_PRIMARY_VALUE) {
389                 OnFirstStrongRef(objectId);
390             }
391             refs_->SetAttemptAcquire();
392             return true;
393         }
394     }
395     return false;
396 }
397 
AttemptIncStrongRef(const void * objectId)398 bool RefBase::AttemptIncStrongRef(const void *objectId)
399 {
400     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
401         int count = 0;
402         bool ret = refs_->AttemptIncStrongRef(objectId, count);
403         if (count == INITIAL_PRIMARY_VALUE) {
404             OnFirstStrongRef(objectId);
405         }
406         return ret;
407     }
408     return false;
409 }
410 
IsAttemptAcquireSet()411 bool RefBase::IsAttemptAcquireSet()
412 {
413     if (refs_ != nullptr) {
414         return refs_->IsAttemptAcquireSet();
415     }
416     return false;
417 }
418 
IsExtendLifeTimeSet()419 bool RefBase::IsExtendLifeTimeSet()
420 {
421     if (refs_ != nullptr) {
422         return refs_->IsLifeTimeExtended();
423     }
424     return false;
425 }
426 
OnFirstStrongRef(const void *)427 void RefBase::OnFirstStrongRef(const void *)
428 {}
429 
OnLastStrongRef(const void *)430 void RefBase::OnLastStrongRef(const void *)
431 {}
432 
OnLastWeakRef(const void *)433 void RefBase::OnLastWeakRef(const void *)
434 {}
435 
OnAttemptPromoted(const void *)436 bool RefBase::OnAttemptPromoted(const void *)
437 {
438     return true;
439 }
440 } // namespace OHOS
441