1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #include <cassert>
19 
20 #include <phosphor/chunk_lock.h>
21 
22 namespace phosphor {
23 
ChunkLock(non_trivial_constructor_t t)24 ChunkLock::ChunkLock(non_trivial_constructor_t t)
25     : state(State::Unlocked) {
26 }
27 
ChunkLock(const ChunkLock& other)28 ChunkLock::ChunkLock(const ChunkLock& other)
29    : state(other.state.load()) {
30 }
31 
operator =(const ChunkLock& other)32 ChunkLock& ChunkLock::operator=(const ChunkLock& other) {
33     state = other.state.load();
34     return *this;
35 }
36 
lockSlave()37 void ChunkLock::lockSlave() {
38     auto expected = State::Unlocked;
39     while (!state.compare_exchange_weak(expected, State::SlaveLocked)) {
40         expected = State::Unlocked;
41     }
42 }
43 
tryLockSlave()44 bool ChunkLock::tryLockSlave() {
45     auto expected = State::Unlocked;
46     while (!state.compare_exchange_weak(expected, State::SlaveLocked)) {
47         if (expected == State::MasterLocked) {
48             return false;
49         }
50         expected = State::Unlocked;
51     }
52     return true;
53 }
54 
unlockSlave()55 void ChunkLock::unlockSlave() {
56 #ifdef NDEBUG
57     state.store(State::Unlocked, std::memory_order_release);
58 #else
59     auto expected = State::SlaveLocked;
60     assert(state.compare_exchange_strong(expected, State::Unlocked) &&
61            "ChunkLock::unlockSlave() should only be called while State::SlaveLocked");
62     (void)expected;
63 #endif
64 }
65 
slave()66 SlaveChunkLock& ChunkLock::slave() {
67     return static_cast<SlaveChunkLock&>(*this);
68 }
69 
lockMaster()70 void ChunkLock::lockMaster() {
71     auto expected = State::Unlocked;
72     while (!state.compare_exchange_weak(expected, State::MasterLocked)) {
73         expected = State::Unlocked;
74     }
75 }
76 
unlockMaster()77 void ChunkLock::unlockMaster() {
78 #ifdef NDEBUG
79     state.store(State::Unlocked, std::memory_order_release);
80 #else
81     auto expected = State::MasterLocked;
82     assert(state.compare_exchange_strong(expected, State::Unlocked) &&
83            "ChunkLock::unlockMaster() should only be called while State::MasterLocked");
84     (void)expected;
85 #endif
86 }
87 
master()88 MasterChunkLock& ChunkLock::master() {
89     return static_cast<MasterChunkLock&>(*this);
90 }
91 
lock()92 void SlaveChunkLock::lock() {
93     lockSlave();
94 }
95 
try_lock()96 bool SlaveChunkLock::try_lock() {
97     return tryLockSlave();
98 }
99 
unlock()100 void SlaveChunkLock::unlock() {
101     unlockSlave();
102 }
103 
lock()104 void MasterChunkLock::lock() {
105     lockMaster();
106 }
107 
unlock()108 void MasterChunkLock::unlock() {
109     unlockMaster();
110 }
111 
ChunkTenant(non_trivial_constructor_t t)112 ChunkTenant::ChunkTenant(non_trivial_constructor_t t)
113     : lck(non_trivial_constructor), chunk(nullptr), initialised(true) {
114 }
115 }
116