1  /*
2   * Copyright (c) 2021 Huawei Device Co., Ltd.
3   * Licensed under the Apache License, Version 2.0 (the "License");
4   * you may not use this file except in compliance with the License.
5   * You may obtain a copy of the License at
6   *
7   *     http://www.apache.org/licenses/LICENSE-2.0
8   *
9   * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  #ifndef NOTIFICATION_CHAIN_H
17  #define NOTIFICATION_CHAIN_H
18  
19  #include <map>
20  #include <set>
21  #include <thread>
22  #include <condition_variable>
23  
24  #include "ref_object.h"
25  
26  namespace DistributedDB {
27  using EventType = unsigned int;
28  
29  class NotificationChain final : public RefObject {
30  private:
31      class ListenerChain;
32  
33  public:
34      class Listener final : public RefObject {
35      public:
36          using OnEvent = std::function<void(void *)>;
37          using OnFinalize = std::function<void(void)>;
38  
39          // Called by ListenerChain.callbackListeners, it will call the OnEvent
40          void NotifyListener(void *arg);
41  
42          // Drop this listener. after call this function, the listener will be destroy
43          int Drop(bool wait = false);
44  
45          // Enter kill-waiting state if 'onEvent()' is invoking when 'KillObj()'.
46          void KillWait();
47  
48          // Set the listener chain we belong to.
49          void SetOwner(ListenerChain *listenerChain);
50  
51          Listener(const OnEvent &onEvent, const OnFinalize &onFinalize);
52  
53          // Delete the copy and assign constructors
54          DISABLE_COPY_ASSIGN_MOVE(Listener);
55  
56      protected:
57          ~Listener() override;
58  
59      private:
60          // will be call when this listener destroy
61          void Finalize() const;
62          bool EnterEventAction();
63          void LeaveEventAction();
64  
65          DECLARE_OBJECT_TAG(Listener);
66  
67          constexpr static int KILL_WAIT_SECONDS = 5; // wait only 5 seconds when killing to avoid dead-lock.
68          OnEvent onEvent_;
69          OnFinalize onFinalize_;
70          ListenerChain *listenerChain_;
71          std::thread::id eventRunningThread_;
72          std::condition_variable safeKill_;
73      };
74  
75      // Add a listener from the NotificationChain. it will return a Listener handle
76      // The param type should match the RegisterEventsType
77      // The param onEvent will be call when events happened.
78      // The param onFinalize will be call when this listener destroy
79      Listener *RegisterListener(EventType type, const Listener::OnEvent &onEvent,
80          const Listener::OnFinalize &onFinalize, int &errCode);
81  
82      // User to register an events type to the NotificationChain, needs to call at init
83      int RegisterEventType(EventType type);
84  
85      // User to unregister an events type.
86      int UnRegisterEventType(EventType type);
87  
88      // Should be call when events happened.
89      void NotifyEvent(EventType type, void *arg);
90  
91      bool EmptyListener(EventType type) const;
92  
93      NotificationChain() = default;
94  
95      // Delete the copy and assign constructors
96      DISABLE_COPY_ASSIGN_MOVE(NotificationChain);
97  
98  protected:
99      ~NotificationChain() override;
100  
101  private:
102      class ListenerChain final : public RefObject {
103      public:
104          // Add a listener to the ListenerChain
105          int RegisterListener(Listener *listener);
106  
107          // Remove a listener to the ListenerChain
108          int UnRegisterListener(Listener *listener, bool wait = false);
109  
110          // Callback all the listeners
111          void NotifyListeners(void *arg);
112  
113          // Clear all listeners
114          void ClearListeners();
115  
116          bool Empty() const;
117  
118          ListenerChain();
119  
120          // Delete the copy and assign constructors
121          DISABLE_COPY_ASSIGN_MOVE(ListenerChain);
122      protected:
123          ~ListenerChain() override;
124  
125      private:
126          // Used to back up listenerSet_, need to lock
127          void BackupListenerSet(std::set<Listener *> &backupSet) const;
128  
129          DECLARE_OBJECT_TAG(ListenerChain);
130  
131          std::set<Listener *> listenerSet_;
132      };
133  
134      // Find a ListenerChain from  the eventChains_ with given type,
135      // this function needs to lock.
136      ListenerChain *FindAndGetListenerChainLocked(EventType type) const;
137  
138      // Find a ListenerChain from  the eventChains_ with given type,
139      ListenerChain *FindListenerChain(EventType type) const;
140  
141      DECLARE_OBJECT_TAG(NotificationChain);
142  
143      std::map<EventType, ListenerChain *> eventChains_;
144  };
145  } // namespace DistributedDB
146  
147  #endif // NOTIFICATION_CHAIN_H
148