]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/ReadWriteLock.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / ipc / ReadWriteLock.cc
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
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 void
95 Ipc::ReadWriteLock::startAppending()
96 {
97 assert(writing);
98 appending = true;
99 }
100
101 void
102 Ipc::ReadWriteLock::updateStats(ReadWriteLockStats &stats) const
103 {
104 if (readers) {
105 ++stats.readable;
106 stats.readers += readers;
107 } else if (writing) {
108 ++stats.writeable;
109 ++stats.writers;
110 stats.appenders += appending;
111 } else {
112 ++stats.idle;
113 }
114 ++stats.count;
115 }
116
117 /* Ipc::ReadWriteLockStats */
118
119 Ipc::ReadWriteLockStats::ReadWriteLockStats()
120 {
121 memset(this, 0, sizeof(*this));
122 }
123
124 void
125 Ipc::ReadWriteLockStats::dump(StoreEntry &e) const
126 {
127 storeAppendPrintf(&e, "Available locks: %9d\n", count);
128
129 if (!count)
130 return;
131
132 storeAppendPrintf(&e, "Reading: %9d %6.2f%%\n",
133 readable, (100.0 * readable / count));
134 storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n",
135 writeable, (100.0 * writeable / count));
136 storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n",
137 idle, (100.0 * idle / count));
138
139 if (readers || writers) {
140 const int locked = readers + writers;
141 storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n",
142 readers, (100.0 * readers / locked));
143 const double appPerc = writers ? (100.0 * appenders / writers) : 0.0;
144 storeAppendPrintf(&e, "Writers: %9d %6.2f%% including Appenders: %9d %6.2f%%\n",
145 writers, (100.0 * writers / locked),
146 appenders, appPerc);
147 }
148 }
149