xref: /haiku/src/system/kernel/events/Notifications.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
10 
11 #include <Notifications.h>
12 
13 #include <new>
14 
15 #include <team.h>
16 
17 
18 #ifdef _KERNEL_MODE
19 
20 static const char* kEventMaskString = "event mask";
21 
22 NotificationManager NotificationManager::sManager;
23 
24 #endif
25 
26 
27 // #pragma mark - NotificationListener
28 
29 
30 NotificationListener::~NotificationListener()
31 {
32 }
33 
34 
35 void
36 NotificationListener::EventOccurred(NotificationService& service,
37 	const KMessage* event)
38 {
39 }
40 
41 
42 void
43 NotificationListener::AllListenersNotified(NotificationService& service)
44 {
45 }
46 
47 
48 bool
49 NotificationListener::operator==(const NotificationListener& other) const
50 {
51 	return &other == this;
52 }
53 
54 
55 // #pragma mark - UserMessagingMessageSender
56 
57 
58 #ifdef _KERNEL_MODE
59 
60 
61 UserMessagingMessageSender::UserMessagingMessageSender()
62 	:
63 	fMessage(NULL),
64 	fTargetCount(0)
65 {
66 }
67 
68 
69 void
70 UserMessagingMessageSender::SendMessage(const KMessage* message, port_id port,
71 	int32 token)
72 {
73 	if ((message != fMessage && fMessage != NULL)
74 		|| fTargetCount == MAX_MESSAGING_TARGET_COUNT) {
75 		FlushMessage();
76 	}
77 
78 	fMessage = message;
79 	fTargets[fTargetCount].port = port;
80 	fTargets[fTargetCount].token = token;
81 	fTargetCount++;
82 }
83 
84 
85 void
86 UserMessagingMessageSender::FlushMessage()
87 {
88 	if (fMessage != NULL && fTargetCount > 0) {
89 		send_message(fMessage->Buffer(), fMessage->ContentSize(),
90 			fTargets, fTargetCount);
91 	}
92 
93 	fMessage = NULL;
94 	fTargetCount = 0;
95 }
96 
97 
98 // #pragma mark - UserMessagingListener
99 
100 
101 UserMessagingListener::UserMessagingListener(UserMessagingMessageSender& sender,
102 		port_id port, int32 token)
103 	:
104 	fSender(sender),
105 	fPort(port),
106 	fToken(token)
107 {
108 }
109 
110 
111 UserMessagingListener::~UserMessagingListener()
112 {
113 }
114 
115 
116 void
117 UserMessagingListener::EventOccurred(NotificationService& service,
118 	const KMessage* event)
119 {
120 	fSender.SendMessage(event, fPort, fToken);
121 }
122 
123 
124 void
125 UserMessagingListener::AllListenersNotified(NotificationService& service)
126 {
127 	fSender.FlushMessage();
128 }
129 
130 
131 //	#pragma mark - NotificationService
132 
133 
134 NotificationService::~NotificationService()
135 {
136 }
137 
138 
139 //	#pragma mark - default_listener
140 
141 
142 default_listener::~default_listener()
143 {
144 	// Only delete the listener if it's one of ours
145 	if (dynamic_cast<UserMessagingListener*>(listener) != NULL) {
146 		delete listener;
147 	}
148 }
149 
150 
151 //	#pragma mark - DefaultNotificationService
152 
153 
154 DefaultNotificationService::DefaultNotificationService(const char* name)
155 	:
156 	fName(name)
157 {
158 	recursive_lock_init(&fLock, name);
159 }
160 
161 
162 DefaultNotificationService::~DefaultNotificationService()
163 {
164 	recursive_lock_destroy(&fLock);
165 }
166 
167 
168 /*!	\brief Notifies all registered listeners.
169 	\param event The message defining the event
170 	\param eventMask Only listeners with an event mask sharing at least one
171 		common bit with this mask will receive the event.
172 */
173 void
174 DefaultNotificationService::NotifyLocked(const KMessage& event, uint32 eventMask)
175 {
176 	// Note: The following iterations support that the listener removes itself
177 	// in the hook method. That's a property of the DoublyLinkedList iterator.
178 
179 	// notify all listeners about the event
180 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
181 	while (default_listener* listener = iterator.Next()) {
182 		if ((eventMask & listener->eventMask) != 0)
183 			listener->listener->EventOccurred(*this, &event);
184 	}
185 
186 	// notify all listeners that all listeners have been notified
187 	iterator = fListeners.GetIterator();
188 	while (default_listener* listener = iterator.Next()) {
189 		if ((eventMask & listener->eventMask) != 0)
190 			listener->listener->AllListenersNotified(*this);
191 	}
192 }
193 
194 
195 status_t
196 DefaultNotificationService::AddListener(const KMessage* eventSpecifier,
197 	NotificationListener& notificationListener)
198 {
199 	if (eventSpecifier == NULL)
200 		return B_BAD_VALUE;
201 
202 	uint32 eventMask;
203 	status_t status = ToEventMask(*eventSpecifier, eventMask);
204 	if (status != B_OK)
205 		return status;
206 
207 	default_listener* listener = new(std::nothrow) default_listener;
208 	if (listener == NULL)
209 		return B_NO_MEMORY;
210 
211 	listener->eventMask = eventMask;
212 	listener->team = -1;
213 	listener->listener = &notificationListener;
214 
215 	RecursiveLocker _(fLock);
216 	if (fListeners.IsEmpty())
217 		FirstAdded();
218 	fListeners.Add(listener);
219 
220 	return B_OK;
221 }
222 
223 
224 status_t
225 DefaultNotificationService::UpdateListener(const KMessage* eventSpecifier,
226 	NotificationListener& notificationListener)
227 {
228 	return B_NOT_SUPPORTED;
229 }
230 
231 
232 status_t
233 DefaultNotificationService::RemoveListener(const KMessage* eventSpecifier,
234 	NotificationListener& notificationListener)
235 {
236 	RecursiveLocker _(fLock);
237 
238 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
239 	while (default_listener* listener = iterator.Next()) {
240 		if (listener->listener == &notificationListener) {
241 			iterator.Remove();
242 			delete listener;
243 
244 			if (fListeners.IsEmpty())
245 				LastRemoved();
246 			return B_OK;
247 		}
248 	}
249 
250 	return B_ENTRY_NOT_FOUND;
251 }
252 
253 
254 status_t
255 DefaultNotificationService::Register()
256 {
257 	return NotificationManager::Manager().RegisterService(*this);
258 }
259 
260 
261 void
262 DefaultNotificationService::Unregister()
263 {
264 	NotificationManager::Manager().UnregisterService(*this);
265 }
266 
267 
268 status_t
269 DefaultNotificationService::ToEventMask(const KMessage& eventSpecifier,
270 	uint32& eventMask)
271 {
272 	return eventSpecifier.FindInt32("event mask", (int32*)&eventMask);
273 }
274 
275 
276 void
277 DefaultNotificationService::FirstAdded()
278 {
279 }
280 
281 
282 void
283 DefaultNotificationService::LastRemoved()
284 {
285 }
286 
287 
288 //	#pragma mark - DefaultUserNotificationService
289 
290 
291 DefaultUserNotificationService::DefaultUserNotificationService(const char* name)
292 	: DefaultNotificationService(name)
293 {
294 	NotificationManager::Manager().AddListener("teams", TEAM_REMOVED, *this);
295 }
296 
297 
298 DefaultUserNotificationService::~DefaultUserNotificationService()
299 {
300 	NotificationManager::Manager().RemoveListener("teams", NULL, *this);
301 }
302 
303 
304 status_t
305 DefaultUserNotificationService::AddListener(const KMessage* eventSpecifier,
306 	NotificationListener& listener)
307 {
308 	if (eventSpecifier == NULL)
309 		return B_BAD_VALUE;
310 
311 	uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0);
312 
313 	return _AddListener(eventMask, listener);
314 }
315 
316 
317 status_t
318 DefaultUserNotificationService::UpdateListener(const KMessage* eventSpecifier,
319 	NotificationListener& notificationListener)
320 {
321 	if (eventSpecifier == NULL)
322 		return B_BAD_VALUE;
323 
324 	uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0);
325 	bool addEvents = eventSpecifier->GetBool("add events", false);
326 
327 	RecursiveLocker _(fLock);
328 
329 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
330 	while (default_listener* listener = iterator.Next()) {
331 		if (*listener->listener == notificationListener) {
332 			if (addEvents)
333 				listener->eventMask |= eventMask;
334 			else
335 				listener->eventMask = eventMask;
336 			return B_OK;
337 		}
338 	}
339 
340 	return B_ENTRY_NOT_FOUND;
341 }
342 
343 
344 status_t
345 DefaultUserNotificationService::RemoveListener(const KMessage* eventSpecifier,
346 	NotificationListener& notificationListener)
347 {
348 	RecursiveLocker _(fLock);
349 
350 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
351 	while (default_listener* listener = iterator.Next()) {
352 		if (listener->listener == &notificationListener) {
353 			iterator.Remove();
354 			delete listener;
355 			return B_OK;
356 		}
357 	}
358 
359 	return B_ENTRY_NOT_FOUND;
360 }
361 
362 
363 status_t
364 DefaultUserNotificationService::RemoveUserListeners(port_id port, uint32 token)
365 {
366 	UserMessagingListener userListener(fSender, port, token);
367 
368 	RecursiveLocker _(fLock);
369 
370 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
371 	while (default_listener* listener = iterator.Next()) {
372 		if (*listener->listener == userListener) {
373 			iterator.Remove();
374 			delete listener;
375 
376 			if (fListeners.IsEmpty())
377 				LastRemoved();
378 			return B_OK;
379 		}
380 	}
381 
382 	return B_ENTRY_NOT_FOUND;
383 }
384 
385 
386 status_t
387 DefaultUserNotificationService::UpdateUserListener(uint32 eventMask,
388 	port_id port, uint32 token)
389 {
390 	UserMessagingListener userListener(fSender, port, token);
391 
392 	RecursiveLocker _(fLock);
393 
394 	DefaultListenerList::Iterator iterator = fListeners.GetIterator();
395 	while (default_listener* listener = iterator.Next()) {
396 		if (*listener->listener == userListener) {
397 			listener->eventMask |= eventMask;
398 			return B_OK;
399 		}
400 	}
401 
402 	UserMessagingListener* copiedListener
403 		= new(std::nothrow) UserMessagingListener(userListener);
404 	if (copiedListener == NULL)
405 		return B_NO_MEMORY;
406 
407 	status_t status = _AddListener(eventMask, *copiedListener);
408 	if (status != B_OK)
409 		delete copiedListener;
410 
411 	return status;
412 }
413 
414 
415 void
416 DefaultUserNotificationService::EventOccurred(NotificationService& service,
417 	const KMessage* event)
418 {
419 	int32 eventCode = event->GetInt32("event", -1);
420 	team_id team = event->GetInt32("team", -1);
421 
422 	if (eventCode == TEAM_REMOVED && team >= B_OK) {
423 		// check if we have any listeners from that team, and remove them
424 		RecursiveLocker _(fLock);
425 
426 		DefaultListenerList::Iterator iterator = fListeners.GetIterator();
427 		while (default_listener* listener = iterator.Next()) {
428 			if (listener->team == team) {
429 				iterator.Remove();
430 				delete listener;
431 			}
432 		}
433 	}
434 }
435 
436 
437 void
438 DefaultUserNotificationService::AllListenersNotified(
439 	NotificationService& service)
440 {
441 }
442 
443 
444 status_t
445 DefaultUserNotificationService::_AddListener(uint32 eventMask,
446 	NotificationListener& notificationListener)
447 {
448 	default_listener* listener = new(std::nothrow) default_listener;
449 	if (listener == NULL)
450 		return B_NO_MEMORY;
451 
452 	listener->eventMask = eventMask;
453 	listener->team = team_get_current_team_id();
454 	listener->listener = &notificationListener;
455 
456 	RecursiveLocker _(fLock);
457 	if (fListeners.IsEmpty())
458 		FirstAdded();
459 	fListeners.Add(listener);
460 
461 	return B_OK;
462 }
463 
464 
465 //	#pragma mark - NotificationManager
466 
467 
468 /*static*/ NotificationManager&
469 NotificationManager::Manager()
470 {
471 	return sManager;
472 }
473 
474 
475 /*static*/ status_t
476 NotificationManager::CreateManager()
477 {
478 	new(&sManager) NotificationManager;
479 	return sManager._Init();
480 }
481 
482 
483 NotificationManager::NotificationManager()
484 {
485 }
486 
487 
488 NotificationManager::~NotificationManager()
489 {
490 }
491 
492 
493 status_t
494 NotificationManager::_Init()
495 {
496 	mutex_init(&fLock, "notification manager");
497 
498 	return fServiceHash.Init();
499 }
500 
501 
502 NotificationService*
503 NotificationManager::_ServiceFor(const char* name)
504 {
505 	return fServiceHash.Lookup(name);
506 }
507 
508 
509 status_t
510 NotificationManager::RegisterService(NotificationService& service)
511 {
512 	MutexLocker _(fLock);
513 
514 	if (_ServiceFor(service.Name()))
515 		return B_NAME_IN_USE;
516 
517 	status_t status = fServiceHash.Insert(&service);
518 	if (status == B_OK)
519 		service.AcquireReference();
520 
521 	return status;
522 }
523 
524 
525 void
526 NotificationManager::UnregisterService(NotificationService& service)
527 {
528 	MutexLocker _(fLock);
529 	fServiceHash.Remove(&service);
530 	service.ReleaseReference();
531 }
532 
533 
534 status_t
535 NotificationManager::AddListener(const char* serviceName,
536 	uint32 eventMask, NotificationListener& listener)
537 {
538 	char buffer[96];
539 	KMessage specifier;
540 	specifier.SetTo(buffer, sizeof(buffer), 0);
541 	specifier.AddInt32(kEventMaskString, eventMask);
542 
543 	return AddListener(serviceName, &specifier, listener);
544 }
545 
546 
547 status_t
548 NotificationManager::AddListener(const char* serviceName,
549 	const KMessage* eventSpecifier, NotificationListener& listener)
550 {
551 	MutexLocker locker(fLock);
552 	NotificationService* service = _ServiceFor(serviceName);
553 	if (service == NULL)
554 		return B_NAME_NOT_FOUND;
555 
556 	BReference<NotificationService> reference(service);
557 	locker.Unlock();
558 
559 	return service->AddListener(eventSpecifier, listener);
560 }
561 
562 
563 status_t
564 NotificationManager::UpdateListener(const char* serviceName,
565 	uint32 eventMask, NotificationListener& listener)
566 {
567 	char buffer[96];
568 	KMessage specifier;
569 	specifier.SetTo(buffer, sizeof(buffer), 0);
570 	specifier.AddInt32(kEventMaskString, eventMask);
571 
572 	return UpdateListener(serviceName, &specifier, listener);
573 }
574 
575 
576 status_t
577 NotificationManager::UpdateListener(const char* serviceName,
578 	const KMessage* eventSpecifier, NotificationListener& listener)
579 {
580 	MutexLocker locker(fLock);
581 	NotificationService* service = _ServiceFor(serviceName);
582 	if (service == NULL)
583 		return B_NAME_NOT_FOUND;
584 
585 	BReference<NotificationService> reference(service);
586 	locker.Unlock();
587 
588 	return service->UpdateListener(eventSpecifier, listener);
589 }
590 
591 
592 status_t
593 NotificationManager::RemoveListener(const char* serviceName,
594 	const KMessage* eventSpecifier, NotificationListener& listener)
595 {
596 	MutexLocker locker(fLock);
597 	NotificationService* service = _ServiceFor(serviceName);
598 	if (service == NULL)
599 		return B_NAME_NOT_FOUND;
600 
601 	BReference<NotificationService> reference(service);
602 	locker.Unlock();
603 
604 	return service->RemoveListener(eventSpecifier, listener);
605 }
606 
607 
608 //	#pragma mark -
609 
610 
611 extern "C" void
612 notifications_init(void)
613 {
614 	status_t status = NotificationManager::CreateManager();
615 	if (status < B_OK) {
616 		panic("Creating the notification manager failed: %s\n",
617 			strerror(status));
618 	}
619 }
620 
621 
622 #endif	// _KERNEL_MODE
623