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