ReadWriteLock.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 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
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
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
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
62 {
63  assert(readers > 0);
64  --readers;
65  --readLevel;
66 }
67 
68 void
70 {
71  assert(writing);
72  appending = false;
73  writing = false;
74  --writeLevel;
75 }
76 
77 void
79 {
80  AssertFlagIsSet(updating);
81  updating.clear(std::memory_order_release);
82  unlockShared();
83 }
84 
85 void
87 {
88  assert(writing);
89  ++readLevel; // must be done before we release exclusive control
90  ++readers;
91  unlockExclusive();
92 }
93 
94 bool
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
116 {
117  assert(writing);
118  appending = true;
119 }
120 
121 void
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 
140 {
141  memset(this, 0, sizeof(*this));
142 }
143 
144 void
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 
class Ping::pingStats_ stats
approximate stats of a set of ReadWriteLocks
Definition: ReadWriteLock.h:63
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:880
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()
std::ostream & operator<<(std::ostream &os, const Ipc::ReadWriteLock &)
dumps approximate lock state (for debugging)
#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:56
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:55

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors