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 = ¬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 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 == ¬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 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 == ¬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 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 = ¬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& 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