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