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