xref: /haiku/headers/private/kernel/Notifications.h (revision 481f986b59e7782458dcc5fe98ad59a57480e5db)
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/khash.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 Referenceable {
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 protected:
156 	virtual status_t			ToEventMask(const KMessage& eventSpecifier,
157 									uint32& eventMask);
158 	virtual	void				FirstAdded();
159 	virtual	void				LastRemoved();
160 
161 			recursive_lock		fLock;
162 			DefaultListenerList	fListeners;
163 			const char*			fName;
164 };
165 
166 class DefaultUserNotificationService : public DefaultNotificationService,
167 	NotificationListener {
168 public:
169 								DefaultUserNotificationService(
170 									const char* name);
171 	virtual						~DefaultUserNotificationService();
172 
173 	virtual	status_t			AddListener(const KMessage* eventSpecifier,
174 									NotificationListener& listener);
175 	virtual	status_t			UpdateListener(const KMessage* eventSpecifier,
176 									NotificationListener& listener);
177 	virtual	status_t			RemoveListener(const KMessage* eventSpecifier,
178 									NotificationListener& listener);
179 
180 			status_t			RemoveUserListeners(port_id port, uint32 token);
181 			status_t			UpdateUserListener(uint32 eventMask,
182 									port_id port, uint32 token);
183 
184 private:
185 	virtual void				EventOccurred(NotificationService& service,
186 									const KMessage* event);
187 	virtual void				AllListenersNotified(
188 									NotificationService& service);
189 			status_t			_AddListener(uint32 eventMask,
190 									NotificationListener& listener);
191 
192 			UserMessagingMessageSender fSender;
193 };
194 
195 class NotificationManager {
196 public:
197 	static NotificationManager& Manager();
198 	static status_t CreateManager();
199 
200 			status_t			RegisterService(NotificationService& service);
201 			void				UnregisterService(
202 									NotificationService& service);
203 
204 			status_t			AddListener(const char* service,
205 									uint32 eventMask,
206 									NotificationListener& listener);
207 			status_t			AddListener(const char* service,
208 									const KMessage* eventSpecifier,
209 									NotificationListener& listener);
210 
211 			status_t			UpdateListener(const char* service,
212 									uint32 eventMask,
213 									NotificationListener& listener);
214 			status_t			UpdateListener(const char* service,
215 									const KMessage* eventSpecifier,
216 									NotificationListener& listener);
217 
218 			status_t			RemoveListener(const char* service,
219 									const KMessage* eventSpecifier,
220 									NotificationListener& listener);
221 
222 private:
223 								NotificationManager();
224 								~NotificationManager();
225 
226 			status_t			_Init();
227 			NotificationService* _ServiceFor(const char* name);
228 
229 	struct HashDefinition {
230 		typedef const char* KeyType;
231 		typedef	NotificationService ValueType;
232 
233 		size_t HashKey(const char* key) const
234 			{ return hash_hash_string(key); }
235 		size_t Hash(NotificationService *service) const
236 			{ return hash_hash_string(service->Name()); }
237 		bool Compare(const char* key, NotificationService* service) const
238 			{ return !strcmp(key, service->Name()); }
239 		NotificationService*& GetLink(
240 				NotificationService* service) const
241 			{ return service->Link(); }
242 	};
243 	typedef BOpenHashTable<HashDefinition> ServiceHash;
244 
245 	static	NotificationManager	sManager;
246 
247 			mutex				fLock;
248 			ServiceHash			fServiceHash;
249 };
250 
251 
252 void
253 DefaultNotificationService::Notify(const KMessage& event, uint32 eventMask)
254 {
255 	RecursiveLocker _(fLock);
256 	NotifyLocked(event, eventMask);
257 }
258 
259 
260 extern "C" {
261 
262 #endif	// __cplusplus
263 
264 void notifications_init(void);
265 
266 #ifdef __cplusplus
267 }
268 #endif	// __cplusplus
269 
270 #endif	// _KERNEL_NOTIFICATIONS_H
271