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
29class NotificationService;
30
31class NotificationListener {
32public:
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
48class UserMessagingMessageSender {
49public:
50								UserMessagingMessageSender();
51
52			void				SendMessage(const KMessage* message,
53									port_id port, int32 token);
54			void				FlushMessage();
55
56private:
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
66class UserMessagingListener : public NotificationListener {
67public:
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
84private:
85	UserMessagingMessageSender&	fSender;
86	port_id						fPort;
87	int32						fToken;
88};
89
90inline bool
91UserMessagingListener::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
99class NotificationService : public BReferenceable {
100public:
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
114private:
115			NotificationService* fLink;
116};
117
118struct default_listener : public DoublyLinkedListLinkImpl<default_listener> {
119	~default_listener();
120
121	uint32	eventMask;
122	team_id	team;
123	NotificationListener* listener;
124};
125
126typedef DoublyLinkedList<default_listener> DefaultListenerList;
127
128
129class DefaultNotificationService : public NotificationService {
130public:
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
155protected:
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
166class DefaultUserNotificationService : public DefaultNotificationService,
167	NotificationListener {
168public:
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
184private:
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
195class NotificationManager {
196public:
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
222private:
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
252void
253DefaultNotificationService::Notify(const KMessage& event, uint32 eventMask)
254{
255	RecursiveLocker _(fLock);
256	NotifyLocked(event, eventMask);
257}
258
259
260extern "C" {
261
262#endif	// __cplusplus
263
264void notifications_init(void);
265
266#ifdef __cplusplus
267}
268#endif	// __cplusplus
269
270#endif	// _KERNEL_NOTIFICATIONS_H
271