ReadWriteLock.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 
27 bool
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 
40 bool
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 
52 bool
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 
62 bool
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 
74 void
76 {
77  assert(readers > 0);
78  --readers;
79  --readLevel;
80 }
81 
82 void
84 {
85  assert(writing);
86  appending = false;
87  writing = false;
88  --writeLevel;
89 }
90 
91 void
93 {
94  AssertFlagIsSet(updating);
95  updating.clear(std::memory_order_release);
96  unlockShared();
97 }
98 
99 void
101 {
102  assert(writing);
103  ++readLevel; // must be done before we release exclusive control
104  ++readers;
105  unlockExclusive();
106 }
107 
108 bool
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 
123 void
125 {
126  assert(writing);
127  appending = true;
128 }
129 
130 void
132 {
133  if (readers) {
134  ++stats.readable;
135  stats.readers += readers;
136  } else if (writing) {
137  ++stats.writeable;
138  ++stats.writers;
139  stats.appenders += appending;
140  } else {
141  ++stats.idle;
142  }
143  ++stats.count;
144 }
145 
146 /* Ipc::ReadWriteLockStats */
147 
149 {
150  memset(this, 0, sizeof(*this));
151 }
152 
153 void
155 {
156  storeAppendPrintf(&e, "Available locks: %9d\n", count);
157 
158  if (!count)
159  return;
160 
161  storeAppendPrintf(&e, "Reading: %9d %6.2f%%\n",
162  readable, (100.0 * readable / count));
163  storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n",
164  writeable, (100.0 * writeable / count));
165  storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n",
166  idle, (100.0 * idle / count));
167 
168  if (readers || writers) {
169  const int locked = readers + writers;
170  storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n",
171  readers, (100.0 * readers / locked));
172  const double appPerc = writers ? (100.0 * appenders / writers) : 0.0;
173  storeAppendPrintf(&e, "Writers: %9d %6.2f%% including Appenders: %9d %6.2f%%\n",
174  writers, (100.0 * writers / locked),
175  appenders, appPerc);
176  }
177 }
178 
179 std::ostream &
180 Ipc::operator <<(std::ostream &os, const Ipc::ReadWriteLock &lock)
181 {
182  return os << lock.readers << 'R' <<
183  (lock.writing ? "W" : "") <<
184  (lock.appending ? "A" : "");
185  // impossible to report lock.updating without setting/clearing that flag
186 }
187 
class Ping::pingStats_ stats
approximate stats of a set of ReadWriteLocks
Definition: ReadWriteLock.h:66
std::atomic< bool > writing
there is a writing user (there can be at most 1)
Definition: ReadWriteLock.h:50
bool lockShared()
lock for reading or return false
bool unlockSharedAndSwitchToExclusive()
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:830
void updateStats(ReadWriteLockStats &stats) const
adds approximate current stats to the supplied ones
bool lockExclusive()
lock for modification or return false
std::atomic< bool > appending
the writer has promised to only append
Definition: ReadWriteLock.h:51
void unlockShared()
undo successful sharedLock()
std::atomic< uint32_t > readers
number of reading users
Definition: ReadWriteLock.h:49
void unlockExclusive()
undo successful exclusiveLock()
#define assert(EX)
Definition: assert.h:19
bool lockHeaders()
lock for [readable] metadata update or return false
void dump(StoreEntry &e) const
void unlockHeaders()
undo successful lockHeaders()
void AssertFlagIsSet(std::atomic_flag &flag)
std::atomic< uint32_t > writeLevel
number of users writing (or trying to write)
Definition: ReadWriteLock.h:58
std::ostream & operator<<(std::ostream &os, const QuestionerId &qid)
Definition: QuestionerId.h:63
void switchExclusiveToShared()
void startAppending()
writer keeps its lock but also allows reading
std::atomic< uint32_t > readLevel
number of users reading (or trying to)
Definition: ReadWriteLock.h:57

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors