ReadWriteLock.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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
Definition: ReadWriteLock.h:71
void dump(StoreEntry &e) const
void unlockHeaders()
undo successful lockHeaders()
std::atomic< uint32_t > readLevel
number of users reading (or trying to)
Definition: ReadWriteLock.h:62
void switchExclusiveToShared()
bool lockHeaders()
lock for [readable] metadata update or return false
std::atomic< uint32_t > readers
number of reading users
Definition: ReadWriteLock.h:54
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)
Definition: ReadWriteLock.h:63
std::atomic< bool > writing
there is a writing user (there can be at most 1)
Definition: ReadWriteLock.h:55
bool unlockSharedAndSwitchToExclusive()
std::atomic< bool > appending
the writer has promised to only append
Definition: ReadWriteLock.h:56
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)
Definition: QuestionerId.h:63
class Ping::pingStats_ stats
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:841

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors