1 /*
2  * Copyright (C) 1996-2021 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 #ifndef SQUID_IPC_READ_WRITE_LOCK_H
10 #define SQUID_IPC_READ_WRITE_LOCK_H
11 
12 #include <atomic>
13 
14 class StoreEntry;
15 
16 namespace Ipc
17 {
18 
19 class ReadWriteLockStats;
20 
21 /// an atomic readers-writer or shared-exclusive lock suitable for maps/tables
22 /// Also supports reading-while-appending mode when readers and writer are
23 /// allowed to access the same locked object because the writer promisses
24 /// to only append new data and all size-related object properties are atomic.
25 class ReadWriteLock
26 {
27 public:
ReadWriteLock()28     ReadWriteLock() : readers(0), writing(false), appending(false), readLevel(0), writeLevel(0)
29     {}
30 
31     bool lockShared(); ///< lock for reading or return false
32     bool lockExclusive(); ///< lock for modification or return false
33     bool lockHeaders(); ///< lock for [readable] metadata update or return false
34     void unlockShared(); ///< undo successful sharedLock()
35     void unlockExclusive(); ///< undo successful exclusiveLock()
36     void unlockHeaders(); ///< undo successful lockHeaders()
37     void switchExclusiveToShared(); ///< stop writing, start reading
38 
39     void startAppending(); ///< writer keeps its lock but also allows reading
40 
41     /// adds approximate current stats to the supplied ones
42     void updateStats(ReadWriteLockStats &stats) const;
43 
44 public:
45     mutable std::atomic<uint32_t> readers; ///< number of reading users
46     std::atomic<bool> writing; ///< there is a writing user (there can be at most 1)
47     std::atomic<bool> appending; ///< the writer has promised to only append
48     std::atomic_flag updating; ///< a reader is updating metadata/headers
49 
50 private:
51     mutable std::atomic<uint32_t> readLevel; ///< number of users reading (or trying to)
52     std::atomic<uint32_t> writeLevel; ///< number of users writing (or trying to write)
53 };
54 
55 /// approximate stats of a set of ReadWriteLocks
56 class ReadWriteLockStats
57 {
58 public:
59     ReadWriteLockStats();
60 
61     void dump(StoreEntry &e) const;
62 
63     int count; ///< the total number of locks
64     int readable; ///< number of locks locked for reading
65     int writeable; ///< number of locks locked for writing
66     int idle; ///< number of unlocked locks
67     int readers; ///< sum of lock.readers
68     int writers; ///< sum of lock.writers
69     int appenders; ///< number of appending writers
70 };
71 
72 /// Same as assert(flag is set): The process assert()s if flag is not set.
73 /// Side effect: The unset flag becomes set just before we assert().
74 /// Needed because atomic_flag cannot be compared with a boolean.
75 void AssertFlagIsSet(std::atomic_flag &flag);
76 
77 } // namespace Ipc
78 
79 #endif /* SQUID_IPC_READ_WRITE_LOCK_H */
80 
81