• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(std::bind(&RefBase::RefPtrCallback, this));
233 }
234 
RefBase(const RefBase & other)235 RefBase::RefBase(const RefBase& other)
236 {
237     refs_ = new RefCounter();
238     if (refs_ != nullptr) {
239         refs_->IncRefCount();
240         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
241     }
242 }
243 
RefPtrCallback()244 void RefBase::RefPtrCallback()
245 {
246     delete this;
247 }
248 
operator =(const RefBase & other)249 RefBase &RefBase::operator=(const RefBase& other)
250 {
251     if (refs_ != nullptr) {
252         refs_->RemoveCallback();
253         refs_->DecRefCount();
254     }
255 
256     refs_ = new RefCounter();
257     if (refs_ != nullptr) {
258         refs_->IncRefCount();
259         refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
260     }
261 
262     return *this;
263 }
264 
RefBase(RefBase && other)265 RefBase::RefBase(RefBase &&other) noexcept
266 {
267     refs_ = other.refs_;
268     if (other.refs_ != nullptr) {
269         other.refs_ = nullptr;
270     }
271 }
272 
operator =(RefBase && other)273 RefBase &RefBase::operator=(RefBase &&other) noexcept
274 {
275     if (refs_ == other.refs_) {
276         return *this;
277     }
278 
279     if (refs_ != nullptr) {
280         refs_->RemoveCallback();
281         refs_->DecRefCount();
282     }
283 
284     refs_ = other.refs_;
285     if (other.refs_ != nullptr) {
286         other.refs_ = nullptr;
287     }
288     return *this;
289 }
290 
~RefBase()291 RefBase::~RefBase()
292 {
293     if (refs_ != nullptr) {
294         refs_->RemoveCallback();
295         refs_->DecRefCount();
296         refs_ = nullptr;
297     }
298 }
299 
ExtendObjectLifetime()300 void RefBase::ExtendObjectLifetime()
301 {
302     refs_->ExtendObjectLifetime();
303 }
304 
IncStrongRef(const void * objectId)305 void RefBase::IncStrongRef(const void *objectId)
306 {
307     if (refs_ == nullptr) {
308         return;
309     }
310 
311     const int curCount = refs_->IncStrongRefCount(objectId);
312     IncWeakRef(objectId);
313     if (curCount == INITIAL_PRIMARY_VALUE) {
314         OnFirstStrongRef(objectId);
315     }
316     if (refs_->IsAttemptAcquireSet()) {
317         refs_->ClearAttemptAcquire();
318         refs_->DecStrongRefCount(objectId);
319         refs_->DecWeakRefCount(objectId);
320     }
321 }
322 
DecStrongRef(const void * objectId)323 void RefBase::DecStrongRef(const void *objectId)
324 {
325     if (refs_ == nullptr) {
326         return;
327     }
328 
329     const int curCount = refs_->DecStrongRefCount(objectId);
330     if (curCount == 1) {
331         OnLastStrongRef(objectId);
332     }
333     DecWeakRef(objectId);
334 }
335 
GetSptrRefCount()336 int RefBase::GetSptrRefCount()
337 {
338     if (refs_ == nullptr) {
339         return 0;
340     }
341     return refs_->GetStrongRefCount();
342 }
343 
CreateWeakRef(void * cookie)344 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
345 {
346     if (refs_ != nullptr) {
347         return new WeakRefCounter(refs_, cookie);
348     }
349     return nullptr;
350 }
351 
IncWeakRef(const void * objectId)352 void RefBase::IncWeakRef(const void *objectId)
353 {
354     if (refs_ != nullptr) {
355         refs_->IncWeakRefCount(objectId);
356     }
357 }
358 
DecWeakRef(const void * objectId)359 void RefBase::DecWeakRef(const void *objectId)
360 {
361     if (refs_ != nullptr) {
362         refs_->DecWeakRefCount(objectId);
363     }
364 }
365 
GetWptrRefCount()366 int RefBase::GetWptrRefCount()
367 {
368     if (refs_ == nullptr) {
369         return 0;
370     }
371     return refs_->GetWeakRefCount();
372 }
373 
AttemptAcquire(const void * objectId)374 bool RefBase::AttemptAcquire(const void *objectId)
375 {
376     if (refs_ == nullptr) {
377         return false;
378     }
379 
380     int count = 0;
381     if (refs_->AttemptIncStrongRef(objectId, count)) {
382         refs_->SetAttemptAcquire();
383         if (count == INITIAL_PRIMARY_VALUE) {
384             OnFirstStrongRef(objectId);
385         }
386 
387         return true;
388     }
389     return false;
390 }
391 
AttemptIncStrongRef(const void * objectId)392 bool RefBase::AttemptIncStrongRef(const void *objectId)
393 {
394     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
395         int count = 0;
396         bool ret = refs_->AttemptIncStrongRef(objectId, count);
397         if (count == INITIAL_PRIMARY_VALUE) {
398             OnFirstStrongRef(objectId);
399         }
400         return ret;
401     }
402 
403     return false;
404 }
405 
IsAttemptAcquireSet()406 bool RefBase::IsAttemptAcquireSet()
407 {
408     if (refs_ == nullptr) {
409         return false;
410     }
411     return refs_->IsAttemptAcquireSet();
412 }
413 
IsExtendLifeTimeSet()414 bool RefBase::IsExtendLifeTimeSet()
415 {
416     if (refs_ == nullptr) {
417         return false;
418     }
419     return refs_->IsLifeTimeExtended();
420 }
421 
OnFirstStrongRef(const void * objectId)422 void RefBase::OnFirstStrongRef(const void* objectId)
423 {}
424 
OnLastStrongRef(const void * objectId)425 void RefBase::OnLastStrongRef(const void* objectId)
426 {}
427 
OnLastWeakRef(const void * objectId)428 void RefBase::OnLastWeakRef(const void* objectId)
429 {}
430 
OnAttemptPromoted(const void * objectId)431 bool RefBase::OnAttemptPromoted(const void* objectId)
432 {
433     return true;
434 }
435 }  // namespace OHOS
436