Squid Web Cache master
Loading...
Searching...
No Matches
ReadWriteLock.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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
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
27bool
29{
30 assert(writeLevel); // "new" readers are locked out by the caller
31 assert(!appending); // nobody can be appending without an exclusive lock
32 if (!readLevel) { // no old readers and nobody is becoming a reader
33 writing = true;
34 return true;
35 }
36 --writeLevel;
37 return false;
38}
39
40bool
42{
43 ++readLevel; // this locks "new" writers out
44 if (!writeLevel || appending) { // nobody is writing, or sharing is OK
45 ++readers;
46 return true;
47 }
48 --readLevel;
49 return false;
50}
51
52bool
54{
55 if (!writeLevel++) // we are the first writer + lock "new" readers out
56 return finalizeExclusive(); // decrements writeLevel on failures
57
58 --writeLevel;
59 return false;
60}
61
62bool
64{
65 if (lockShared()) {
66 if (!updating.test_and_set(std::memory_order_acquire))
67 return true; // we got here first
68 // the updating lock was already set by somebody else
69 unlockShared();
70 }
71 return false;
72}
73
74void
76{
77 assert(readers > 0);
78 --readers;
79 --readLevel;
80}
81
82void
84{
85 assert(writing);
86 appending = false;
87 writing = false;
88 --writeLevel;
89}
90
91void
93{
94 AssertFlagIsSet(updating);
95 updating.clear(std::memory_order_release);
96 unlockShared();
97}
98
99void
101{
102 assert(writing);
103 ++readLevel; // must be done before we release exclusive control
104 ++readers;
105 unlockExclusive();
106}
107
108bool
110{
111 assert(readers > 0);
112 if (!writeLevel++) { // we are the first writer + lock "new" readers out
113 unlockShared();
114 return finalizeExclusive(); // decrements writeLevel on failures
115 }
116
117 // somebody is still writing, so we just stop reading
118 unlockShared();
119 --writeLevel;
120 return false;
121}
122
123void
125{
126 assert(writing);
127 appending = true;
128}
129
130bool
132{
133 assert(writing);
134 assert(appending);
135
136 appending = false;
137
138 // Checking `readers` here would mishandle a lockShared() call that started
139 // before we banned appending above, saw still true `appending`, got on a
140 // "success" code path, but had not incremented the `readers` counter yet.
141 // Checking `readLevel` mishandles lockShared() that saw false `appending`,
142 // got on a "failure" code path, but had not decremented `readLevel` yet.
143 // Our callers prefer the wrong "false" to the wrong "true" result.
144 return !readLevel;
145}
146
147void
149{
150 if (readers) {
151 ++stats.readable;
152 stats.readers += readers;
153 } else if (writing) {
154 ++stats.writeable;
155 ++stats.writers;
156 stats.appenders += appending;
157 } else {
158 ++stats.idle;
159 }
160 ++stats.count;
161}
162
163/* Ipc::ReadWriteLockStats */
164
166{
167 memset(this, 0, sizeof(*this));
168}
169
170void
172{
173 storeAppendPrintf(&e, "Available locks: %9d\n", count);
174
175 if (!count)
176 return;
177
178 storeAppendPrintf(&e, "Reading: %9d %6.2f%%\n",
179 readable, (100.0 * readable / count));
180 storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n",
181 writeable, (100.0 * writeable / count));
182 storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n",
183 idle, (100.0 * idle / count));
184
185 if (readers || writers) {
186 const int locked = readers + writers;
187 storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n",
188 readers, (100.0 * readers / locked));
189 const double appPerc = writers ? (100.0 * appenders / writers) : 0.0;
190 storeAppendPrintf(&e, "Writers: %9d %6.2f%% including Appenders: %9d %6.2f%%\n",
191 writers, (100.0 * writers / locked),
192 appenders, appPerc);
193 }
194}
195
196std::ostream &
197Ipc::operator <<(std::ostream &os, const Ipc::ReadWriteLock &lock)
198{
199 return os << lock.readers << 'R' <<
200 (lock.writing ? "W" : "") <<
201 (lock.appending ? "A" : "");
202 // impossible to report lock.updating without setting/clearing that flag
203}
204
#define assert(EX)
Definition assert.h:17
approximate stats of a set of ReadWriteLocks
int readable
number of locks locked for reading
int idle
number of unlocked locks
int writers
sum of lock.writers
int count
the total number of locks
void dump(StoreEntry &e) const
int writeable
number of locks locked for writing
int readers
sum of lock.readers
int appenders
number of appending writers
void unlockHeaders()
undo successful lockHeaders()
std::atomic< uint32_t > readLevel
number of users reading (or trying to)
bool lockHeaders()
lock for [readable] metadata update or return false
std::atomic< uint32_t > readers
number of reading users
void unlockExclusive()
undo successful exclusiveLock()
bool lockExclusive()
lock for modification or return false
bool stopAppendingAndRestoreExclusive()
std::atomic< uint32_t > writeLevel
number of users writing (or trying to write)
std::atomic< bool > writing
there is a writing user (there can be at most 1)
bool unlockSharedAndSwitchToExclusive()
std::atomic< bool > appending
the writer has promised to only append
void unlockShared()
undo successful sharedLock()
bool lockShared()
lock for reading or return false
void updateStats(ReadWriteLockStats &stats) const
adds approximate current stats to the supplied ones
void startAppending()
writer keeps its lock but also allows reading
void AssertFlagIsSet(std::atomic_flag &flag)
std::ostream & operator<<(std::ostream &os, const QuestionerId &qid)
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition store.cc:855