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