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