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