]>
Commit | Line | Data |
---|---|---|
44c95fcf | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
bbc27441 AJ |
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. | |
44c95fcf AR |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 54 Interprocess Communication */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
44c95fcf | 12 | #include "ipc/ReadWriteLock.h" |
602d9612 | 13 | #include "Store.h" |
44c95fcf | 14 | |
abf396ec AR |
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 | ||
44c95fcf AR |
23 | bool |
24 | Ipc::ReadWriteLock::lockShared() | |
25 | { | |
92e29797 AR |
26 | ++readLevel; // this locks "new" writers out |
27 | if (!writeLevel || appending) { // nobody is writing, or sharing is OK | |
28 | ++readers; | |
44c95fcf | 29 | return true; |
92e29797 AR |
30 | } |
31 | --readLevel; | |
44c95fcf AR |
32 | return false; |
33 | } | |
34 | ||
35 | bool | |
36 | Ipc::ReadWriteLock::lockExclusive() | |
37 | { | |
92e29797 AR |
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; | |
44c95fcf | 41 | return true; |
92e29797 | 42 | } |
44c95fcf | 43 | } |
92e29797 | 44 | --writeLevel; |
44c95fcf AR |
45 | return false; |
46 | } | |
47 | ||
abf396ec AR |
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 | ||
44c95fcf AR |
60 | void |
61 | Ipc::ReadWriteLock::unlockShared() | |
62 | { | |
92e29797 AR |
63 | assert(readers > 0); |
64 | --readers; | |
65 | --readLevel; | |
44c95fcf AR |
66 | } |
67 | ||
68 | void | |
69 | Ipc::ReadWriteLock::unlockExclusive() | |
70 | { | |
92e29797 AR |
71 | assert(writing); |
72 | appending = false; | |
73 | writing = false; | |
74 | --writeLevel; | |
44c95fcf AR |
75 | } |
76 | ||
abf396ec AR |
77 | void |
78 | Ipc::ReadWriteLock::unlockHeaders() | |
79 | { | |
80 | AssertFlagIsSet(updating); | |
81 | updating.clear(std::memory_order_release); | |
82 | unlockShared(); | |
83 | } | |
84 | ||
44c95fcf AR |
85 | void |
86 | Ipc::ReadWriteLock::switchExclusiveToShared() | |
87 | { | |
92e29797 AR |
88 | assert(writing); |
89 | ++readLevel; // must be done before we release exclusive control | |
90 | ++readers; | |
44c95fcf AR |
91 | unlockExclusive(); |
92 | } | |
93 | ||
d1d3b4dc EB |
94 | bool |
95 | Ipc::ReadWriteLock::unlockSharedAndSwitchToExclusive() | |
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 | ||
ce49546e AR |
114 | void |
115 | Ipc::ReadWriteLock::startAppending() | |
116 | { | |
92e29797 AR |
117 | assert(writing); |
118 | appending = true; | |
ce49546e AR |
119 | } |
120 | ||
44c95fcf AR |
121 | void |
122 | Ipc::ReadWriteLock::updateStats(ReadWriteLockStats &stats) const | |
123 | { | |
124 | if (readers) { | |
125 | ++stats.readable; | |
126 | stats.readers += readers; | |
92e29797 | 127 | } else if (writing) { |
44c95fcf | 128 | ++stats.writeable; |
92e29797 | 129 | ++stats.writers; |
ce49546e | 130 | stats.appenders += appending; |
44c95fcf AR |
131 | } else { |
132 | ++stats.idle; | |
133 | } | |
134 | ++stats.count; | |
135 | } | |
136 | ||
44c95fcf AR |
137 | /* Ipc::ReadWriteLockStats */ |
138 | ||
139 | Ipc::ReadWriteLockStats::ReadWriteLockStats() | |
140 | { | |
141 | memset(this, 0, sizeof(*this)); | |
142 | } | |
9199139f | 143 | |
44c95fcf AR |
144 | void |
145 | Ipc::ReadWriteLockStats::dump(StoreEntry &e) const | |
146 | { | |
147 | storeAppendPrintf(&e, "Available locks: %9d\n", count); | |
148 | ||
149 | if (!count) | |
150 | return; | |
151 | ||
152 | storeAppendPrintf(&e, "Reading: %9d %6.2f%%\n", | |
9199139f | 153 | readable, (100.0 * readable / count)); |
44c95fcf | 154 | storeAppendPrintf(&e, "Writing: %9d %6.2f%%\n", |
9199139f | 155 | writeable, (100.0 * writeable / count)); |
44c95fcf | 156 | storeAppendPrintf(&e, "Idle: %9d %6.2f%%\n", |
9199139f | 157 | idle, (100.0 * idle / count)); |
44c95fcf AR |
158 | |
159 | if (readers || writers) { | |
160 | const int locked = readers + writers; | |
161 | storeAppendPrintf(&e, "Readers: %9d %6.2f%%\n", | |
9199139f | 162 | readers, (100.0 * readers / locked)); |
ce49546e AR |
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); | |
44c95fcf AR |
167 | } |
168 | } | |
f53969cc | 169 | |
b2aca62a EB |
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 |