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
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
155			status_t			Register();
156			void				Unregister();
157
158protected:
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
169class DefaultUserNotificationService : public DefaultNotificationService,
170	NotificationListener {
171public:
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
187private:
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
198class NotificationManager {
199public:
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
225private:
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
255void
256DefaultNotificationService::Notify(const KMessage& event, uint32 eventMask)
257{
258	RecursiveLocker _(fLock);
259	NotifyLocked(event, eventMask);
260}
261
262
263extern "C" {
264
265#endif	// __cplusplus
266
267void notifications_init(void);
268
269#ifdef __cplusplus
270}
271#endif	// __cplusplus
272
273#endif	// _KERNEL_NOTIFICATIONS_H
274