All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
notice.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_NOTICE_H
8#define PXR_BASE_TF_NOTICE_H
9
12
13#include "pxr/pxr.h"
14#include "pxr/base/tf/api.h"
17#include "pxr/base/tf/type.h"
18#include "pxr/base/tf/weakPtr.h"
20#include "pxr/base/arch/hints.h"
21
22#include <atomic>
23#include <list>
24#include <typeinfo>
25
26PXR_NAMESPACE_OPEN_SCOPE
27
28class Tf_NoticeRegistry;
29
77class TfNotice {
78private:
79 class _DelivererBase;
81 typedef std::list<_DelivererBase*> _DelivererList;
82
84 // Per-sender delivery, listener gets sender.
85 template <class LPtr, class L,
86 class Notice, class SPtr, class DeliveredSPtr>
87 static _DelivererBase *
88 _MakeDeliverer(LPtr const &listener,
89 void (L::*method)
90 (const Notice &, DeliveredSPtr const &),
91 SPtr const &sender) {
92 DeliveredSPtr weakSender(sender);
93 return new _DelivererWithSender<
94 LPtr, DeliveredSPtr,
95 void (L::*)(const Notice &, DeliveredSPtr const &),
96 Notice
97 >(listener, method, weakSender);
98 }
99
100 template <class LPtr, class L,
101 class Notice, class SPtr, class DeliveredSPtr>
102 static _DelivererBase *
103 _MakeDeliverer(LPtr const &listener,
104 void (L::*method)
105 (const Notice &, DeliveredSPtr const &) const,
106 SPtr const &sender) {
107 DeliveredSPtr weakSender(sender);
108 return new _DelivererWithSender<
109 LPtr, DeliveredSPtr,
110 void (L::*)(const Notice &, DeliveredSPtr const &) const,
111 Notice
112 >(listener, method, weakSender);
113 }
114
116 // Per-sender delivery, listener does not get sender.
117 template <class LPtr, class L, class SPtr, class Notice>
118 static _DelivererBase *
119 _MakeDeliverer(LPtr const &listener,
120 void (L::*method)(const Notice &),
121 SPtr const &sender) {
122 return new _Deliverer<
123 LPtr, SPtr, void (L::*)(const Notice &), Notice
124 >(listener, method, sender);
125 }
126
127 template <class LPtr, class L, class SPtr, class Notice>
128 static _DelivererBase *
129 _MakeDeliverer(LPtr const &listener,
130 void (L::*method)(const Notice &) const,
131 SPtr const &sender) {
132 return new _Deliverer<
133 LPtr, SPtr, void (L::*)(const Notice &) const, Notice
134 >(listener, method, sender);
135 }
136
138 // Global delivery.
139 template <class LPtr, class L, class Notice>
140 static _DelivererBase *
141 _MakeDeliverer(LPtr const &listener,
142 void (L::*method)(const Notice &)) {
143 return new _Deliverer<
144 LPtr, TfAnyWeakPtr, void (L::*)(const Notice &), Notice
145 >(listener, method);
146 }
147
148 template <class LPtr, class L, class Notice>
149 static _DelivererBase *
150 _MakeDeliverer(LPtr const &listener,
151 void (L::*method)(const Notice &) const) {
152 return new _Deliverer<
153 LPtr, TfAnyWeakPtr, void (L::*)(const Notice &) const, Notice
154 >(listener, method);
155 }
156
158 // Generic (raw) delivery.
159 template <class LPtr, class L>
160 static _DelivererBase *
161 _MakeDeliverer(TfType const &noticeType,
162 LPtr const &listener,
163 void (L::*method)(const TfNotice &,
164 const TfType &,
165 TfWeakBase*, const void *,
166 const std::type_info&),
167 TfAnyWeakPtr const &sender) {
168 return new _RawDeliverer<LPtr,
169 void (L::*)(const TfNotice &, const TfType &,
170 TfWeakBase *, const void *,
171 const std::type_info &)>
172 (listener, method, sender, noticeType);
173 }
174
175 template <class LPtr, class L>
176 static _DelivererBase *
177 _MakeDeliverer(TfType const &noticeType,
178 LPtr const &listener,
179 void (L::*method)(const TfNotice &,
180 const TfType &,
181 TfWeakBase*, const void *,
182 const std::type_info&) const,
183 TfAnyWeakPtr const &sender)
184 {
185 return new _RawDeliverer<LPtr,
186 void (L::*)(const TfNotice &, const TfType &,
187 TfWeakBase *, const void *,
188 const std::type_info &) const>
189 (listener, method, sender, noticeType);
190 }
191
192
193
194public:
195
196 class Probe;
198
202 class Probe : public TfWeakBase {
203 public:
204 TF_API
205 virtual ~Probe() = 0;
206
210 virtual void BeginSend(const TfNotice &notice,
211 const TfWeakBase *sender,
212 const std::type_info &senderType) = 0;
213
216 virtual void EndSend() = 0;
217
222 virtual void BeginDelivery(const TfNotice &notice,
223 const TfWeakBase *sender,
224 const std::type_info &senderType,
225 const TfWeakBase *listener,
226 const std::type_info &listenerType) = 0;
227
231 virtual void EndDelivery() = 0;
232 };
233
240 class Key {
241 public:
242 Key() {}
243
248 bool IsValid() const {
249 return _deliverer && _deliverer->_IsActive();
250 }
251
255 operator bool() const {
256 return IsValid();
257 }
258
259 private:
260 Key(const _DelivererWeakPtr & d) : _deliverer(d) {}
261
262 _DelivererWeakPtr _deliverer;
263
264 friend class Tf_NoticeRegistry;
265 friend class TfNotice;
266 };
267
273 typedef std::vector<Key> Keys;
274
278 TF_API
279 static void InsertProbe(const WeakProbePtr &probe);
280
283 TF_API
284 static void RemoveProbe(const WeakProbePtr &probe);
285
343 template <class LPtr, class MethodPtr>
344 static TfNotice::Key
345 Register(LPtr const &listener, MethodPtr method) {
346 return _Register(_MakeDeliverer(listener, method));
347 }
348
349 template <class LPtr, class MethodPtr, class SenderPtr>
350 static TfNotice::Key
351 Register(LPtr const &listener, MethodPtr method, SenderPtr const &sender) {
352 return _Register(_MakeDeliverer(listener, method, sender));
353 }
354
355 template <class LPtr, class MethodPtr>
356 static TfNotice::Key
357 Register(LPtr const &listener, MethodPtr method,
358 const TfType &noticeType, const TfAnyWeakPtr &sender) {
359 return _Register(_MakeDeliverer(noticeType, listener, method, sender));
360 }
361
370 TF_API
371 static bool Revoke(TfNotice::Key& key);
372
378 TF_API
379 static void Revoke(TfNotice::Keys* keys);
380
390 TF_API
391 static bool RevokeAndWait(TfNotice::Key& key);
392
399 TF_API
400 static void RevokeAndWait(TfNotice::Keys* keys);
401
416 TF_API
417 size_t Send() const;
418
433 template <typename SenderPtr>
434 size_t Send(SenderPtr const &s) const;
435
442 TF_API
443 size_t SendWithWeakBase(const TfWeakBase *senderWeakBase,
444 const void *senderUniqueId,
445 const std::type_info &type) const;
446
447 TF_API
448 virtual ~TfNotice();
449
458 class Block {
459 public:
460 TF_API Block();
461 TF_API ~Block();
462 };
463
464private:
465 // Abstract base class for calling listeners.
466 // A typed-version derives (via templating) off this class.
467 class _DelivererBase : public TfWeakBase {
468 public:
469 _DelivererBase()
470 : _list(0), _active(true), _markedForRemoval(false)
471 {
472 }
473
474 TF_API
475 virtual ~_DelivererBase();
476
477 TF_API
478 void _BeginDelivery(const TfNotice &notice,
479 const TfWeakBase *sender,
480 const std::type_info &senderType,
481 const TfWeakBase *listener,
482 const std::type_info &listenerType,
483 const std::vector<TfNotice::WeakProbePtr> &probes);
484
485 TF_API
486 void _EndDelivery(const std::vector<TfNotice::WeakProbePtr> &probes);
487
488 // The derived class converts n to the proper type and delivers it by
489 // calling the listener's method. The function returns \c true,
490 // unless the listener has expired or been marked in active (i.e. by
491 // TfNotice::Revoke()), in which case the method call is skipped and
492 // \c false is returned.
493 virtual bool
494 _SendToListenerImpl(const TfNotice &n,
495 const TfType &type,
496 const TfWeakBase *s,
497 const void *senderUniqueId,
498 const std::type_info &senderType,
499 const std::vector<TfNotice::WeakProbePtr> &) = 0;
500
501 void _Deactivate() {
502 _active = false;
503 }
504
505 bool _IsActive() const {
506 return _active;
507 }
508
509 void _MarkForRemoval() {
510 _markedForRemoval = true;
511 }
512
513 // True if the entry has been added to the _deadEntries list for
514 // removal. Used to avoid adding it more than once to the list.
515 bool _IsMarkedForRemoval() const {
516 return _markedForRemoval;
517 }
518
519 virtual TfType GetNoticeType() const = 0;
520
521 virtual bool Delivers(TfType const &noticeType,
522 const TfWeakBase *sender) const = 0;
523
524 virtual TfWeakBase const *GetSenderWeakBase() const = 0;
525
526 virtual _DelivererBase *Clone() const = 0;
527
528 // Increment the busy count around the actual delivery.
529 bool _SendToListener(const TfNotice &n,
530 const TfType &type,
531 const TfWeakBase *s,
532 const void *senderUniqueId,
533 const std::type_info &senderType,
534 const std::vector<TfNotice::WeakProbePtr> &probes)
535 {
536 // Increment the number of sends in progress.
537 if (_busy.fetch_add(1, std::memory_order_release) & _waitBit) {
538 // We're waiting to revoke this listener and we haven't
539 // started the real send yet so act like we already revoked.
540 // If we didn't check if we were waiting then it's possible
541 // to enter this function but not yet increment, have wait
542 // see the count is zero and return, then have this function
543 // increment and do the real send after having supposedly
544 // waited for all sends to complete.
545 _busy.fetch_add(-1, std::memory_order_release);
546 return false;
547 }
548 const auto result =
549 _SendToListenerImpl(n, type,
550 s, senderUniqueId, senderType, probes);
551 _busy.fetch_add(-1, std::memory_order_release);
552 return result;
553 }
554
555 // Spin wait until no deliveries are in progress. This is used when
556 // revoking a listener so we set the _waitBit in _busy permanently.
557 void _WaitForSendsToFinish()
558 {
559 // Mark this listener as waiting for sends to finish and check if
560 // any send is in progress.
561 if (_busy.fetch_or(_waitBit, std::memory_order_release)) {
562 // At least one send was in progress.
563 _WaitUntilNotSending();
564 }
565 }
566
567 protected:
568
569 template <class ToNoticeType, class FromNoticeType>
570 static inline ToNoticeType const *
571 _CastNotice(FromNoticeType const *from) {
572 // Dynamic casting in deliverers is significant overhead, so only
573 // do error checking in debug builds.
574 if (TF_DEV_BUILD) {
575 if (!dynamic_cast<ToNoticeType const *>(from)) {
576 ToNoticeType const *castNotice =
577 TfSafeDynamic_cast<ToNoticeType const *>(from);
578 // this will abort with a clear error message if
579 // castNotice is NULL
580 TfNotice::_VerifyFailedCast(typeid(ToNoticeType),
581 *from, castNotice);
582 }
583 }
584 return static_cast<ToNoticeType const *>(from);
585 }
586
587 private:
588 // Wait until there are no sends in progress.
589 void _WaitUntilNotSending();
590
591 private:
592 // Linkage to the containing _DelivererList in the Tf_NoticeRegistry
593 _DelivererList *_list;
594 _DelivererList::iterator _listIter;
595
596 bool _active;
597 bool _markedForRemoval;
598 std::atomic<int> _busy{0};
599
600 static constexpr int _waitBit = 0x80000000;
601
602 friend class Tf_NoticeRegistry;
603 };
604
605 template <class Derived>
606 class _StandardDeliverer : public _DelivererBase {
607 public:
608 virtual ~_StandardDeliverer() {}
609
610 virtual TfType GetNoticeType() const {
611 typedef typename Derived::NoticeType NoticeType;
612 TfType ret = TfType::Find<NoticeType>();
613 if (ret.IsUnknown())
614 TF_FATAL_ERROR("notice type " + ArchGetDemangled<NoticeType>() +
615 " undefined in the TfType system");
616 return ret;
617 }
618
619 virtual bool Delivers(TfType const &noticeType,
620 TfWeakBase const *sender) const {
621 Derived const *derived = this->AsDerived();
622 return noticeType.IsA(GetNoticeType()) &&
623 !derived->_sender.IsInvalid() &&
624 sender && derived->_sender.GetWeakBase() == sender;
625 }
626
627 virtual TfWeakBase const *GetSenderWeakBase() const {
628 Derived const *derived = this->AsDerived();
629 return derived->_sender ? derived->_sender.GetWeakBase() : 0;
630 }
631
632 virtual _DelivererBase *Clone() const {
633 Derived const *derived = this->AsDerived();
634 return new Derived(derived->_listener,
635 derived->_method,
636 derived->_sender,
637 GetNoticeType());
638 }
639
640 virtual bool
641 _SendToListenerImpl(const TfNotice &notice,
642 const TfType &noticeType,
643 const TfWeakBase *sender,
644 const void *senderUniqueId,
645 const std::type_info &senderType,
646 const std::vector<TfNotice::WeakProbePtr> &probes)
647 {
648 Derived *derived = this->AsDerived();
649 typedef typename Derived::ListenerType ListenerType;
650 typedef typename Derived::NoticeType NoticeType;
651 ListenerType *listener = get_pointer(derived->_listener);
652
653 if (listener && !derived->_sender.IsInvalid()) {
654 if (ARCH_UNLIKELY(!probes.empty())) {
655 TfWeakBase const *senderWeakBase = GetSenderWeakBase(),
656 *listenerWeakBase = derived->_listener.GetWeakBase();
657 _BeginDelivery(notice, senderWeakBase,
658 senderWeakBase ?
659 senderType : typeid(void),
660 listenerWeakBase,
661 typeid(ListenerType), probes);
662 }
663
664 derived->
665 _InvokeListenerMethod(listener,
666 *_CastNotice<NoticeType>(&notice),
667 noticeType, sender,
668 senderUniqueId, senderType);
669
670 if (ARCH_UNLIKELY(!probes.empty()))
671 _EndDelivery(probes);
672
673 return true;
674 }
675 return false;
676 }
677
678 private:
679 Derived *AsDerived() {
680 return static_cast<Derived *>(this);
681 }
682
683 Derived const *AsDerived() const {
684 return static_cast<Derived const *>(this);
685 }
686 };
687
688
689 template <typename LPtr, typename SPtr, typename Method, typename Notice>
690 class _Deliverer :
691 public _StandardDeliverer<_Deliverer<LPtr, SPtr, Method, Notice> >
692 {
693 public:
694 typedef Notice NoticeType;
695 typedef typename LPtr::DataType ListenerType;
696 typedef Method MethodPtr;
697
698 _Deliverer(LPtr const &listener,
699 MethodPtr const &methodPtr,
700 SPtr const &sender = SPtr(),
701 TfType const &noticeType = TfType())
702 : _listener(listener)
703 , _sender(sender)
704 , _method(methodPtr)
705 {
706 }
707
708 void _InvokeListenerMethod(ListenerType *listener,
709 const NoticeType &notice,
710 const TfType &noticeType,
711 const TfWeakBase *,
712 const void *,
713 const std::type_info &)
714 {
715 (listener->*_method)(notice);
716 }
717
718 LPtr _listener;
719 SPtr _sender;
720 MethodPtr _method;
721 };
722
723 template <class LPtr, class Method>
724 class _RawDeliverer :
725 public _StandardDeliverer<_RawDeliverer<LPtr, Method> >
726 {
727 public:
728 typedef TfNotice NoticeType;
729 typedef typename LPtr::DataType ListenerType;
730 typedef Method MethodPtr;
731
732 _RawDeliverer(LPtr const &listener,
733 MethodPtr const &methodPtr,
734 TfAnyWeakPtr const &sender,
735 TfType const &noticeType)
736 : _noticeType(noticeType),
737 _listener(listener),
738 _method(methodPtr),
739 _sender(sender)
740 {
741 }
742
743 virtual TfType GetNoticeType() const {
744 return _noticeType;
745 }
746
747 void _InvokeListenerMethod(ListenerType *listener,
748 const NoticeType &notice,
749 const TfType &noticeType,
750 const TfWeakBase *sender,
751 const void *senderUniqueId,
752 const std::type_info &senderType)
753 {
754 (listener->*_method)(notice, noticeType,
755 const_cast<TfWeakBase *>(sender),
756 senderUniqueId, senderType);
757 }
758
759 TfType _noticeType;
760 LPtr _listener;
761 MethodPtr _method;
762 TfAnyWeakPtr _sender;
763 };
764
765 template <class LPtr, class SPtr, class Method, class Notice>
766 class _DelivererWithSender :
767 public _StandardDeliverer<
768 _DelivererWithSender<LPtr, SPtr, Method, Notice>
769 >
770 {
771 public:
772 typedef Notice NoticeType;
773 typedef Method MethodPtr;
774 typedef typename LPtr::DataType ListenerType;
775
776 typedef typename SPtr::DataType SenderType;
777
778 _DelivererWithSender(LPtr const &listener,
779 MethodPtr const &methodPtr,
780 SPtr const &sender,
781 TfType const &noticeType = TfType())
782 : _listener(listener),
783 _sender(sender),
784 _method(methodPtr)
785 {
786 }
787
788 void _InvokeListenerMethod(ListenerType *listener,
789 const NoticeType &notice,
790 const TfType &noticeType,
791 const TfWeakBase *sender,
792 const void *,
793 const std::type_info &)
794 {
795 SenderType *deliveredSender =
796 static_cast<SenderType *>(const_cast<TfWeakBase *>(sender));
797 SPtr deliveredSPtr(deliveredSender);
798 (listener->*_method)(notice, deliveredSPtr);
799 }
800
801 LPtr _listener;
802 SPtr _sender;
803 MethodPtr _method;
804 };
805
806private:
807 // Internal non-templated function to install listeners.
808 TF_API
809 static Key _Register(_DelivererBase*);
810
811 TF_API
812 static void _VerifyFailedCast(const std::type_info& toType,
813 const TfNotice& notice,
814 const TfNotice* castNotice);
815
816 TF_API
817 size_t _Send(const TfWeakBase* sender,
818 const void *senderUniqueId,
819 const std::type_info & senderType) const;
820 TF_API
821 size_t _SendWithType(const TfType & noticeType,
822 const TfWeakBase* sender,
823 const void *senderUniqueId,
824 const std::type_info & senderType) const;
825
826 friend class Tf_NoticeRegistry;
827
828 // Befriend the wrapping so it can access _SendWithType() directly
829 // in order to provide dynamic downcasting of Python notice types.
830 friend class Tf_PyNotice;
831};
832
833template <typename SenderPtr>
834size_t
835TfNotice::Send(SenderPtr const &s) const
836{
837 const TfWeakBase *senderWeakBase = s ? s.GetWeakBase() : NULL;
838 return _Send(senderWeakBase, senderWeakBase ? s.GetUniqueIdentifier() : 0,
839 senderWeakBase ?
840 typeid(typename SenderPtr::DataType) : typeid(void));
841}
842
843PXR_NAMESPACE_CLOSE_SCOPE
844
845#endif // PXR_BASE_TF_NOTICE_H
Type independent WeakPtr holder class.
Low-level utilities for informing users of various internal and external diagnostic conditions.
Provides the ability to hold an arbitrary TfWeakPtr in a non-type-specific manner in order to observe...
Definition: anyWeakPtr.h:37
Blocks sending of all notices in current thread.
Definition: notice.h:458
Handle-object returned by TfNotice::Register().
Definition: notice.h:240
bool IsValid() const
Does this key refer to a valid notification?
Definition: notice.h:248
Probe interface class which may be implemented and then registered via InsertProbe to introspect abou...
Definition: notice.h:202
virtual void EndDelivery()=0
This method is called after the notice in the corresponding BeginDelivery call has finished being pro...
virtual void EndSend()=0
This method is called after the notice in the corresponding BeginSend call has been delivered to all ...
virtual void BeginDelivery(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType, const TfWeakBase *listener, const std::type_info &listenerType)=0
This method is called just before notice is delivered to a listener.
virtual void BeginSend(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType)=0
This method is called just before notice is sent to any listeners.
The base class for objects used to notify interested parties (listeners) when events have occurred.
Definition: notice.h:77
TF_API size_t Send() const
Deliver the notice to interested listeners, returning the number of interested listeners.
static TF_API void RevokeAndWait(TfNotice::Keys *keys)
Revoke interest by listeners.
static TF_API void InsertProbe(const WeakProbePtr &probe)
Register a probe that will be invoked when notices are sent and delivered.
static TF_API void Revoke(TfNotice::Keys *keys)
Revoke interest by listeners.
static TfNotice::Key Register(LPtr const &listener, MethodPtr method)
Register a listener as being interested in a TfNotice.
Definition: notice.h:345
static TF_API void RemoveProbe(const WeakProbePtr &probe)
Remove a probe that was previously registered with InsertProbe.
TF_API size_t SendWithWeakBase(const TfWeakBase *senderWeakBase, const void *senderUniqueId, const std::type_info &type) const
Variant of Send() that takes a specific sender in the form of a TfWeakBase pointer and a typeid.
static TF_API bool Revoke(TfNotice::Key &key)
Revoke interest by a listener.
static TF_API bool RevokeAndWait(TfNotice::Key &key)
Revoke interest by a listener.
std::vector< Key > Keys
A TfNotice::Key container.
Definition: notice.h:273
TfType represents a dynamic runtime type.
Definition: type.h:48
TF_API bool IsA(TfType queryType) const
Return true if this type is the same as or derived from queryType.
bool IsUnknown() const
Return true if this is the unknown type, representing a type unknown to the TfType system.
Definition: type.h:374
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:124
Pointer storage with deletion detection.
Definition: weakPtr.h:128
Demangle C++ typenames generated by the typeid() facility.
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:91
Compiler hints.
Pointer storage with deletion detection.