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