]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc/ReadWriteLock.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / ipc / ReadWriteLock.cc
CommitLineData
44c95fcf 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
44c95fcf
AR
7 */
8
bbc27441
AJ
9/* DEBUG: section 54 Interprocess Communication */
10
582c2af2 11#include "squid.h"
44c95fcf 12#include "ipc/ReadWriteLock.h"
602d9612 13#include "Store.h"
44c95fcf 14
abf396ec
AR
15void Ipc::AssertFlagIsSet(std::atomic_flag &flag)
16{
17 // If the flag was false, then we set it to true and assert. A true flag
18 // may help keep other processes away from this broken entry.
19 // Otherwise, we just set an already set flag, which is probably a no-op.
20 assert(flag.test_and_set(std::memory_order_relaxed));
21}
22
44c95fcf
AR
23bool
24Ipc::ReadWriteLock::lockShared()
25{
92e29797
AR
26 ++readLevel; // this locks "new" writers out
27 if (!writeLevel || appending) { // nobody is writing, or sharing is OK
28 ++readers;
44c95fcf 29 return true;
92e29797
AR
30 }
31 --readLevel;
44c95fcf
AR
32 return false;
33}
34
35bool
36Ipc::ReadWriteLock::lockExclusive()
37{
92e29797
AR
38 if (!writeLevel++) { // we are the first writer + lock "new" readers out
39 if (!readLevel) { // no old readers and nobody is becoming one
40 writing = true;
44c95fcf 41 return true;
92e29797 42 }
44c95fcf 43 }
92e29797 44 --writeLevel;
44c95fcf
AR
45 return false;
46}
47
abf396ec
AR
48bool
49Ipc::ReadWriteLock::lockHeaders()
50{
51 if (lockShared()) {
52 if (!updating.test_and_set(std::memory_order_acquire))
53 return true; // we got here first
54 // the updating lock was already set by somebody else
55 unlockShared();
56 }
57 return false;
58}
59
44c95fcf
AR
60void
61Ipc::ReadWriteLock::unlockShared()
62{
92e29797
AR
63 assert(readers > 0);
64 --readers;
65 --readLevel;
44c95fcf
AR
66}
67
68void
69Ipc::ReadWriteLock::unlockExclusive()
70{
92e29797
AR
71 assert(writing);
72 appending = false;
73 writing = false;
74 --writeLevel;
44c95fcf
AR
75}
76
abf396ec
AR
77void
78Ipc::ReadWriteLock::unlockHeaders()
79{
80 AssertFlagIsSet(updating);
81 updating.clear(std::memory_order_release);
82 unlockShared();
83}
84
44c95fcf
AR
85void
86Ipc::ReadWriteLock::switchExclusiveToShared()
87{
92e29797
AR
88 assert(writing);
89 ++readLevel; // must be done before we release exclusive control
90 ++readers;
44c95fcf
AR
91 unlockExclusive();
92}
93
d1d3b4dc
EB
94bool
95Ipc::ReadWriteLock::unlockSharedAndSwitchToExclusive()
96{
97 assert(readers > 0);
98 if (!writeLevel++) { // we are the first writer + lock "new" readers out
99 assert(!appending);
100 unlockShared();
101 if (!readers) {
102 writing = true;
103 return true;
104 }
105 // somebody is still reading: fall through
106 } else {
107 // somebody is still writing: just stop reading
108 unlockShared();
109 }
110 --writeLevel;
111 return false;
112}
113
ce49546e
AR
114void
115Ipc::ReadWriteLock::startAppending()
116{
92e29797
AR
117 assert(writing);
118 appending = true;
ce49546e
AR
119}
120
44c95fcf
AR
121void
122Ipc::ReadWriteLock::updateStats(ReadWriteLockStats &stats) const
123{
124 if (readers) {
125 ++stats.readable;
126 stats.readers += readers;
92e29797 127 } else if (writing) {
44c95fcf 128 ++stats.writeable;
92e29797 129 ++stats.writers;
ce49546e 130 stats.appenders += appending;
44c95fcf
AR
131 } else {
132 ++stats.idle;
133 }
134 ++stats.count;
135}
136
44c95fcf
AR
137/* Ipc::ReadWriteLockStats */
138
139Ipc::ReadWriteLockStats::ReadWriteLockStats()
140{
141 memset(this, 0, sizeof(*this));
142}
9199139f 143
44c95fcf
AR
144void
145Ipc::ReadWriteLockStats::dump(StoreEntry &e) const
146{
147 storeAppendPrintf(&e, "Available locks: %9d\n", count);
148
149 if (!count)
150 return;
151
152 storeAppendPrintf(&e, "Reading: %9d %6.2f%%\n",
9199139f 153 readable, (100.0 * readable / count));
44c95fcf 154 storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n",
9199139f 155 writeable, (100.0 * writeable / count));
44c95fcf 156 storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n",
9199139f 157 idle, (100.0 * idle / count));
44c95fcf
AR
158
159 if (readers || writers) {
160 const int locked = readers + writers;
161 storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n",
9199139f 162 readers, (100.0 * readers / locked));
ce49546e
AR
163 const double appPerc = writers ? (100.0 * appenders / writers) : 0.0;
164 storeAppendPrintf(&e, "Writers: %9d %6.2f%% including Appenders: %9d %6.2f%%\n",
165 writers, (100.0 * writers / locked),
166 appenders, appPerc);
44c95fcf
AR
167 }
168}
f53969cc 169
b2aca62a
EB
170std::ostream &
171Ipc::operator <<(std::ostream &os, const Ipc::ReadWriteLock &lock)
172{
173 return os << lock.readers << 'R' <<
174 (lock.writing ? "W" : "") <<
175 (lock.appending ? "A" : "");
176 // impossible to report lock.updating without setting/clearing that flag
177}
178