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* /*objectId*/)
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* /*objectId*/)
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* /*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
151 int strongRefCount = GetStrongRefCount();
152 if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) {
153 if (callback_) {
154 callback_();
155 }
156 }
157 return curCount;
158 }
159
GetWeakRefCount()160 int RefCounter::GetWeakRefCount()
161 {
162 return atomicWeak_.load(std::memory_order_relaxed);
163 }
164
SetAttemptAcquire()165 void RefCounter::SetAttemptAcquire()
166 {
167 (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
168 }
169
IsAttemptAcquireSet()170 bool RefCounter::IsAttemptAcquireSet()
171 {
172 return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
173 }
174
ClearAttemptAcquire()175 void RefCounter::ClearAttemptAcquire()
176 {
177 atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
178 }
179
ExtendObjectLifetime()180 void RefCounter::ExtendObjectLifetime()
181 {
182 atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
183 }
184
IsLifeTimeExtended()185 bool RefCounter::IsLifeTimeExtended()
186 {
187 return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
188 }
189
AttemptIncStrongRef(const void * objectId,int & outCount)190 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
191 {
192 int curCount = GetStrongRefCount();
193 IncWeakRefCount(objectId);
194
195 // if the object already had strong references.just promoting it.
196 while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
197 if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
198 goto ATTEMPT_SUCCESS;
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 curCount = atomicStrong_.load(std::memory_order_relaxed);
211 }
212 }
213
214 if (IsLifeTimeExtended()) {
215 curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
216 }
217
218 ATTEMPT_SUCCESS:
219 if (curCount >= INITIAL_PRIMARY_VALUE) {
220 outCount = curCount;
221 atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
222 return true;
223 }
224
225 if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
226 // the object destroyed on strong reference count reduce to zero.
227 DecWeakRefCount(objectId);
228 return false;
229 }
230
231 return true;
232 }
233
RefBase()234 RefBase::RefBase() : refs_(new RefCounter())
235 {
236 refs_->IncRefCount();
237 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
238 }
239
RefBase(const RefBase &)240 RefBase::RefBase(const RefBase &/*other*/)
241 {
242 refs_ = new RefCounter();
243 if (refs_ != nullptr) {
244 refs_->IncRefCount();
245 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
246 }
247 }
248
RefPtrCallback()249 void RefBase::RefPtrCallback()
250 {
251 delete this;
252 }
253
254 /*
255 * The two ends of the assignment are two independent and exclusive,
256 * and the application should not share the reference counter.
257 * RISK: If there is a reference count on the left of the equal sign,
258 * it may cause a reference count exception
259 */
operator =(const RefBase &)260 RefBase &RefBase::operator=(const RefBase &/*other*/)
261 {
262 if (refs_ != nullptr) {
263 refs_->RemoveCallback();
264 refs_->DecRefCount();
265 }
266
267 refs_ = new RefCounter();
268 if (refs_ != nullptr) {
269 refs_->IncRefCount();
270 refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this));
271 }
272
273 return *this;
274 }
275
RefBase(RefBase && other)276 RefBase::RefBase(RefBase &&other) noexcept
277 {
278 refs_ = other.refs_;
279 if (other.refs_ != nullptr) {
280 other.refs_ = nullptr;
281 }
282 }
283
operator =(RefBase && other)284 RefBase &RefBase::operator=(RefBase &&other) noexcept
285 {
286 if (refs_ == other.refs_) {
287 return *this;
288 }
289
290 if (refs_ != nullptr) {
291 refs_->RemoveCallback();
292 refs_->DecRefCount();
293 }
294
295 refs_ = other.refs_;
296 if (other.refs_ != nullptr) {
297 other.refs_ = nullptr;
298 }
299 return *this;
300 }
301
~RefBase()302 RefBase::~RefBase()
303 {
304 if (refs_ != nullptr) {
305 refs_->RemoveCallback();
306 refs_->DecRefCount();
307 refs_ = nullptr;
308 }
309 }
310
ExtendObjectLifetime()311 void RefBase::ExtendObjectLifetime()
312 {
313 refs_->ExtendObjectLifetime();
314 }
315
IncStrongRef(const void * objectId)316 void RefBase::IncStrongRef(const void *objectId)
317 {
318 if (refs_ == nullptr) {
319 return;
320 }
321
322 const int curCount = refs_->IncStrongRefCount(objectId);
323 IncWeakRef(objectId);
324 if (curCount == INITIAL_PRIMARY_VALUE) {
325 OnFirstStrongRef(objectId);
326 }
327 if (refs_->IsAttemptAcquireSet()) {
328 refs_->ClearAttemptAcquire();
329 refs_->DecStrongRefCount(objectId);
330 refs_->DecWeakRefCount(objectId);
331 }
332 }
333
DecStrongRef(const void * objectId)334 void RefBase::DecStrongRef(const void *objectId)
335 {
336 if (refs_ == nullptr) {
337 return;
338 }
339
340 const int curCount = refs_->DecStrongRefCount(objectId);
341 if (curCount == 1) {
342 OnLastStrongRef(objectId);
343 }
344 DecWeakRef(objectId);
345 }
346
GetSptrRefCount()347 int RefBase::GetSptrRefCount()
348 {
349 if (refs_ == nullptr) {
350 return 0;
351 }
352 return refs_->GetStrongRefCount();
353 }
354
CreateWeakRef(void * cookie)355 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
356 {
357 if (refs_ != nullptr) {
358 return new WeakRefCounter(refs_, cookie);
359 }
360 return nullptr;
361 }
362
IncWeakRef(const void * objectId)363 void RefBase::IncWeakRef(const void *objectId)
364 {
365 if (refs_ != nullptr) {
366 refs_->IncWeakRefCount(objectId);
367 }
368 }
369
DecWeakRef(const void * objectId)370 void RefBase::DecWeakRef(const void *objectId)
371 {
372 if (refs_ != nullptr) {
373 refs_->DecWeakRefCount(objectId);
374 }
375 }
376
GetWptrRefCount()377 int RefBase::GetWptrRefCount()
378 {
379 if (refs_ == nullptr) {
380 return 0;
381 }
382 return refs_->GetWeakRefCount();
383 }
384
AttemptAcquire(const void * objectId)385 bool RefBase::AttemptAcquire(const void *objectId)
386 {
387 if (refs_ == nullptr) {
388 return false;
389 }
390
391 int count = 0;
392 if (refs_->AttemptIncStrongRef(objectId, count)) {
393 refs_->SetAttemptAcquire();
394 if (count == INITIAL_PRIMARY_VALUE) {
395 OnFirstStrongRef(objectId);
396 }
397
398 return true;
399 }
400 return false;
401 }
402
AttemptIncStrongRef(const void * objectId)403 bool RefBase::AttemptIncStrongRef(const void *objectId)
404 {
405 if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
406 int count = 0;
407 bool ret = refs_->AttemptIncStrongRef(objectId, count);
408 if (count == INITIAL_PRIMARY_VALUE) {
409 OnFirstStrongRef(objectId);
410 }
411 return ret;
412 }
413
414 return false;
415 }
416
IsAttemptAcquireSet()417 bool RefBase::IsAttemptAcquireSet()
418 {
419 if (refs_ == nullptr) {
420 return false;
421 }
422 return refs_->IsAttemptAcquireSet();
423 }
424
IsExtendLifeTimeSet()425 bool RefBase::IsExtendLifeTimeSet()
426 {
427 if (refs_ == nullptr) {
428 return false;
429 }
430 return refs_->IsLifeTimeExtended();
431 }
432
OnFirstStrongRef(const void *)433 void RefBase::OnFirstStrongRef(const void* /*objectId*/)
434 {}
435
OnLastStrongRef(const void *)436 void RefBase::OnLastStrongRef(const void* /*objectId*/)
437 {}
438
OnLastWeakRef(const void *)439 void RefBase::OnLastWeakRef(const void* /*objectId*/)
440 {}
441
OnAttemptPromoted(const void *)442 bool RefBase::OnAttemptPromoted(const void* /*objectId*/)
443 {
444 return true;
445 }
446
447 } // namespace OHOS
448