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