xref: /haiku/headers/private/kernel/Notifications.h (revision 4a850ca730d8282b5b924e49e09b4ba4d6db7f54)
1 /*
2  * Copyright 2007-2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Ingo Weinhold, bonefish@cs.tu-berlin.de
8  */
9 #ifndef _KERNEL_NOTIFICATIONS_H
10 #define _KERNEL_NOTIFICATIONS_H
11 
12 
13 #include <SupportDefs.h>
14 
15 #include <lock.h>
16 #include <messaging.h>
17 #include <util/StringHash.h>
18 
19 
20 #ifdef __cplusplus
21 
22 #include <Referenceable.h>
23 
24 #include <util/AutoLock.h>
25 #include <util/DoublyLinkedList.h>
26 #include <util/KMessage.h>
27 #include <util/OpenHashTable.h>
28 
29 
30 class NotificationService;
31 
32 class NotificationListener {
33 public:
34 	virtual						~NotificationListener();
35 
36 	virtual void				EventOccurred(NotificationService& service,
37 									const KMessage* event);
38 	virtual void				AllListenersNotified(
39 									NotificationService& service);
40 
41 	virtual bool				operator==(
42 									const NotificationListener& other) const;
43 
44 			bool				operator!=(
45 									const NotificationListener& other) const
46 									{ return !(*this == other); }
47 };
48 
49 class UserMessagingMessageSender {
50 public:
51 								UserMessagingMessageSender();
52 
53 			void				SendMessage(const KMessage* message,
54 									port_id port, int32 token);
55 			void				FlushMessage();
56 
57 private:
58 	enum {
59 		MAX_MESSAGING_TARGET_COUNT	= 16,
60 	};
61 
62 			const KMessage*		fMessage;
63 			messaging_target	fTargets[MAX_MESSAGING_TARGET_COUNT];
64 			int32				fTargetCount;
65 };
66 
67 class UserMessagingListener : public NotificationListener {
68 public:
69 								UserMessagingListener(
70 									UserMessagingMessageSender& sender,
71 									port_id port, int32 token);
72 	virtual						~UserMessagingListener();
73 
74 	virtual void				EventOccurred(NotificationService& service,
75 									const KMessage* event);
76 	virtual void				AllListenersNotified(
77 									NotificationService& service);
78 
79 			port_id				Port() const	{ return fPort; }
80 			int32				Token() const	{ return fToken; }
81 
82 			bool				operator==(
83 									const NotificationListener& _other) const;
84 
85 private:
86 	UserMessagingMessageSender&	fSender;
87 	port_id						fPort;
88 	int32						fToken;
89 };
90 
91 inline bool
92 UserMessagingListener::operator==(const NotificationListener& _other) const
93 {
94 	const UserMessagingListener* other
95 		= dynamic_cast<const UserMessagingListener*>(&_other);
96 	return other != NULL && other->Port() == Port()
97 		&& other->Token() == Token();
98 }
99 
100 class NotificationService : public BReferenceable {
101 public:
102 	virtual						~NotificationService();
103 
104 	virtual status_t			AddListener(const KMessage* eventSpecifier,
105 									NotificationListener& listener) = 0;
106 	virtual status_t			RemoveListener(const KMessage* eventSpecifier,
107 									NotificationListener& listener) = 0;
108 	virtual status_t			UpdateListener(const KMessage* eventSpecifier,
109 									NotificationListener& listener) = 0;
110 
111 	virtual const char*			Name() = 0;
112 			NotificationService*&
113 								Link() { return fLink; }
114 
115 private:
116 			NotificationService* fLink;
117 };
118 
119 struct default_listener : public DoublyLinkedListLinkImpl<default_listener> {
120 	~default_listener();
121 
122 	uint32	eventMask;
123 	team_id	team;
124 	NotificationListener* listener;
125 };
126 
127 typedef DoublyLinkedList<default_listener> DefaultListenerList;
128 
129 
130 class DefaultNotificationService : public NotificationService {
131 public:
132 								DefaultNotificationService(const char* name);
133 	virtual						~DefaultNotificationService();
134 
135 	inline	bool				Lock()
136 									{ return recursive_lock_lock(&fLock)
137 										== B_OK; }
138 	inline	void				Unlock()
139 									{ recursive_lock_unlock(&fLock); }
140 
141 	inline	void				Notify(const KMessage& event, uint32 eventMask);
142 			void				NotifyLocked(const KMessage& event,
143 									uint32 eventMask);
144 
145 	inline	bool				HasListeners() const
146 									{ return !fListeners.IsEmpty(); }
147 	virtual status_t			AddListener(const KMessage* eventSpecifier,
148 									NotificationListener& listener);
149 	virtual status_t			UpdateListener(const KMessage* eventSpecifier,
150 									NotificationListener& listener);
151 	virtual status_t			RemoveListener(const KMessage* eventSpecifier,
152 									NotificationListener& listener);
153 
154 	virtual const char*			Name() { return fName; }
155 
156 			status_t			Register();
157 			void				Unregister();
158 
159 protected:
160 	virtual status_t			ToEventMask(const KMessage& eventSpecifier,
161 									uint32& eventMask);
162 	virtual	void				FirstAdded();
163 	virtual	void				LastRemoved();
164 
165 			recursive_lock		fLock;
166 			DefaultListenerList	fListeners;
167 			const char*			fName;
168 };
169 
170 class DefaultUserNotificationService : public DefaultNotificationService,
171 	NotificationListener {
172 public:
173 								DefaultUserNotificationService(
174 									const char* name);
175 	virtual						~DefaultUserNotificationService();
176 
177 	virtual	status_t			AddListener(const KMessage* eventSpecifier,
178 									NotificationListener& listener);
179 	virtual	status_t			UpdateListener(const KMessage* eventSpecifier,
180 									NotificationListener& listener);
181 	virtual	status_t			RemoveListener(const KMessage* eventSpecifier,
182 									NotificationListener& listener);
183 
184 			status_t			RemoveUserListeners(port_id port, uint32 token);
185 			status_t			UpdateUserListener(uint32 eventMask,
186 									port_id port, uint32 token);
187 
188 private:
189 	virtual void				EventOccurred(NotificationService& service,
190 									const KMessage* event);
191 	virtual void				AllListenersNotified(
192 									NotificationService& service);
193 			status_t			_AddListener(uint32 eventMask,
194 									NotificationListener& listener);
195 
196 			UserMessagingMessageSender fSender;
197 };
198 
199 class NotificationManager {
200 public:
201 	static NotificationManager& Manager();
202 	static status_t CreateManager();
203 
204 			status_t			RegisterService(NotificationService& service);
205 			void				UnregisterService(
206 									NotificationService& service);
207 
208 			status_t			AddListener(const char* service,
209 									uint32 eventMask,
210 									NotificationListener& listener);
211 			status_t			AddListener(const char* service,
212 									const KMessage* eventSpecifier,
213 									NotificationListener& listener);
214 
215 			status_t			UpdateListener(const char* service,
216 									uint32 eventMask,
217 									NotificationListener& listener);
218 			status_t			UpdateListener(const char* service,
219 									const KMessage* eventSpecifier,
220 									NotificationListener& listener);
221 
222 			status_t			RemoveListener(const char* service,
223 									const KMessage* eventSpecifier,
224 									NotificationListener& listener);
225 
226 private:
227 								NotificationManager();
228 								~NotificationManager();
229 
230 			status_t			_Init();
231 			NotificationService* _ServiceFor(const char* name);
232 
233 	struct HashDefinition {
234 		typedef const char* KeyType;
235 		typedef	NotificationService ValueType;
236 
237 		size_t HashKey(const char* key) const
238 			{ return hash_hash_string(key); }
239 		size_t Hash(NotificationService *service) const
240 			{ return hash_hash_string(service->Name()); }
241 		bool Compare(const char* key, NotificationService* service) const
242 			{ return !strcmp(key, service->Name()); }
243 		NotificationService*& GetLink(
244 				NotificationService* service) const
245 			{ return service->Link(); }
246 	};
247 	typedef BOpenHashTable<HashDefinition> ServiceHash;
248 
249 	static	NotificationManager	sManager;
250 
251 			mutex				fLock;
252 			ServiceHash			fServiceHash;
253 };
254 
255 
256 void
257 DefaultNotificationService::Notify(const KMessage& event, uint32 eventMask)
258 {
259 	RecursiveLocker _(fLock);
260 	NotifyLocked(event, eventMask);
261 }
262 
263 
264 extern "C" {
265 
266 #endif	// __cplusplus
267 
268 void notifications_init(void);
269 
270 #ifdef __cplusplus
271 }
272 #endif	// __cplusplus
273 
274 #endif	// _KERNEL_NOTIFICATIONS_H
275