Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TReentrantRWLock.hxx
Go to the documentation of this file.
1 // @(#)root/thread:$Id$
2 // Authors: Enric Tejedor CERN 12/09/2016
3 // Philippe Canal FNAL 12/09/2016
4 
5 /*************************************************************************
6  * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. *
7  * All rights reserved. *
8  * *
9  * For the licensing terms see $ROOTSYS/LICENSE. *
10  * For the list of contributors see $ROOTSYS/README/CREDITS. *
11  *************************************************************************/
12 
13 #ifndef ROOT_TReentrantRWLock
14 #define ROOT_TReentrantRWLock
15 
16 #include "ThreadLocalStorage.h"
17 #include "ROOT/TSpinMutex.hxx"
18 #include "TVirtualRWMutex.h"
19 
20 #include <atomic>
21 #include <condition_variable>
22 #include <thread>
23 #include <unordered_map>
24 
25 namespace ROOT {
26 namespace Internal {
27 struct UniqueLockRecurseCount {
28  using Hint_t = TVirtualRWMutex::Hint_t;
29 
30  struct LocalCounts {
31  size_t fReadersCount = 0;
32  bool fIsWriter = false;
33  };
34  size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
35 
36  UniqueLockRecurseCount();
37 
38  using local_t = LocalCounts*;
39 
40  local_t GetLocal(){
41  TTHREAD_TLS_DECL(LocalCounts, gLocal);
42  return &gLocal;
43  }
44 
45  Hint_t *IncrementReadCount(local_t &local) {
46  ++(local->fReadersCount);
47  return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
48  }
49 
50  template <typename MutexT>
51  Hint_t *IncrementReadCount(local_t &local, MutexT &) {
52  return IncrementReadCount(local);
53  }
54 
55  Hint_t *DecrementReadCount(local_t &local) {
56  --(local->fReadersCount);
57  return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
58  }
59 
60  template <typename MutexT>
61  Hint_t *DecrementReadCount(local_t &local, MutexT &) {
62  return DecrementReadCount(local);
63  }
64 
65  void ResetReadCount(local_t &local, int newvalue) {
66  local->fReadersCount = newvalue;
67  }
68 
69  bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
70  bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
71 
72  void SetIsWriter(local_t &local)
73  {
74  // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
75  // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
76  // }
77  ++fWriteRecurse;
78  local->fIsWriter = true;
79  }
80 
81  void DecrementWriteCount() { --fWriteRecurse; }
82 
83  void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
84 
85  size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
86 };
87 
88 struct RecurseCounts {
89  using Hint_t = TVirtualRWMutex::Hint_t;
90  using ReaderColl_t = std::unordered_map<std::thread::id, size_t>;
91  size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
92 
93  std::thread::id fWriterThread; ///<! Holder of the write lock
94  ReaderColl_t fReadersCount; ///<! Set of reader thread ids
95 
96  using local_t = std::thread::id;
97 
98  local_t GetLocal() const { return std::this_thread::get_id(); }
99 
100  Hint_t *IncrementReadCount(local_t &local) {
101  auto &count = fReadersCount[local];
102  ++(count);
103  return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
104  }
105 
106  template <typename MutexT>
107  Hint_t *IncrementReadCount(local_t &local, MutexT &mutex)
108  {
109  std::unique_lock<MutexT> lock(mutex);
110  return IncrementReadCount(local);
111  }
112 
113  Hint_t *DecrementReadCount(local_t &local) {
114  auto &count = fReadersCount[local];
115  --count;
116  return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
117  }
118 
119  template <typename MutexT>
120  Hint_t *DecrementReadCount(local_t &local, MutexT &mutex)
121  {
122  std::unique_lock<MutexT> lock(mutex);
123  return DecrementReadCount(local);
124  }
125 
126  void ResetReadCount(local_t &local, int newvalue) {
127  fReadersCount[local] = newvalue;
128  }
129 
130  bool IsCurrentWriter(local_t &local) const { return fWriterThread == local; }
131  bool IsNotCurrentWriter(local_t &local) const { return fWriterThread != local; }
132 
133  void SetIsWriter(local_t &local)
134  {
135  // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
136  // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
137  // }
138  ++fWriteRecurse;
139  fWriterThread = local;
140  }
141 
142  void DecrementWriteCount() { --fWriteRecurse; }
143 
144  void ResetIsWriter(local_t & /* local */) { fWriterThread = std::thread::id(); }
145 
146  size_t &GetLocalReadersCount(local_t &local) { return fReadersCount[local]; }
147 
148 
149 };
150 } // Internal
151 
152 template <typename MutexT = ROOT::TSpinMutex, typename RecurseCountsT = Internal::RecurseCounts>
153 class TReentrantRWLock {
154 private:
155 
156  std::atomic<int> fReaders; ///<! Number of readers
157  std::atomic<int> fReaderReservation; ///<! A reader wants access
158  std::atomic<int> fWriterReservation; ///<! A writer wants access
159  std::atomic<bool> fWriter; ///<! Is there a writer?
160  MutexT fMutex; ///<! RWlock internal mutex
161  std::condition_variable_any fCond; ///<! RWlock internal condition variable
162 
163  RecurseCountsT fRecurseCounts; ///<! Trackers for re-entry in the lock by the same thread.
164 
165  // size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
166 
167  // std::thread::id fWriterThread; ///<! Holder of the write lock
168  // ReaderColl_t fReadersCount; ///<! Set of reader thread ids
169 
170  void AssertReadCountLocIsFromCurrentThread(const size_t* presumedLocalReadersCount);
171 
172 public:
173  using State = TVirtualRWMutex::State;
174  using StateDelta = TVirtualRWMutex::StateDelta;
175 
176  ////////////////////////////////////////////////////////////////////////
177  /// Regular constructor.
178  TReentrantRWLock() : fReaders(0), fReaderReservation(0), fWriterReservation(0), fWriter(false) {}
179 
180  TVirtualRWMutex::Hint_t *ReadLock();
181  void ReadUnLock(TVirtualRWMutex::Hint_t *);
182  TVirtualRWMutex::Hint_t *WriteLock();
183  void WriteUnLock(TVirtualRWMutex::Hint_t *);
184 
185  std::unique_ptr<State> GetStateBefore();
186  std::unique_ptr<StateDelta> Rewind(const State &earlierState);
187  void Apply(std::unique_ptr<StateDelta> &&delta);
188  };
189 } // end of namespace ROOT
190 
191 #endif