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