1e5c4badcSopenharmony_ci/*
2e5c4badcSopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
3e5c4badcSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e5c4badcSopenharmony_ci * you may not use this file except in compliance with the License.
5e5c4badcSopenharmony_ci * You may obtain a copy of the License at
6e5c4badcSopenharmony_ci *
7e5c4badcSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e5c4badcSopenharmony_ci *
9e5c4badcSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e5c4badcSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e5c4badcSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e5c4badcSopenharmony_ci * See the License for the specific language governing permissions and
13e5c4badcSopenharmony_ci * limitations under the License.
14e5c4badcSopenharmony_ci */
15e5c4badcSopenharmony_ci
16e5c4badcSopenharmony_ci#include "rwlock.h"
17e5c4badcSopenharmony_ci#include <cassert>
18e5c4badcSopenharmony_ci
19e5c4badcSopenharmony_cinamespace OHOS {
20e5c4badcSopenharmony_cinamespace Utils {
21e5c4badcSopenharmony_ciRWLock::RWLock(bool writeFirst)
22e5c4badcSopenharmony_ci    : writeFirst_(writeFirst), writeThreadID_(), lockCount_(0), writeWaitCount_(0)
23e5c4badcSopenharmony_ci{
24e5c4badcSopenharmony_ci}
25e5c4badcSopenharmony_ci
26e5c4badcSopenharmony_civoid RWLock::LockRead()
27e5c4badcSopenharmony_ci{
28e5c4badcSopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
29e5c4badcSopenharmony_ci        int count;
30e5c4badcSopenharmony_ci        if (writeFirst_) {
31e5c4badcSopenharmony_ci            do {
32e5c4badcSopenharmony_ci                // In write priority mode, the state must be non-write locked and no other threads are waiting to write
33e5c4badcSopenharmony_ci                while ((count = lockCount_) == LOCK_STATUS_WRITE || writeWaitCount_ > 0) {
34e5c4badcSopenharmony_ci                }
35e5c4badcSopenharmony_ci            } while (!lockCount_.compare_exchange_weak(count, count + 1));
36e5c4badcSopenharmony_ci        } else {
37e5c4badcSopenharmony_ci            do {
38e5c4badcSopenharmony_ci                // If it is not write priority, you only need the current state to be non-write-locked.
39e5c4badcSopenharmony_ci                while ((count = lockCount_) == LOCK_STATUS_WRITE) {}
40e5c4badcSopenharmony_ci            } while (!lockCount_.compare_exchange_weak(count, count + 1));
41e5c4badcSopenharmony_ci        }
42e5c4badcSopenharmony_ci    }
43e5c4badcSopenharmony_ci}
44e5c4badcSopenharmony_ci
45e5c4badcSopenharmony_civoid RWLock::UnLockRead()
46e5c4badcSopenharmony_ci{
47e5c4badcSopenharmony_ci    // Supports the case of writing and reading nesting.
48e5c4badcSopenharmony_ci    // If the write lock has been obtained before, the read lock is directly returned successfully,
49e5c4badcSopenharmony_ci    // and then the thread is still directly returned when unlocking.
50e5c4badcSopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
51e5c4badcSopenharmony_ci        --lockCount_;
52e5c4badcSopenharmony_ci    }
53e5c4badcSopenharmony_ci}
54e5c4badcSopenharmony_ci
55e5c4badcSopenharmony_civoid RWLock::LockWrite()
56e5c4badcSopenharmony_ci{
57e5c4badcSopenharmony_ci    // If this thread is already a thread that gets the write lock, return directly to avoid repeated locks.
58e5c4badcSopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
59e5c4badcSopenharmony_ci        ++writeWaitCount_; // Write wait counter plus 1
60e5c4badcSopenharmony_ci
61e5c4badcSopenharmony_ci        // Only when no thread has acquired a read lock or a write lock (the lock counter status is FREE)
62e5c4badcSopenharmony_ci        // can the write lock be acquired and the counter set to WRITE; otherwise wait
63e5c4badcSopenharmony_ci        for (int status = LOCK_STATUS_FREE; !lockCount_.compare_exchange_weak(status, LOCK_STATUS_WRITE);
64e5c4badcSopenharmony_ci            status = LOCK_STATUS_FREE) {
65e5c4badcSopenharmony_ci        }
66e5c4badcSopenharmony_ci
67e5c4badcSopenharmony_ci        // After the write lock is successfully acquired, the write wait counter is decremented by 1.
68e5c4badcSopenharmony_ci        --writeWaitCount_;
69e5c4badcSopenharmony_ci        writeThreadID_ = std::this_thread::get_id();
70e5c4badcSopenharmony_ci    }
71e5c4badcSopenharmony_ci}
72e5c4badcSopenharmony_ci
73e5c4badcSopenharmony_civoid RWLock::UnLockWrite()
74e5c4badcSopenharmony_ci{
75e5c4badcSopenharmony_ci    if (std::this_thread::get_id() != writeThreadID_) {
76e5c4badcSopenharmony_ci        return;
77e5c4badcSopenharmony_ci    }
78e5c4badcSopenharmony_ci
79e5c4badcSopenharmony_ci    if (lockCount_ != LOCK_STATUS_WRITE) {
80e5c4badcSopenharmony_ci        return;
81e5c4badcSopenharmony_ci    }
82e5c4badcSopenharmony_ci
83e5c4badcSopenharmony_ci    writeThreadID_ = std::thread::id();
84e5c4badcSopenharmony_ci    lockCount_.store(LOCK_STATUS_FREE);
85e5c4badcSopenharmony_ci}
86e5c4badcSopenharmony_ci} // namespace Utils
87e5c4badcSopenharmony_ci} // namespace OHOS
88