13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License.
53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at
63f4cbf05Sopenharmony_ci *
73f4cbf05Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83f4cbf05Sopenharmony_ci *
93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and
133f4cbf05Sopenharmony_ci * limitations under the License.
143f4cbf05Sopenharmony_ci */
153f4cbf05Sopenharmony_ci
163f4cbf05Sopenharmony_ci#include "rwlock.h"
173f4cbf05Sopenharmony_ci#include <cassert>
183f4cbf05Sopenharmony_ci
193f4cbf05Sopenharmony_cinamespace OHOS {
203f4cbf05Sopenharmony_cinamespace Utils {
213f4cbf05Sopenharmony_ci
223f4cbf05Sopenharmony_ciRWLock::RWLock(bool writeFirst)
233f4cbf05Sopenharmony_ci    : writeFirst_(writeFirst), writeThreadID_(), lockCount_(0), writeWaitCount_(0)
243f4cbf05Sopenharmony_ci{
253f4cbf05Sopenharmony_ci}
263f4cbf05Sopenharmony_ci
273f4cbf05Sopenharmony_civoid RWLock::LockRead()
283f4cbf05Sopenharmony_ci{
293f4cbf05Sopenharmony_ci    // If the thread has obtained the write lock, return directly.
303f4cbf05Sopenharmony_ci    if (std::this_thread::get_id() == writeThreadID_) {
313f4cbf05Sopenharmony_ci        return;
323f4cbf05Sopenharmony_ci    }
333f4cbf05Sopenharmony_ci
343f4cbf05Sopenharmony_ci    int count;
353f4cbf05Sopenharmony_ci    if (writeFirst_) {
363f4cbf05Sopenharmony_ci        do {
373f4cbf05Sopenharmony_ci            // In write priority mode, the state must be non-write locked and no other threads are waiting to write
383f4cbf05Sopenharmony_ci            while ((count = lockCount_) == LOCK_STATUS_WRITE || writeWaitCount_ > 0) {}
393f4cbf05Sopenharmony_ci        } while (!lockCount_.compare_exchange_weak(count, count + 1));
403f4cbf05Sopenharmony_ci    } else {
413f4cbf05Sopenharmony_ci        do {
423f4cbf05Sopenharmony_ci            // If it is not write priority, you only need the current state to be non-write-locked.
433f4cbf05Sopenharmony_ci            while ((count = lockCount_) == LOCK_STATUS_WRITE) {}
443f4cbf05Sopenharmony_ci        } while (!lockCount_.compare_exchange_weak(count, count + 1));
453f4cbf05Sopenharmony_ci    }
463f4cbf05Sopenharmony_ci}
473f4cbf05Sopenharmony_ci
483f4cbf05Sopenharmony_civoid RWLock::UnLockRead()
493f4cbf05Sopenharmony_ci{
503f4cbf05Sopenharmony_ci    // Supports the case of writing and reading nesting.
513f4cbf05Sopenharmony_ci    // If the write lock has been obtained before, the read lock is directly returned successfully,
523f4cbf05Sopenharmony_ci    // and then the thread is still directly returned when unlocking.
533f4cbf05Sopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
543f4cbf05Sopenharmony_ci        --lockCount_;
553f4cbf05Sopenharmony_ci    }
563f4cbf05Sopenharmony_ci}
573f4cbf05Sopenharmony_ci
583f4cbf05Sopenharmony_civoid RWLock::LockWrite()
593f4cbf05Sopenharmony_ci{
603f4cbf05Sopenharmony_ci    // If this thread is already a thread that gets the write lock, return directly to avoid repeated locks.
613f4cbf05Sopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
623f4cbf05Sopenharmony_ci        ++writeWaitCount_; // Write wait counter plus 1
633f4cbf05Sopenharmony_ci
643f4cbf05Sopenharmony_ci        // Only when no thread has acquired a read lock or a write lock (the lock counter status is FREE)
653f4cbf05Sopenharmony_ci        // can the write lock be acquired and the counter set to WRITE; otherwise wait
663f4cbf05Sopenharmony_ci        for (int status = LOCK_STATUS_FREE; !lockCount_.compare_exchange_weak(status, LOCK_STATUS_WRITE);
673f4cbf05Sopenharmony_ci            status = LOCK_STATUS_FREE) {
683f4cbf05Sopenharmony_ci        }
693f4cbf05Sopenharmony_ci
703f4cbf05Sopenharmony_ci        // After the write lock is successfully acquired, the write wait counter is decremented by 1.
713f4cbf05Sopenharmony_ci        --writeWaitCount_;
723f4cbf05Sopenharmony_ci        writeThreadID_ = std::this_thread::get_id();
733f4cbf05Sopenharmony_ci    }
743f4cbf05Sopenharmony_ci}
753f4cbf05Sopenharmony_ci
763f4cbf05Sopenharmony_civoid RWLock::UnLockWrite()
773f4cbf05Sopenharmony_ci{
783f4cbf05Sopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
793f4cbf05Sopenharmony_ci        return;
803f4cbf05Sopenharmony_ci    }
813f4cbf05Sopenharmony_ci
823f4cbf05Sopenharmony_ci    if (lockCount_ != LOCK_STATUS_WRITE) {
833f4cbf05Sopenharmony_ci        return;
843f4cbf05Sopenharmony_ci    }
853f4cbf05Sopenharmony_ci
863f4cbf05Sopenharmony_ci    writeThreadID_ = std::thread::id();
873f4cbf05Sopenharmony_ci    lockCount_.store(LOCK_STATUS_FREE);
883f4cbf05Sopenharmony_ci}
893f4cbf05Sopenharmony_ci
903f4cbf05Sopenharmony_ci} // namespace Utils
913f4cbf05Sopenharmony_ci} // namespace OHOS
92