diff --git a/headers/private/kernel/Notifications.h b/headers/private/kernel/Notifications.h index d09ea0d110..61d8125f63 100644 --- a/headers/private/kernel/Notifications.h +++ b/headers/private/kernel/Notifications.h @@ -1,5 +1,5 @@ /* - * Copyright 2007, Haiku, Inc. All Rights Reserved. + * Copyright 2007-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -29,124 +29,213 @@ class NotificationService; class NotificationListener { - public: - virtual ~NotificationListener(); +public: + virtual ~NotificationListener(); - virtual void EventOccured(NotificationService& service, - const KMessage* event); - virtual void AllListenersNotified(NotificationService& service); + virtual void EventOccured(NotificationService& service, + const KMessage* event); + virtual void AllListenersNotified( + NotificationService& service); - virtual bool operator==(const NotificationListener& other) const; + virtual bool operator==( + const NotificationListener& other) const; - bool operator!=(const NotificationListener& other) const - { return !(*this == other); } + bool operator!=( + const NotificationListener& other) const + { return !(*this == other); } }; class UserMessagingMessageSender { - public: - UserMessagingMessageSender(); +public: + UserMessagingMessageSender(); - void SendMessage(const KMessage* message, port_id port, int32 token); - void FlushMessage(); + void SendMessage(const KMessage* message, + port_id port, int32 token); + void FlushMessage(); - private: - enum { - MAX_MESSAGING_TARGET_COUNT = 16, - }; +private: + enum { + MAX_MESSAGING_TARGET_COUNT = 16, + }; - const KMessage* fMessage; - messaging_target fTargets[MAX_MESSAGING_TARGET_COUNT]; - int32 fTargetCount; + const KMessage* fMessage; + messaging_target fTargets[MAX_MESSAGING_TARGET_COUNT]; + int32 fTargetCount; }; class UserMessagingListener : public NotificationListener { - public: - UserMessagingListener(UserMessagingMessageSender& sender, port_id port, - int32 token); - virtual ~UserMessagingListener(); +public: + UserMessagingListener( + UserMessagingMessageSender& sender, + port_id port, int32 token); + virtual ~UserMessagingListener(); - virtual void EventOccured(NotificationService& service, - const KMessage* event); - virtual void AllListenersNotified(NotificationService& service); + virtual void EventOccured(NotificationService& service, + const KMessage* event); + virtual void AllListenersNotified( + NotificationService& service); - port_id Port() const { return fPort; } - int32 Token() const { return fToken; } + port_id Port() const { return fPort; } + int32 Token() const { return fToken; } - private: - UserMessagingMessageSender& fSender; - port_id fPort; - int32 fToken; + bool operator==( + const NotificationListener& _other) const; + +private: + UserMessagingMessageSender& fSender; + port_id fPort; + int32 fToken; }; +inline bool +UserMessagingListener::operator==(const NotificationListener& _other) const +{ + const UserMessagingListener* other + = dynamic_cast(&_other); + return other != NULL && other->Port() == Port() + && other->Token() == Token(); +} + class NotificationService : public Referenceable { - public: - virtual ~NotificationService(); +public: + virtual ~NotificationService(); - virtual status_t AddListener(const KMessage* eventSpecifier, - NotificationListener& listener) = 0; - virtual status_t RemoveListener(const KMessage* eventSpecifier, - NotificationListener& listener) = 0; - virtual status_t UpdateListener(const KMessage* eventSpecifier, - NotificationListener& listener) = 0; + virtual status_t AddListener(const KMessage* eventSpecifier, + NotificationListener& listener) = 0; + virtual status_t RemoveListener(const KMessage* eventSpecifier, + NotificationListener& listener) = 0; + virtual status_t UpdateListener(const KMessage* eventSpecifier, + NotificationListener& listener) = 0; - virtual const char* Name() = 0; - HashTableLink& Link() { return fLink; } + virtual const char* Name() = 0; + HashTableLink& + Link() { return fLink; } - private: - HashTableLink fLink; +private: + HashTableLink fLink; +}; + +struct default_listener : public DoublyLinkedListLinkImpl { + ~default_listener(); + + uint32 flags; + team_id team; + NotificationListener* listener; +}; + +typedef DoublyLinkedList DefaultListenerList; + + +class DefaultNotificationService : public NotificationService { +public: + DefaultNotificationService(const char* name); + virtual ~DefaultNotificationService(); + + void Notify(const KMessage& event, uint32 flags); + + virtual status_t AddListener(const KMessage* eventSpecifier, + NotificationListener& listener); + virtual status_t UpdateListener(const KMessage* eventSpecifier, + NotificationListener& listener); + virtual status_t RemoveListener(const KMessage* eventSpecifier, + NotificationListener& listener); + + virtual const char* Name() { return fName; } + +protected: + virtual status_t _ToFlags(const KMessage& eventSpecifier, + uint32& flags); + virtual void _FirstAdded(); + virtual void _LastRemoved(); + + recursive_lock fLock; + DefaultListenerList fListeners; + const char* fName; +}; + +class DefaultUserNotificationService : public DefaultNotificationService, + NotificationListener { +public: + DefaultUserNotificationService( + const char* name); + virtual ~DefaultUserNotificationService(); + + virtual status_t AddListener(const KMessage* eventSpecifier, + NotificationListener& listener); + virtual status_t UpdateListener(const KMessage* eventSpecifier, + NotificationListener& listener); + virtual status_t RemoveListener(const KMessage* eventSpecifier, + NotificationListener& listener); + + status_t RemoveUserListeners(port_id port, uint32 token); + status_t UpdateUserListener(uint32 flags, + port_id port, uint32 token); + +private: + virtual void EventOccured(NotificationService& service, + const KMessage* event); + virtual void AllListenersNotified( + NotificationService& service); + status_t _AddListener(uint32 flags, + NotificationListener& listener); + + UserMessagingMessageSender fSender; }; class NotificationManager { - public: - static NotificationManager& Manager(); - static status_t CreateManager(); +public: + static NotificationManager& Manager(); + static status_t CreateManager(); - status_t RegisterService(NotificationService& service); - void UnregisterService(NotificationService& service); + status_t RegisterService(NotificationService& service); + void UnregisterService( + NotificationService& service); - NotificationService* GetService(const char* name); - void PutService(NotificationService* service); + status_t AddListener(const char* service, + uint32 eventMask, + NotificationListener& listener); + status_t AddListener(const char* service, + const KMessage* eventSpecifier, + NotificationListener& listener); - status_t AddListener(const char* service, uint32 eventMask, - NotificationListener& listener); - status_t AddListener(const char* service, - const KMessage* eventSpecifier, NotificationListener& listener); + status_t UpdateListener(const char* service, + uint32 eventMask, + NotificationListener& listener); + status_t UpdateListener(const char* service, + const KMessage* eventSpecifier, + NotificationListener& listener); - status_t UpdateListener(const char* service, - uint32 eventMask, NotificationListener& listener); - status_t UpdateListener(const char* service, - const KMessage* eventSpecifier, NotificationListener& listener); + status_t RemoveListener(const char* service, + const KMessage* eventSpecifier, + NotificationListener& listener); - status_t RemoveListener(const char* service, - const KMessage* eventSpecifier, NotificationListener& listener); +private: + NotificationManager(); + ~NotificationManager(); - private: - NotificationManager(); - ~NotificationManager(); + status_t _Init(); + NotificationService* _ServiceFor(const char* name); - status_t _Init(); - NotificationService* _ServiceFor(const char* name); + struct HashDefinition { + typedef const char* KeyType; + typedef NotificationService ValueType; - struct HashDefinition { - typedef const char* KeyType; - typedef NotificationService ValueType; + size_t HashKey(const char* key) const + { return hash_hash_string(key); } + size_t Hash(NotificationService *service) const + { return hash_hash_string(service->Name()); } + bool Compare(const char* key, NotificationService* service) const + { return !strcmp(key, service->Name()); } + HashTableLink* GetLink( + NotificationService* service) const + { return &service->Link(); } + }; + typedef OpenHashTable ServiceHash; - size_t HashKey(const char* key) const - { return hash_hash_string(key); } - size_t Hash(NotificationService *service) const - { return hash_hash_string(service->Name()); } - bool Compare(const char* key, NotificationService* service) const - { return !strcmp(key, service->Name()); } - HashTableLink* GetLink( - NotificationService* service) const - { return &service->Link(); } - }; + static NotificationManager sManager; - static NotificationManager sManager; - - mutex fLock; - typedef OpenHashTable ServiceHash; - ServiceHash fServiceHash; + mutex fLock; + ServiceHash fServiceHash; }; extern "C" { diff --git a/headers/private/kernel/port.h b/headers/private/kernel/port.h index bcc07f8f2c..fa5f905d50 100644 --- a/headers/private/kernel/port.h +++ b/headers/private/kernel/port.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku Inc. All Rights Reserved. + * Copyright 2005-2009, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT license. */ #ifndef _KERNEL_PORT_H @@ -22,6 +22,10 @@ enum { // kernel-only; memory must be locked }; +// port notifications +#define PORT_MONITOR '_Pm_' +#define PORT_ADDED 1 +#define PORT_REMOVED 2 #ifdef __cplusplus extern "C" { diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index 9238f3840c..bb497382e5 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007, Haiku Inc. All Rights Reserved. + * Copyright 2004-2009, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _TEAM_H @@ -9,6 +9,12 @@ #include +// Team notifications +#define TEAM_MONITOR '_Tm_' +#define TEAM_ADDED 1 +#define TEAM_REMOVED 2 + + #ifdef __cplusplus extern "C" { #endif diff --git a/src/add-ons/kernel/network/notifications/notifications.cpp b/src/add-ons/kernel/network/notifications/notifications.cpp index 63651889b8..2181ff6ad4 100644 --- a/src/add-ons/kernel/network/notifications/notifications.cpp +++ b/src/add-ons/kernel/network/notifications/notifications.cpp @@ -18,95 +18,38 @@ # define TRACE(x...) ; #endif -// TODO: add possibility to remove teams/ports that are gone - -static UserMessagingMessageSender sNotificationSender; - -struct net_listener : public DoublyLinkedListLinkImpl { - ~net_listener(); - - uint32 flags; - NotificationListener* listener; -}; - -typedef DoublyLinkedList ListenerList; - -class UserNetListener : public UserMessagingListener { -public: - UserNetListener(port_id port, int32 token) - : UserMessagingListener(sNotificationSender, port, token) - { - } - - bool operator==(const NotificationListener& _other) const - { - const UserNetListener* other - = dynamic_cast(&_other); - return other != NULL && other->Port() == Port() - && other->Token() == Token(); - } -}; - -class NetNotificationService : public NotificationService { +class NetNotificationService : public DefaultUserNotificationService { public: NetNotificationService(); virtual ~NetNotificationService(); void Notify(const KMessage& event); - status_t AddListener(const KMessage* eventSpecifier, - NotificationListener& listener); - status_t UpdateListener(const KMessage* eventSpecifier, - NotificationListener& listener); - status_t RemoveListener(const KMessage* eventSpecifier, - NotificationListener& listener); - - status_t RemoveUserListeners(port_id port, uint32 token); - status_t UpdateUserListener(uint32 flags, - port_id port, uint32 token); - - virtual const char* Name() { return "network"; } - -private: - status_t _AddListener(uint32 flags, - NotificationListener& listener); - - recursive_lock fRecursiveLock; - ListenerList fListeners; +protected: + virtual status_t _ToFlags(const KMessage& eventSpecifier, + uint32& flags); + virtual void _FirstAdded(); + virtual void _LastRemoved(); }; static NetNotificationService sNotificationService; -net_listener::~net_listener() -{ - // Only delete the listener if it's one of ours - if (dynamic_cast(listener) != NULL) { - TRACE("delete user listener %p\n", listener); - delete listener; - } -} - - // #pragma mark - NetNotificationService NetNotificationService::NetNotificationService() + : DefaultUserNotificationService("network") { - recursive_lock_init(&fRecursiveLock, "net notifications"); } NetNotificationService::~NetNotificationService() { - recursive_lock_destroy(&fRecursiveLock); } -/*! \brief Notifies all registered listeners. - \param event The message defining the event -*/ void NetNotificationService::Notify(const KMessage& event) { @@ -116,173 +59,36 @@ NetNotificationService::Notify(const KMessage& event) TRACE("notify for %lx\n", opcode); - RecursiveLocker _(fRecursiveLock); - - ListenerList::Iterator iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if ((listener->flags & opcode) != 0) { - TRACE(" notify listener %p for %lx\n", listener, opcode); - listener->listener->EventOccured(*this, &event); - } - } - - iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if ((listener->flags & opcode) != 0) - listener->listener->AllListenersNotified(*this); - } + DefaultUserNotificationService::Notify(event, opcode); } status_t -NetNotificationService::AddListener(const KMessage* eventSpecifier, - NotificationListener& listener) +NetNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) { - if (eventSpecifier == NULL) - return B_BAD_VALUE; - - uint32 flags = eventSpecifier->GetInt32("flags", 0); - - return _AddListener(flags, listener); -} - - -status_t -NetNotificationService::UpdateListener(const KMessage* eventSpecifier, - NotificationListener& notificationListener) -{ - if (eventSpecifier == NULL) - return B_BAD_VALUE; - - uint32 flags = eventSpecifier->GetInt32("flags", 0); - bool addFlags = eventSpecifier->GetBool("add flags", false); - - RecursiveLocker _(fRecursiveLock); - - ListenerList::Iterator iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if (*listener->listener == notificationListener) { - if (addFlags) - listener->flags |= flags; - else - listener->flags = flags; - return B_OK; - } - } - - return B_ENTRY_NOT_FOUND; -} - - -status_t -NetNotificationService::RemoveListener(const KMessage* eventSpecifier, - NotificationListener& notificationListener) -{ - RecursiveLocker _(fRecursiveLock); - - ListenerList::Iterator iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if (listener->listener == ¬ificationListener) { - TRACE("remove listener %p\n", listener); - iterator.Remove(); - delete listener; - - if (fListeners.IsEmpty()) { - // Give up the reference _AddListener() - put_module(NET_NOTIFICATIONS_MODULE_NAME); - } - return B_OK; - } - } - - return B_ENTRY_NOT_FOUND; -} - - -status_t -NetNotificationService::RemoveUserListeners(port_id port, uint32 token) -{ - UserNetListener userListener(port, token); - - RecursiveLocker _(fRecursiveLock); - - ListenerList::Iterator iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if (*listener->listener == userListener) { - TRACE("remove user listener %p\n", listener); - iterator.Remove(); - delete listener; - - if (fListeners.IsEmpty()) { - // Give up the reference _AddListener() - put_module(NET_NOTIFICATIONS_MODULE_NAME); - } - return B_OK; - } - } - - return B_ENTRY_NOT_FOUND; -} - - -status_t -NetNotificationService::UpdateUserListener(uint32 flags, port_id port, - uint32 token) -{ - UserNetListener userListener(port, token); - - RecursiveLocker _(fRecursiveLock); - - ListenerList::Iterator iterator = fListeners.GetIterator(); - while (net_listener* listener = iterator.Next()) { - if (*listener->listener == userListener) { - listener->flags |= flags; - return B_OK; - } - } - - UserNetListener* copiedListener = new(std::nothrow) UserNetListener( - userListener); - if (copiedListener == NULL) - return B_NO_MEMORY; - - status_t status = _AddListener(flags, *copiedListener); - if (status != B_OK) - delete copiedListener; - - return status; -} - - -status_t -NetNotificationService::_AddListener(uint32 flags, - NotificationListener& notificationListener) -{ - net_listener* listener = new(std::nothrow) net_listener; - if (listener == NULL) - return B_NO_MEMORY; - - TRACE("add %slistener %p for %lx\n", - dynamic_cast(¬ificationListener) != NULL - ? "user " : "", listener, flags); - - listener->flags = flags; - listener->listener = ¬ificationListener; - - RecursiveLocker _(fRecursiveLock); - - if (fListeners.IsEmpty()) { - // The reference counting doesn't work for us, as we'll have to - // ensure our module stays loaded. - module_info* dummy; - get_module(NET_NOTIFICATIONS_MODULE_NAME, &dummy); - } - - fListeners.Add(listener); + flags = eventSpecifier.GetInt32("flags", 0); return B_OK; } +void +NetNotificationService::_FirstAdded() +{ + // The reference counting doesn't work for us, as we'll have to + // ensure our module stays loaded. + module_info* dummy; + get_module(NET_NOTIFICATIONS_MODULE_NAME, &dummy); +} + + +void +NetNotificationService::_LastRemoved() +{ + // Give up the reference _AddListener() + put_module(NET_NOTIFICATIONS_MODULE_NAME); +} + + // #pragma mark - User generic syscall @@ -326,7 +132,6 @@ notifications_std_ops(int32 op, ...) case B_MODULE_INIT: TRACE("init\n"); - new(&sNotificationSender) UserMessagingMessageSender(); new(&sNotificationService) NetNotificationService(); register_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, @@ -338,7 +143,6 @@ notifications_std_ops(int32 op, ...) unregister_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, 1); - sNotificationSender.~UserMessagingMessageSender(); sNotificationService.~NetNotificationService(); return B_OK; diff --git a/src/system/kernel/Notifications.cpp b/src/system/kernel/Notifications.cpp index 203ce2ac52..7e2c0bac16 100644 --- a/src/system/kernel/Notifications.cpp +++ b/src/system/kernel/Notifications.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007, Haiku, Inc. All Rights Reserved. + * Copyright 2007-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -10,11 +10,13 @@ #include +#include + NotificationManager NotificationManager::sManager; -// #pragma mark - UserMessagingListener +// #pragma mark - NotificationListener NotificationListener::~NotificationListener() @@ -123,6 +125,316 @@ NotificationService::~NotificationService() } +// #pragma mark - default_listener + + +default_listener::~default_listener() +{ + // Only delete the listener if it's one of ours + if (dynamic_cast(listener) != NULL) { + delete listener; + } +} + + +// #pragma mark - NotificationService + + +DefaultNotificationService::DefaultNotificationService(const char* name) + : + fName(name) +{ + recursive_lock_init(&fLock, name); + NotificationManager::Manager().RegisterService(*this); +} + + +DefaultNotificationService::~DefaultNotificationService() +{ + NotificationManager::Manager().UnregisterService(*this); + recursive_lock_destroy(&fLock); +} + + +/*! \brief Notifies all registered listeners. + \param event The message defining the event + \param flags The flags that must be set in listeners to receive this event +*/ +void +DefaultNotificationService::Notify(const KMessage& event, uint32 flags) +{ + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if ((flags & listener->flags) != 0) + listener->listener->EventOccured(*this, &event); + } + + iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if ((flags & listener->flags) != 0) + listener->listener->AllListenersNotified(*this); + } +} + + +status_t +DefaultNotificationService::AddListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + if (eventSpecifier == NULL) + return B_BAD_VALUE; + + uint32 flags; + status_t status = _ToFlags(*eventSpecifier, flags); + if (status != B_OK) + return status; + + default_listener* listener = new(std::nothrow) default_listener; + if (listener == NULL) + return B_NO_MEMORY; + + listener->flags = flags; + listener->team = -1; + listener->listener = ¬ificationListener; + + RecursiveLocker _(fLock); + if (fListeners.IsEmpty()) + _FirstAdded(); + fListeners.Add(listener); + + return B_OK; +} + + +status_t +DefaultNotificationService::UpdateListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + return B_NOT_SUPPORTED; +} + + +status_t +DefaultNotificationService::RemoveListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (listener->listener == ¬ificationListener) { + iterator.Remove(); + delete listener; + + if (fListeners.IsEmpty()) + _LastRemoved(); + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DefaultNotificationService::_ToFlags(const KMessage& eventSpecifier, + uint32& flags) +{ + return eventSpecifier.FindInt32("flags", (int32*)&flags); +} + + +void +DefaultNotificationService::_FirstAdded() +{ +} + + +void +DefaultNotificationService::_LastRemoved() +{ +} + + +// #pragma mark - DefaultUserNotificationService + + +DefaultUserNotificationService::DefaultUserNotificationService(const char* name) + : DefaultNotificationService(name) +{ + NotificationManager::Manager().AddListener("teams", TEAM_REMOVED, *this); +} + + +DefaultUserNotificationService::~DefaultUserNotificationService() +{ + NotificationManager::Manager().RemoveListener("teams", NULL, *this); +} + + +status_t +DefaultUserNotificationService::AddListener(const KMessage* eventSpecifier, + NotificationListener& listener) +{ + if (eventSpecifier == NULL) + return B_BAD_VALUE; + + uint32 flags = eventSpecifier->GetInt32("flags", 0); + + return _AddListener(flags, listener); +} + + +status_t +DefaultUserNotificationService::UpdateListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + if (eventSpecifier == NULL) + return B_BAD_VALUE; + + uint32 flags = eventSpecifier->GetInt32("flags", 0); + bool addFlags = eventSpecifier->GetBool("add flags", false); + + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (*listener->listener == notificationListener) { + if (addFlags) + listener->flags |= flags; + else + listener->flags = flags; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DefaultUserNotificationService::RemoveListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (listener->listener == ¬ificationListener) { + iterator.Remove(); + delete listener; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DefaultUserNotificationService::RemoveUserListeners(port_id port, uint32 token) +{ + UserMessagingListener userListener(fSender, port, token); + + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (*listener->listener == userListener) { + iterator.Remove(); + delete listener; + + if (fListeners.IsEmpty()) + _LastRemoved(); + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DefaultUserNotificationService::UpdateUserListener(uint32 flags, port_id port, + uint32 token) +{ + UserMessagingListener userListener(fSender, port, token); + + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (*listener->listener == userListener) { + listener->flags |= flags; + return B_OK; + } + } + + UserMessagingListener* copiedListener + = new(std::nothrow) UserMessagingListener(userListener); + if (copiedListener == NULL) + return B_NO_MEMORY; + + status_t status = _AddListener(flags, *copiedListener); + if (status != B_OK) + delete copiedListener; + + return status; +} + + +void +DefaultUserNotificationService::EventOccured(NotificationService& service, + const KMessage* event) +{ + int32 opcode = event->GetInt32("opcode", -1); + team_id team = event->GetInt32("team", -1); + + if (opcode == TEAM_REMOVED && team >= B_OK) { + // check if we have any listeners from that team, and remove them + RecursiveLocker _(fLock); + + DefaultListenerList::Iterator iterator = fListeners.GetIterator(); + while (default_listener* listener = iterator.Next()) { + if (listener->team == team) { + iterator.Remove(); + delete listener; + } + } + } +} + + +void +DefaultUserNotificationService::AllListenersNotified( + NotificationService& service) +{ +} + + +status_t +DefaultUserNotificationService::_AddListener(uint32 flags, + NotificationListener& notificationListener) +{ + default_listener* listener = new(std::nothrow) default_listener; + if (listener == NULL) + return B_NO_MEMORY; + + listener->flags = flags; + listener->team = team_get_current_team_id(); + listener->listener = ¬ificationListener; + + RecursiveLocker _(fLock); + if (fListeners.IsEmpty()) + _FirstAdded(); + fListeners.Add(listener); + + return B_OK; +} + + // #pragma mark - NotificationManager diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index 48404b909b..7d9eec385c 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -130,6 +130,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU) boot_item_init(); driver_settings_init(&sKernelArgs); debug_init_post_vm(&sKernelArgs); + TRACE("init notification services\n"); + notifications_init(); TRACE("init teams\n"); team_init(&sKernelArgs); TRACE("init ELF loader\n"); @@ -180,8 +182,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU) TRACE("init VM threads\n"); vm_init_post_thread(&sKernelArgs); low_resource_manager_init_post_thread(); - TRACE("init notification services\n"); - notifications_init(); TRACE("init VFS\n"); vfs_init(&sKernelArgs); #if ENABLE_SWAP_SUPPORT diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index 328a7d5c3f..ca35f0af51 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001, Mark-Jan Bastian. All rights reserved. @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,16 @@ struct port_entry { struct list msg_queue; }; +class PortNotificationService : public DefaultNotificationService { +public: + PortNotificationService(); + + void Notify(uint32 opcode, port_id team); + +protected: + virtual status_t _ToFlags(const KMessage& eventSpecifier, + uint32& flags); +}; #define MAX_QUEUE_LENGTH 4096 #define PORT_MAX_MESSAGE_SIZE (256 * 1024) @@ -73,6 +84,8 @@ static bool sPortsActive = false; static port_id sNextPort = 1; static int32 sFirstFreeSlot = 1; +static PortNotificationService sNotificationService; + static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER; #define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock) @@ -81,6 +94,39 @@ static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER; #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock) +// #pragma mark - TeamNotificationService + + +PortNotificationService::PortNotificationService() + : DefaultNotificationService("ports") +{ +} + + +void +PortNotificationService::Notify(uint32 opcode, port_id port) +{ + char eventBuffer[64]; + KMessage event; + event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR); + event.AddInt32("opcode", opcode); + event.AddInt32("port", port); + + DefaultNotificationService::Notify(event, ~0U); +} + + +status_t +PortNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) +{ + flags = ~0U; + return B_OK; +} + + +// #pragma mark - + + static int dump_port_list(int argc, char **argv) { @@ -362,6 +408,7 @@ port_init(kernel_args *args) " - Name of the port.\n" " - ID of the port's read or write semaphore.\n", 0); + new(&sNotificationService) PortNotificationService(); sPortsActive = true; return B_OK; } @@ -380,7 +427,8 @@ create_port(int32 queueLength, const char *name) team_id owner; int32 slot; - TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, name)); + TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, + name)); if (!sPortsActive) return B_BAD_PORT_ID; @@ -463,13 +511,14 @@ create_port(int32 queueLength, const char *name) TRACE(("create_port() done: port created %ld\n", id)); + sNotificationService.Notify(PORT_ADDED, id); return id; } } // not enough ports... - // ToDo: due to sUsedPorts, this cannot happen anymore - as + // TODO: due to sUsedPorts, this cannot happen anymore - as // long as sMaxPorts stays constant over the kernel run // time (which it should be). IOW we could simply panic() // here. @@ -597,6 +646,7 @@ delete_port(port_id id) // read_port() will see the B_BAD_SEM_ID acq_sem() return value, and act accordingly delete_sem(readSem); delete_sem(writeSem); + sNotificationService.Notify(PORT_REMOVED, id); return B_OK; } diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index f1acc96e01..783e744e2e 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,17 @@ struct fork_arg { struct arch_fork_arg arch_info; }; +class TeamNotificationService : public DefaultNotificationService { +public: + TeamNotificationService(); + + void Notify(uint32 opcode, team_id team); + +protected: + virtual status_t _ToFlags(const KMessage& eventSpecifier, + uint32& flags); +}; + static hash_table *sTeamHash = NULL; static hash_table *sGroupHash = NULL; @@ -91,6 +103,8 @@ static struct team *sKernelTeam = NULL; static int32 sMaxTeams = 2048; static int32 sUsedTeams = 1; +static TeamNotificationService sNotificationService; + spinlock gTeamSpinlock = B_SPINLOCK_INITIALIZER; @@ -288,6 +302,35 @@ private: #endif +// #pragma mark - TeamNotificationService + + +TeamNotificationService::TeamNotificationService() + : DefaultNotificationService("teams") +{ +} + + +void +TeamNotificationService::Notify(uint32 opcode, team_id team) +{ + char eventBuffer[64]; + KMessage event; + event.SetTo(eventBuffer, sizeof(eventBuffer), TEAM_MONITOR); + event.AddInt32("opcode", opcode); + event.AddInt32("team", team); + + DefaultNotificationService::Notify(event, ~0U); +} + + +status_t +TeamNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) +{ + flags = ~0U; + return B_OK; +} + // #pragma mark - Private functions @@ -2020,7 +2063,10 @@ team_init(kernel_args *args) add_debugger_command_etc("teams", &dump_teams, "List all teams", "\n" "Prints a list of all existing teams.\n", 0); - return 0; + + new(&sNotificationService) TeamNotificationService(); + + return B_OK; } @@ -2374,6 +2420,8 @@ team_delete_team(struct team *team) } } + sNotificationService.Notify(TEAM_REMOVED, team->id); + // free team resources vfs_put_io_context(team->io_context);