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
~NotificationListener()30 NotificationListener::~NotificationListener()
31 {
32 }
33
34
35 void
EventOccurred(NotificationService & service,const KMessage * event)36 NotificationListener::EventOccurred(NotificationService& service,
37 const KMessage* event)
38 {
39 }
40
41
42 void
AllListenersNotified(NotificationService & service)43 NotificationListener::AllListenersNotified(NotificationService& service)
44 {
45 }
46
47
48 bool
operator ==(const NotificationListener & other) const49 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
UserMessagingMessageSender()61 UserMessagingMessageSender::UserMessagingMessageSender()
62 :
63 fMessage(NULL),
64 fTargetCount(0)
65 {
66 }
67
68
69 void
SendMessage(const KMessage * message,port_id port,int32 token)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
FlushMessage()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
UserMessagingListener(UserMessagingMessageSender & sender,port_id port,int32 token)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
~UserMessagingListener()111 UserMessagingListener::~UserMessagingListener()
112 {
113 }
114
115
116 void
EventOccurred(NotificationService & service,const KMessage * event)117 UserMessagingListener::EventOccurred(NotificationService& service,
118 const KMessage* event)
119 {
120 fSender.SendMessage(event, fPort, fToken);
121 }
122
123
124 void
AllListenersNotified(NotificationService & service)125 UserMessagingListener::AllListenersNotified(NotificationService& service)
126 {
127 fSender.FlushMessage();
128 }
129
130
131 // #pragma mark - NotificationService
132
133
~NotificationService()134 NotificationService::~NotificationService()
135 {
136 }
137
138
139 // #pragma mark - default_listener
140
141
~default_listener()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
DefaultNotificationService(const char * name)154 DefaultNotificationService::DefaultNotificationService(const char* name)
155 :
156 fName(name)
157 {
158 recursive_lock_init(&fLock, name);
159 }
160
161
~DefaultNotificationService()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
NotifyLocked(const KMessage & event,uint32 eventMask)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
AddListener(const KMessage * eventSpecifier,NotificationListener & notificationListener)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 = ¬ificationListener;
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
UpdateListener(const KMessage * eventSpecifier,NotificationListener & notificationListener)225 DefaultNotificationService::UpdateListener(const KMessage* eventSpecifier,
226 NotificationListener& notificationListener)
227 {
228 return B_NOT_SUPPORTED;
229 }
230
231
232 status_t
RemoveListener(const KMessage * eventSpecifier,NotificationListener & notificationListener)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 == ¬ificationListener) {
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
Register()255 DefaultNotificationService::Register()
256 {
257 return NotificationManager::Manager().RegisterService(*this);
258 }
259
260
261 void
Unregister()262 DefaultNotificationService::Unregister()
263 {
264 NotificationManager::Manager().UnregisterService(*this);
265 }
266
267
268 status_t
ToEventMask(const KMessage & eventSpecifier,uint32 & eventMask)269 DefaultNotificationService::ToEventMask(const KMessage& eventSpecifier,
270 uint32& eventMask)
271 {
272 return eventSpecifier.FindInt32("event mask", (int32*)&eventMask);
273 }
274
275
276 void
FirstAdded()277 DefaultNotificationService::FirstAdded()
278 {
279 }
280
281
282 void
LastRemoved()283 DefaultNotificationService::LastRemoved()
284 {
285 }
286
287
288 // #pragma mark - DefaultUserNotificationService
289
290
DefaultUserNotificationService(const char * name)291 DefaultUserNotificationService::DefaultUserNotificationService(const char* name)
292 : DefaultNotificationService(name)
293 {
294 NotificationManager::Manager().AddListener("teams", TEAM_REMOVED, *this);
295 }
296
297
~DefaultUserNotificationService()298 DefaultUserNotificationService::~DefaultUserNotificationService()
299 {
300 NotificationManager::Manager().RemoveListener("teams", NULL, *this);
301 }
302
303
304 status_t
AddListener(const KMessage * eventSpecifier,NotificationListener & listener)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
UpdateListener(const KMessage * eventSpecifier,NotificationListener & notificationListener)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
RemoveListener(const KMessage * eventSpecifier,NotificationListener & notificationListener)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 == ¬ificationListener) {
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
RemoveUserListeners(port_id port,uint32 token)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
UpdateUserListener(uint32 eventMask,port_id port,uint32 token)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
EventOccurred(NotificationService & service,const KMessage * event)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
AllListenersNotified(NotificationService & service)438 DefaultUserNotificationService::AllListenersNotified(
439 NotificationService& service)
440 {
441 }
442
443
444 status_t
_AddListener(uint32 eventMask,NotificationListener & notificationListener)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 = ¬ificationListener;
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&
Manager()469 NotificationManager::Manager()
470 {
471 return sManager;
472 }
473
474
475 /*static*/ status_t
CreateManager()476 NotificationManager::CreateManager()
477 {
478 new(&sManager) NotificationManager;
479 return sManager._Init();
480 }
481
482
NotificationManager()483 NotificationManager::NotificationManager()
484 {
485 }
486
487
~NotificationManager()488 NotificationManager::~NotificationManager()
489 {
490 }
491
492
493 status_t
_Init()494 NotificationManager::_Init()
495 {
496 mutex_init(&fLock, "notification manager");
497
498 return fServiceHash.Init();
499 }
500
501
502 NotificationService*
_ServiceFor(const char * name)503 NotificationManager::_ServiceFor(const char* name)
504 {
505 return fServiceHash.Lookup(name);
506 }
507
508
509 status_t
RegisterService(NotificationService & service)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
UnregisterService(NotificationService & service)526 NotificationManager::UnregisterService(NotificationService& service)
527 {
528 MutexLocker _(fLock);
529 fServiceHash.Remove(&service);
530 service.ReleaseReference();
531 }
532
533
534 status_t
AddListener(const char * serviceName,uint32 eventMask,NotificationListener & listener)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
AddListener(const char * serviceName,const KMessage * eventSpecifier,NotificationListener & listener)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
UpdateListener(const char * serviceName,uint32 eventMask,NotificationListener & listener)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
UpdateListener(const char * serviceName,const KMessage * eventSpecifier,NotificationListener & listener)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
RemoveListener(const char * serviceName,const KMessage * eventSpecifier,NotificationListener & listener)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
notifications_init(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