]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/ReadWriteLock.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / ipc / ReadWriteLock.cc
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
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.
7 */
8
9 /* DEBUG: section 54 Interprocess Communication */
10
11 #include "squid.h"
12 #include "ipc/ReadWriteLock.h"
13 #include "Store.h"
14
15 void 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
23 bool
24 Ipc::ReadWriteLock::lockShared()
25 {
26 ++readLevel; // this locks "new" writers out
27 if (!writeLevel || appending) { // nobody is writing, or sharing is OK
28 ++readers;
29 return true;
30 }
31 --readLevel;
32 return false;
33 }
34
35 bool
36 Ipc::ReadWriteLock::lockExclusive()
37 {
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;
41 return true;
42 }
43 }
44 --writeLevel;
45 return false;
46 }
47
48 bool
49 Ipc::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
60 void
61 Ipc::ReadWriteLock::unlockShared()
62 {
63 assert(readers > 0);
64 --readers;
65 --readLevel;
66 }
67
68 void
69 Ipc::ReadWriteLock::unlockExclusive()
70 {
71 assert(writing);
72 appending = false;
73 writing = false;
74 --writeLevel;
75 }
76
77 void
78 Ipc::ReadWriteLock::unlockHeaders()
79 {
80 AssertFlagIsSet(updating);
81 updating.clear(std::memory_order_release);
82 unlockShared();
83 }
84
85 void
86 Ipc::ReadWriteLock::switchExclusiveToShared()
87 {
88 assert(writing);
89 ++readLevel; // must be done before we release exclusive control
90 ++readers;
91 unlockExclusive();
92 }
93
94 bool
95 Ipc::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
114 void
115 Ipc::ReadWriteLock::startAppending()
116 {
117 assert(writing);
118 appending = true;
119 }
120
121 void
122 Ipc::ReadWriteLock::updateStats(ReadWriteLockStats &stats) const
123 {
124 if (readers) {
125 ++stats.readable;
126 stats.readers += readers;
127 } else if (writing) {
128 ++stats.writeable;
129 ++stats.writers;
130 stats.appenders += appending;
131 } else {
132 ++stats.idle;
133 }
134 ++stats.count;
135 }
136
137 /* Ipc::ReadWriteLockStats */
138
139 Ipc::ReadWriteLockStats::ReadWriteLockStats()
140 {
141 memset(this, 0, sizeof(*this));
142 }
143
144 void
145 Ipc::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",
153 readable, (100.0 * readable / count));
154 storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n",
155 writeable, (100.0 * writeable / count));
156 storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n",
157 idle, (100.0 * idle / count));
158
159 if (readers || writers) {
160 const int locked = readers + writers;
161 storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n",
162 readers, (100.0 * readers / locked));
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);
167 }
168 }
169
170 std::ostream &
171 Ipc::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