All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
noticeRegistry.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef TF_NOTICE_REGISTRY_H
25 #define TF_NOTICE_REGISTRY_H
26 
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/tf/api.h"
32 #include "pxr/base/tf/hash.h"
33 #include "pxr/base/tf/hashmap.h"
34 #include "pxr/base/tf/hashset.h"
35 #include "pxr/base/tf/notice.h"
36 #include "pxr/base/tf/singleton.h"
37 #include "pxr/base/tf/type.h"
38 
39 #include <boost/noncopyable.hpp>
40 
41 #include <tbb/enumerable_thread_specific.h>
42 #include <tbb/spin_mutex.h>
43 #include <atomic>
44 
45 PXR_NAMESPACE_OPEN_SCOPE
46 
71 class Tf_NoticeRegistry : boost::noncopyable {
72 public:
73  TF_API
74  void _BeginDelivery(const TfNotice &notice,
75  const TfWeakBase *sender,
76  const std::type_info &senderType,
77  const TfWeakBase *listener,
78  const std::type_info &listenerType,
79  const std::vector<TfNotice::WeakProbePtr> &probes);
80 
81  TF_API
82  void _EndDelivery(const std::vector<TfNotice::WeakProbePtr> &probes);
83 
84  // Register a particular deliverer, return the key created for the
85  // registration.
86  TF_API
87  TfNotice::Key _Register(TfNotice::_DelivererBase* deliverer);
88 
89  // Send notice n to all interested listeners.
90  TF_API
91  size_t _Send(const TfNotice &n, const TfType &noticeType,
92  const TfWeakBase *s, const void *senderUniqueId,
93  const std::type_info &senderType);
94 
95  // Remove listener instance indicated by \p key. This is pass by
96  // reference so we can mark the key as having been revoked.
97  TF_API
98  void _Revoke(TfNotice::Key& key);
99 
100  // Abort if casting of a notice failed; warn if it succeeded but
101  // TfSafeDynamic_cast was required.
102  TF_API
103  void _VerifyFailedCast(const std::type_info& toType,
104  const TfNotice& notice, const TfNotice* castNotice);
105 
106  // Return reference to singleton object.
107  TF_API
108  static Tf_NoticeRegistry& _GetInstance() {
110  }
111 
112  TF_API
113  void _InsertProbe(const TfNotice::WeakProbePtr &probe);
114  TF_API
115  void _RemoveProbe(const TfNotice::WeakProbePtr &probe);
116 
117  TF_API
118  void _IncrementBlockCount();
119  TF_API
120  void _DecrementBlockCount();
121 
122 private:
123  Tf_NoticeRegistry();
124  friend class TfSingleton<Tf_NoticeRegistry>;
125 
126  void _BadTypeFatalMsg(const TfType& t, const std::type_info&);
127 
128  typedef TfNotice::_DelivererList _DelivererList;
129 
130  typedef std::pair<_DelivererList*, _DelivererList::iterator>
131  _DelivererListEntry;
132 
133  typedef tbb::spin_mutex _Mutex;
134  typedef tbb::spin_mutex::scoped_lock _Lock;
135 
136  void _BeginSend(const TfNotice &notice,
137  const TfWeakBase *sender,
138  const std::type_info &senderType,
139  const std::vector<TfNotice::WeakProbePtr> &probes);
140  void _EndSend(const std::vector<TfNotice::WeakProbePtr> &probes);
141 
142  // It is safe to add a new item onto an STL list during traversal by
143  // multiple threads; the only thing to guard against is a race when
144  // setting/getting the head of the list.
145  //
146  // Removal is trickier: if we can remove something right away, we do (i.e.
147  // if nobody but us is traversing the registry). Otherwise, we just mark
148  // the item on the list as inactive.
149 
150  class _DelivererContainer {
151  public:
152  typedef TfHashMap<const TfWeakBase*, _DelivererList, TfHash>
153  _PerSenderTable;
154 
155  _Mutex _mutex;
156  _DelivererList _delivererList;
157  _PerSenderTable _perSenderTable;
158 
159  // Initialize _perSenderTable with zero buckets
160  _DelivererContainer() : _perSenderTable(0) {}
161  };
162 
163  typedef TfHashMap<TfType, _DelivererContainer*, TfHash> _DelivererTable;
164 
165  typedef TfHashSet<TfNotice::WeakProbePtr, TfHash> _ProbeTable;
166 
167  void
168  _Prepend(_DelivererContainer*c, const TfWeakBase* sender,
169  TfNotice::_DelivererBase* item) {
170  _Lock lock(c->_mutex);
171 
172  TF_DEV_AXIOM(!item->_list);
173 
174  _DelivererList *dlist;
175  if (sender)
176  dlist = &c->_perSenderTable[sender];
177  else
178  dlist = &c->_delivererList;
179 
180  item->_list = dlist;
181  item->_list->push_front(item);
182  item->_listIter = dlist->begin();
183  }
184 
185  _DelivererListEntry
186  _GetHead(_DelivererContainer* c) {
187  _Lock lock(c->_mutex);
188  return _DelivererListEntry(&c->_delivererList,
189  c->_delivererList.begin());
190  }
191 
192  _DelivererListEntry
193  _GetHeadForSender(_DelivererContainer* c, const TfWeakBase* s) {
194  _Lock lock(c->_mutex);
195  _DelivererContainer::_PerSenderTable::iterator i =
196  c->_perSenderTable.find(s);
197  if (i != c->_perSenderTable.end()) {
198  return _DelivererListEntry(&(i->second), i->second.begin());
199  } else {
200  return _DelivererListEntry((_DelivererList*) 0,
201  _DelivererList::iterator());
202  }
203  }
204 
205  _DelivererContainer* _GetDelivererContainer(const TfType& t) {
206  _Lock lock(_tableMutex);
207  _DelivererTable::iterator i = _delivererTable.find(t);
208  return (i == _delivererTable.end()) ? NULL : i->second;
209  }
210 
211  _DelivererContainer* _GetOrCreateDelivererContainer(const TfType& t) {
212  _Lock lock(_tableMutex);
213  _DelivererTable::iterator i = _delivererTable.find(t);
214 
215  if (i == _delivererTable.end())
216  return (_delivererTable[t] = new _DelivererContainer);
217  else
218  return i->second;
219  }
220 
221  int _Deliver(const TfNotice &n, const TfType &type,
222  const TfWeakBase *s,
223  const void *senderUniqueId,
224  const std::type_info &senderType,
225  const std::vector<TfNotice::WeakProbePtr> &probes,
226  const _DelivererListEntry & entry);
227  void _FreeDeliverer(const TfNotice::_DelivererWeakPtr & d);
228 
229  void _IncrementUserCount(int amount) {
230  _Lock lock(_userCountMutex);
231  _userCount += amount;
232  }
233 
234  _DelivererTable _delivererTable;
235  _Mutex _tableMutex;
236 
237  // The user count and mutex track the number of callers into the registry
238  // to determine when it is safe to remove entries from deliverer lists;
239  // entries cannot be removed if another thread is inserting or iterating
240  // over the list at the same time. The mutex is also used to protect
241  // access to _deadEntries; these entries will be discarded later, but
242  // only when the user count is 1.
243  _Mutex _userCountMutex;
244  int _userCount;
245  std::vector< TfNotice::_DelivererWeakPtr > _deadEntries;
246 
247  _Mutex _warnMutex;
248  TfHashSet<std::string, TfHash> _warnedBadCastTypes;
249 
250  _Mutex _probeMutex;
251  _ProbeTable _probes;
252  bool _doProbing;
253 
254  std::atomic<size_t> _globalBlockCount;
255  tbb::enumerable_thread_specific<size_t> _perThreadBlockCount;
256 };
257 
258 TF_API_TEMPLATE_CLASS(TfSingleton<Tf_NoticeRegistry>);
259 
260 PXR_NAMESPACE_CLOSE_SCOPE
261 
262 #endif // TF_NOTICE_REGISTRY_H
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:227
Handle-object returned by TfNotice::Register().
Definition: notice.h:256
Manage a single instance of an object (see.
Definition: singleton.h:122
The base class for objects used to notify interested parties (listeners) when events have occurred...
Definition: notice.h:93
Pointer storage with deletion detection.
Definition: hash.h:44
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
Definition: singleton.h:137
TfType represents a dynamic runtime type.
Definition: type.h:70
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:142