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 19namespace OHOS { 20WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie) 21 : atomicWeak_(0), refCounter_(counter), cookie_(cookie) 22{ 23 if (refCounter_ != nullptr) { 24 refCounter_->IncRefCount(); 25 } 26} 27 28WeakRefCounter::~WeakRefCounter() 29{ 30 if (refCounter_ != nullptr) { 31 refCounter_->DecRefCount(); 32 } 33} 34 35void* WeakRefCounter::GetRefPtr() 36{ 37 if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) { 38 cookie_ = nullptr; 39 } 40 return cookie_; 41} 42 43void WeakRefCounter::IncWeakRefCount(const void *objectId) 44{ 45 if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) { 46 refCounter_->IncWeakRefCount(objectId); 47 } 48} 49 50void 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 58bool WeakRefCounter::AttemptIncStrongRef(const void *objectId) 59{ 60 int unuse = 0; 61 return refCounter_->AttemptIncStrongRef(objectId, unuse); 62} 63 64RefCounter::RefCounter() 65 : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0) 66{ 67} 68int RefCounter::GetRefCount() 69{ 70 return atomicRefCount_.load(std::memory_order_relaxed); 71} 72 73void RefCounter::IncRefCount() 74{ 75 atomicRefCount_.fetch_add(1, std::memory_order_relaxed); 76} 77 78void 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 87void RefCounter::SetCallback(const RefPtrCallback& callback) 88{ 89 callback_ = callback; 90} 91 92void RefCounter::RemoveCallback() 93{ 94 callback_ = nullptr; 95} 96 97bool RefCounter::IsRefPtrValid() 98{ 99 return callback_ != nullptr; 100} 101 102RefCounter::~RefCounter() 103{ 104} 105 106int 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 118int 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 131int RefCounter::GetStrongRefCount() 132{ 133 return atomicStrong_.load(std::memory_order_relaxed); 134} 135 136int RefCounter::IncWeakRefCount(const void * /*objectId*/) 137{ 138 return atomicWeak_.fetch_add(1, std::memory_order_relaxed); 139} 140 141int 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 156int RefCounter::GetWeakRefCount() 157{ 158 return atomicWeak_.load(std::memory_order_relaxed); 159} 160 161void RefCounter::SetAttemptAcquire() 162{ 163 (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed); 164} 165 166bool RefCounter::IsAttemptAcquireSet() 167{ 168 return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0); 169} 170 171void RefCounter::ClearAttemptAcquire() 172{ 173 atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); 174} 175 176void RefCounter::ExtendObjectLifetime() 177{ 178 atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed); 179} 180 181bool RefCounter::IsLifeTimeExtended() 182{ 183 return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME); 184} 185 186bool 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 216attempt_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 231RefBase::RefBase() : refs_(new RefCounter()) 232{ 233 refs_->IncRefCount(); 234 refs_->SetCallback([this] { 235 this->RefPtrCallback(); 236 }); 237} 238 239RefBase::RefBase(const RefBase& /*other*/) 240{ 241 refs_ = new RefCounter(); 242 if (refs_ != nullptr) { 243 refs_->IncRefCount(); 244 refs_->SetCallback([this] { 245 this->RefPtrCallback(); 246 }); 247 } 248} 249 250void RefBase::RefPtrCallback() 251{ 252 delete this; 253} 254 255/* 256 * The two ends of the assignment are two independent and exclusive, 257 * and the application should not share the reference counter. 258 * RISK: If there is a reference count on the left of the equal sign, 259 * it may cause a reference count exception 260 */ 261RefBase &RefBase::operator=(const RefBase& /*other*/) 262{ 263 if (refs_ != nullptr) { 264 refs_->RemoveCallback(); 265 refs_->DecRefCount(); 266 } 267 refs_ = new RefCounter(); 268 if (refs_ != nullptr) { 269 refs_->IncRefCount(); 270 refs_->SetCallback([this] { 271 this->RefPtrCallback(); 272 }); 273 } 274 return *this; 275} 276 277RefBase::RefBase(RefBase &&other) noexcept 278{ 279 refs_ = other.refs_; 280 other.refs_ = nullptr; 281} 282 283RefBase &RefBase::operator=(RefBase &&other) noexcept 284{ 285 if (refs_ == other.refs_) { 286 return *this; 287 } 288 if (refs_ != nullptr) { 289 refs_->RemoveCallback(); 290 refs_->DecRefCount(); 291 } 292 refs_ = other.refs_; 293 other.refs_ = nullptr; 294 return *this; 295} 296 297RefBase::~RefBase() 298{ 299 if (refs_ != nullptr) { 300 refs_->RemoveCallback(); 301 refs_->DecRefCount(); 302 refs_ = nullptr; 303 } 304} 305 306void RefBase::ExtendObjectLifetime() 307{ 308 refs_->ExtendObjectLifetime(); 309} 310 311void RefBase::IncStrongRef(const void *objectId) 312{ 313 if (refs_ == nullptr) { 314 return; 315 } 316 const int curCount = refs_->IncStrongRefCount(objectId); 317 IncWeakRef(objectId); 318 if (curCount == INITIAL_PRIMARY_VALUE) { 319 OnFirstStrongRef(objectId); 320 } 321 if (refs_->IsAttemptAcquireSet()) { 322 refs_->ClearAttemptAcquire(); 323 refs_->DecStrongRefCount(objectId); 324 } 325} 326 327void RefBase::DecStrongRef(const void *objectId) 328{ 329 if (refs_ == nullptr) { 330 return; 331 } 332 const int curCount = refs_->DecStrongRefCount(objectId); 333 if (curCount == 1) { 334 OnLastStrongRef(objectId); 335 } 336 DecWeakRef(objectId); 337} 338 339int RefBase::GetSptrRefCount() 340{ 341 if (refs_ != nullptr) { 342 return refs_->GetStrongRefCount(); 343 } else { 344 return 0; 345 } 346} 347 348WeakRefCounter *RefBase::CreateWeakRef(void *cookie) 349{ 350 if (refs_ != nullptr) { 351 return new WeakRefCounter(refs_, cookie); 352 } 353 354 return nullptr; 355} 356 357void RefBase::IncWeakRef(const void *objectId) 358{ 359 if (refs_ != nullptr) { 360 refs_->IncWeakRefCount(objectId); 361 } 362} 363 364void RefBase::DecWeakRef(const void *objectId) 365{ 366 if (refs_ != nullptr) { 367 refs_->DecWeakRefCount(objectId); 368 } 369} 370 371int RefBase::GetWptrRefCount() 372{ 373 if (refs_ != nullptr) { 374 return refs_->GetWeakRefCount(); 375 } else { 376 return 0; 377 } 378} 379 380bool RefBase::AttemptAcquire(const void *objectId) 381{ 382 if (refs_ != nullptr) { 383 int count = 0; 384 if (refs_->AttemptIncStrongRef(objectId, count)) { 385 if (count == INITIAL_PRIMARY_VALUE) { 386 OnFirstStrongRef(objectId); 387 } 388 refs_->SetAttemptAcquire(); 389 return true; 390 } 391 } 392 return false; 393} 394 395bool RefBase::AttemptIncStrongRef(const void *objectId) 396{ 397 if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) { 398 int count = 0; 399 bool ret = refs_->AttemptIncStrongRef(objectId, count); 400 if (count == INITIAL_PRIMARY_VALUE) { 401 OnFirstStrongRef(objectId); 402 } 403 return ret; 404 } 405 return false; 406} 407 408bool RefBase::IsAttemptAcquireSet() 409{ 410 if (refs_ != nullptr) { 411 return refs_->IsAttemptAcquireSet(); 412 } 413 return false; 414} 415 416bool RefBase::IsExtendLifeTimeSet() 417{ 418 if (refs_ != nullptr) { 419 return refs_->IsLifeTimeExtended(); 420 } 421 return false; 422} 423 424void RefBase::OnFirstStrongRef(const void *) 425{} 426 427void RefBase::OnLastStrongRef(const void *) 428{} 429 430void RefBase::OnLastWeakRef(const void *) 431{} 432 433bool RefBase::OnAttemptPromoted(const void *) 434{ 435 return true; 436} 437} // namespace OHOS 438