1 /*
2  * Copyright (c) 2022 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 namespace OHOS {
WeakRefCounter(RefCounter * counter,void * cookie)18 WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie)
19     : atomicWeak_(0), refCounter_(counter), cookie_(cookie)
20 {
21     if (refCounter_ != nullptr) {
22         refCounter_->IncRefCount();
23     }
24 }
25 
~WeakRefCounter()26 WeakRefCounter::~WeakRefCounter()
27 {
28     if (refCounter_ != nullptr) {
29         refCounter_->DecRefCount();
30     }
31 }
32 
GetRefPtr()33 void *WeakRefCounter::GetRefPtr()
34 {
35     if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) {
36         cookie_ = nullptr;
37     }
38     return cookie_;
39 }
40 
IncWeakRefCount(const void * objectId)41 void WeakRefCounter::IncWeakRefCount(const void *objectId)
42 {
43     if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
44         refCounter_->IncWeakRefCount(objectId);
45     }
46 }
47 
DecWeakRefCount(const void * objectId)48 void WeakRefCounter::DecWeakRefCount(const void *objectId)
49 {
50     if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
51         refCounter_->DecWeakRefCount(objectId);
52         delete this;
53     }
54 }
55 
AttemptIncStrongRef(const void * objectId)56 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
57 {
58     int unuse = 0;
59     return refCounter_->AttemptIncStrongRef(objectId, unuse);
60 }
61 
RefCounter()62 RefCounter::RefCounter()
63     : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
64 {
65 }
GetRefCount()66 int RefCounter::GetRefCount()
67 {
68     return atomicRefCount_.load(std::memory_order_relaxed);
69 }
70 
IncRefCount()71 void RefCounter::IncRefCount()
72 {
73     atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
74 }
75 
DecRefCount()76 void RefCounter::DecRefCount()
77 {
78     if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
79         if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
80             delete (this);
81         }
82     }
83 }
84 
SetCallback(const RefPtrCallback & callback)85 void RefCounter::SetCallback(const RefPtrCallback &callback)
86 {
87     callback_ = callback;
88 }
89 
RemoveCallback()90 void RefCounter::RemoveCallback()
91 {
92     callback_ = nullptr;
93 }
94 
IsRefPtrValid()95 bool RefCounter::IsRefPtrValid()
96 {
97     return callback_ != nullptr;
98 }
99 
~RefCounter()100 RefCounter::~RefCounter()
101 {
102 }
103 
IncStrongRefCount(const void * objectId)104 int RefCounter::IncStrongRefCount(const void *objectId)
105 {
106     int curCount = atomicStrong_.load(std::memory_order_relaxed);
107     if (curCount >= 0) {
108         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
109         if (curCount == INITIAL_PRIMARY_VALUE) {
110             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
111         }
112     }
113     return curCount;
114 }
115 
DecStrongRefCount(const void * objectId)116 int RefCounter::DecStrongRefCount(const void *objectId)
117 {
118     int curCount = GetStrongRefCount();
119     if (curCount == INITIAL_PRIMARY_VALUE) {
120         // unexpected case: there had never a strong reference.
121     } else if (curCount > 0) {
122         // we should update the current count here.
123         // it may be changed after last operation.
124         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
125     }
126     return curCount;
127 }
128 
GetStrongRefCount()129 int RefCounter::GetStrongRefCount()
130 {
131     return atomicStrong_.load(std::memory_order_relaxed);
132 }
133 
IncWeakRefCount(const void * objectId)134 int RefCounter::IncWeakRefCount(const void *objectId)
135 {
136     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
137 }
138 
DecWeakRefCount(const void * objectId)139 int RefCounter::DecWeakRefCount(const void *objectId)
140 {
141     int curCount = GetWeakRefCount();
142     if (curCount > 0) {
143         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
144     }
145 
146     int strongRefCount = GetStrongRefCount();
147     if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
148         if (callback_) {
149             callback_();
150         }
151     }
152     return curCount;
153 }
154 
GetWeakRefCount()155 int RefCounter::GetWeakRefCount()
156 {
157     return atomicWeak_.load(std::memory_order_relaxed);
158 }
159 
SetAttemptAcquire()160 void RefCounter::SetAttemptAcquire()
161 {
162     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
163 }
164 
IsAttemptAcquireSet()165 bool RefCounter::IsAttemptAcquireSet()
166 {
167     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
168 }
169 
ClearAttemptAcquire()170 void RefCounter::ClearAttemptAcquire()
171 {
172     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
173 }
174 
ExtendObjectLifetime()175 void RefCounter::ExtendObjectLifetime()
176 {
177     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
178 }
179 
IsLifeTimeExtended()180 bool RefCounter::IsLifeTimeExtended()
181 {
182     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
183 }
184 
AttemptIncStrongRef(const void * objectId,int & outCount)185 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
186 {
187     int curCount = GetStrongRefCount();
188     IncWeakRefCount(objectId);
189 
190     // if the object already had strong references.just promoting it.
191     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
192         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
193             goto ATTEMPT_SUCCESS;
194         }
195         // someone else changed the counter.re-acquire the counter value.
196         curCount = atomicStrong_.load(std::memory_order_relaxed);
197     }
198 
199     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
200         // this object has a "normal" life-time,
201         while (curCount > 0) {
202             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
203                 goto ATTEMPT_SUCCESS;
204             }
205             curCount = atomicStrong_.load(std::memory_order_relaxed);
206         }
207     }
208 
209     if (IsLifeTimeExtended()) {
210         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
211     }
212 
213 ATTEMPT_SUCCESS:
214     if (curCount >= INITIAL_PRIMARY_VALUE) {
215         outCount = curCount;
216         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
217         return true;
218     }
219 
220     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
221         // the object destroyed on strong reference count reduce to zero.
222         DecWeakRefCount(objectId);
223         return false;
224     }
225 
226     return true;
227 }
228 
RefBase()229 RefBase::RefBase() : refs_(new RefCounter())
230 {
231     refs_->IncRefCount();
232     refs_->SetCallback([this] {
233         this->RefPtrCallback();
234     });
235 }
236 
RefBase(const RefBase & other)237 RefBase::RefBase(const RefBase &other)
238 {
239     refs_ = new RefCounter();
240     if (refs_ != nullptr) {
241         refs_->IncRefCount();
242         refs_->SetCallback([this] {
243             this->RefPtrCallback();
244         });
245     }
246 }
247 
RefPtrCallback()248 void RefBase::RefPtrCallback()
249 {
250     delete this;
251 }
252 
operator =(const RefBase & other)253 RefBase &RefBase::operator=(const RefBase &other)
254 {
255     if (refs_ != nullptr) {
256         refs_->RemoveCallback();
257         refs_->DecRefCount();
258     }
259 
260     refs_ = new RefCounter();
261     if (refs_ != nullptr) {
262         refs_->IncRefCount();
263         refs_->SetCallback([this] {
264             this->RefPtrCallback();
265         });
266     }
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 
285     if (refs_ != nullptr) {
286         refs_->RemoveCallback();
287         refs_->DecRefCount();
288     }
289 
290     refs_ = other.refs_;
291     if (other.refs_ != nullptr) {
292         other.refs_ = nullptr;
293     }
294     return *this;
295 }
296 
~RefBase()297 RefBase::~RefBase()
298 {
299     if (refs_ != nullptr) {
300         refs_->RemoveCallback();
301         refs_->DecRefCount();
302         refs_ = nullptr;
303     }
304 }
305 
ExtendObjectLifetime()306 void RefBase::ExtendObjectLifetime()
307 {
308     refs_->ExtendObjectLifetime();
309 }
310 
IncStrongRef(const void * objectId)311 void RefBase::IncStrongRef(const void *objectId)
312 {
313     if (refs_ == nullptr) {
314         return;
315     }
316 
317     const int curCount = refs_->IncStrongRefCount(objectId);
318     IncWeakRef(objectId);
319     if (curCount == INITIAL_PRIMARY_VALUE) {
320         OnFirstStrongRef(objectId);
321     }
322     if (refs_->IsAttemptAcquireSet()) {
323         refs_->ClearAttemptAcquire();
324         refs_->DecStrongRefCount(objectId);
325         refs_->DecWeakRefCount(objectId);
326     }
327 }
328 
DecStrongRef(const void * objectId)329 void RefBase::DecStrongRef(const void *objectId)
330 {
331     if (refs_ == nullptr) {
332         return;
333     }
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 0;
346     }
347     return refs_->GetStrongRefCount();
348 }
349 
CreateWeakRef(void * cookie)350 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
351 {
352     if (refs_ != nullptr) {
353         return new WeakRefCounter(refs_, cookie);
354     }
355     return nullptr;
356 }
357 
IncWeakRef(const void * objectId)358 void RefBase::IncWeakRef(const void *objectId)
359 {
360     if (refs_ != nullptr) {
361         refs_->IncWeakRefCount(objectId);
362     }
363 }
364 
DecWeakRef(const void * objectId)365 void RefBase::DecWeakRef(const void *objectId)
366 {
367     if (refs_ != nullptr) {
368         refs_->DecWeakRefCount(objectId);
369     }
370 }
371 
GetWptrRefCount()372 int RefBase::GetWptrRefCount()
373 {
374     if (refs_ == nullptr) {
375         return 0;
376     }
377     return refs_->GetWeakRefCount();
378 }
379 
AttemptAcquire(const void * objectId)380 bool RefBase::AttemptAcquire(const void *objectId)
381 {
382     if (refs_ == nullptr) {
383         return false;
384     }
385 
386     int count = 0;
387     if (refs_->AttemptIncStrongRef(objectId, count)) {
388         refs_->SetAttemptAcquire();
389         if (count == INITIAL_PRIMARY_VALUE) {
390             OnFirstStrongRef(objectId);
391         }
392 
393         return true;
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 
409     return false;
410 }
411 
IsAttemptAcquireSet()412 bool RefBase::IsAttemptAcquireSet()
413 {
414     if (refs_ == nullptr) {
415         return false;
416     }
417     return refs_->IsAttemptAcquireSet();
418 }
419 
IsExtendLifeTimeSet()420 bool RefBase::IsExtendLifeTimeSet()
421 {
422     if (refs_ == nullptr) {
423         return false;
424     }
425     return refs_->IsLifeTimeExtended();
426 }
427 
OnFirstStrongRef(const void * objectId)428 void RefBase::OnFirstStrongRef(const void *objectId)
429 {
430 }
431 
OnLastStrongRef(const void * objectId)432 void RefBase::OnLastStrongRef(const void *objectId)
433 {
434 }
435 
OnLastWeakRef(const void * objectId)436 void RefBase::OnLastWeakRef(const void *objectId)
437 {
438 }
439 
OnAttemptPromoted(const void * objectId)440 bool RefBase::OnAttemptPromoted(const void *objectId)
441 {
442     return true;
443 }
444 } // namespace OHOS
445