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