* Added DefaultNotificationService and DefaultUserNotificationService

implementations that can be used by subsystems that want to have a pretty
  standard service. Only the latter is really complete, though.
* The notification manager is now available earlier in the boot process.
* Added notifications to teams/ports (only add/remove).
* The network notification implementation is now using the
  DefaultUserNotificationService.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29543 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-03-15 10:21:56 +00:00
parent d60fa63b38
commit 51755cf832
8 changed files with 632 additions and 319 deletions
+174 -85
View File
@@ -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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -29,124 +29,213 @@
class NotificationService; class NotificationService;
class NotificationListener { class NotificationListener {
public: public:
virtual ~NotificationListener(); virtual ~NotificationListener();
virtual void EventOccured(NotificationService& service, virtual void EventOccured(NotificationService& service,
const KMessage* event); const KMessage* event);
virtual void AllListenersNotified(NotificationService& service); 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 bool operator!=(
{ return !(*this == other); } const NotificationListener& other) const
{ return !(*this == other); }
}; };
class UserMessagingMessageSender { class UserMessagingMessageSender {
public: public:
UserMessagingMessageSender(); UserMessagingMessageSender();
void SendMessage(const KMessage* message, port_id port, int32 token); void SendMessage(const KMessage* message,
void FlushMessage(); port_id port, int32 token);
void FlushMessage();
private: private:
enum { enum {
MAX_MESSAGING_TARGET_COUNT = 16, MAX_MESSAGING_TARGET_COUNT = 16,
}; };
const KMessage* fMessage; const KMessage* fMessage;
messaging_target fTargets[MAX_MESSAGING_TARGET_COUNT]; messaging_target fTargets[MAX_MESSAGING_TARGET_COUNT];
int32 fTargetCount; int32 fTargetCount;
}; };
class UserMessagingListener : public NotificationListener { class UserMessagingListener : public NotificationListener {
public: public:
UserMessagingListener(UserMessagingMessageSender& sender, port_id port, UserMessagingListener(
int32 token); UserMessagingMessageSender& sender,
virtual ~UserMessagingListener(); port_id port, int32 token);
virtual ~UserMessagingListener();
virtual void EventOccured(NotificationService& service, virtual void EventOccured(NotificationService& service,
const KMessage* event); const KMessage* event);
virtual void AllListenersNotified(NotificationService& service); virtual void AllListenersNotified(
NotificationService& service);
port_id Port() const { return fPort; } port_id Port() const { return fPort; }
int32 Token() const { return fToken; } int32 Token() const { return fToken; }
private: bool operator==(
UserMessagingMessageSender& fSender; const NotificationListener& _other) const;
port_id fPort;
int32 fToken; private:
UserMessagingMessageSender& fSender;
port_id fPort;
int32 fToken;
}; };
inline bool
UserMessagingListener::operator==(const NotificationListener& _other) const
{
const UserMessagingListener* other
= dynamic_cast<const UserMessagingListener*>(&_other);
return other != NULL && other->Port() == Port()
&& other->Token() == Token();
}
class NotificationService : public Referenceable { class NotificationService : public Referenceable {
public: public:
virtual ~NotificationService(); virtual ~NotificationService();
virtual status_t AddListener(const KMessage* eventSpecifier, virtual status_t AddListener(const KMessage* eventSpecifier,
NotificationListener& listener) = 0; NotificationListener& listener) = 0;
virtual status_t RemoveListener(const KMessage* eventSpecifier, virtual status_t RemoveListener(const KMessage* eventSpecifier,
NotificationListener& listener) = 0; NotificationListener& listener) = 0;
virtual status_t UpdateListener(const KMessage* eventSpecifier, virtual status_t UpdateListener(const KMessage* eventSpecifier,
NotificationListener& listener) = 0; NotificationListener& listener) = 0;
virtual const char* Name() = 0; virtual const char* Name() = 0;
HashTableLink<NotificationService>& Link() { return fLink; } HashTableLink<NotificationService>&
Link() { return fLink; }
private: private:
HashTableLink<NotificationService> fLink; HashTableLink<NotificationService> fLink;
};
struct default_listener : public DoublyLinkedListLinkImpl<default_listener> {
~default_listener();
uint32 flags;
team_id team;
NotificationListener* listener;
};
typedef DoublyLinkedList<default_listener> 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 { class NotificationManager {
public: public:
static NotificationManager& Manager(); static NotificationManager& Manager();
static status_t CreateManager(); static status_t CreateManager();
status_t RegisterService(NotificationService& service); status_t RegisterService(NotificationService& service);
void UnregisterService(NotificationService& service); void UnregisterService(
NotificationService& service);
NotificationService* GetService(const char* name); status_t AddListener(const char* service,
void PutService(NotificationService* service); uint32 eventMask,
NotificationListener& listener);
status_t AddListener(const char* service,
const KMessage* eventSpecifier,
NotificationListener& listener);
status_t AddListener(const char* service, uint32 eventMask, status_t UpdateListener(const char* service,
NotificationListener& listener); uint32 eventMask,
status_t AddListener(const char* service, NotificationListener& listener);
const KMessage* eventSpecifier, NotificationListener& listener); status_t UpdateListener(const char* service,
const KMessage* eventSpecifier,
NotificationListener& listener);
status_t UpdateListener(const char* service, status_t RemoveListener(const char* service,
uint32 eventMask, NotificationListener& listener); const KMessage* eventSpecifier,
status_t UpdateListener(const char* service, NotificationListener& listener);
const KMessage* eventSpecifier, NotificationListener& listener);
status_t RemoveListener(const char* service, private:
const KMessage* eventSpecifier, NotificationListener& listener); NotificationManager();
~NotificationManager();
private: status_t _Init();
NotificationManager(); NotificationService* _ServiceFor(const char* name);
~NotificationManager();
status_t _Init(); struct HashDefinition {
NotificationService* _ServiceFor(const char* name); typedef const char* KeyType;
typedef NotificationService ValueType;
struct HashDefinition { size_t HashKey(const char* key) const
typedef const char* KeyType; { return hash_hash_string(key); }
typedef NotificationService ValueType; 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<NotificationService>* GetLink(
NotificationService* service) const
{ return &service->Link(); }
};
typedef OpenHashTable<HashDefinition> ServiceHash;
size_t HashKey(const char* key) const static NotificationManager sManager;
{ 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<NotificationService>* GetLink(
NotificationService* service) const
{ return &service->Link(); }
};
static NotificationManager sManager; mutex fLock;
ServiceHash fServiceHash;
mutex fLock;
typedef OpenHashTable<HashDefinition> ServiceHash;
ServiceHash fServiceHash;
}; };
extern "C" { extern "C" {
+5 -1
View File
@@ -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. * Distributed under the terms of the MIT license.
*/ */
#ifndef _KERNEL_PORT_H #ifndef _KERNEL_PORT_H
@@ -22,6 +22,10 @@ enum {
// kernel-only; memory must be locked // kernel-only; memory must be locked
}; };
// port notifications
#define PORT_MONITOR '_Pm_'
#define PORT_ADDED 1
#define PORT_REMOVED 2
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
+7 -1
View File
@@ -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. * Distributed under the terms of the MIT License.
*/ */
#ifndef _TEAM_H #ifndef _TEAM_H
@@ -9,6 +9,12 @@
#include <thread_types.h> #include <thread_types.h>
// Team notifications
#define TEAM_MONITOR '_Tm_'
#define TEAM_ADDED 1
#define TEAM_REMOVED 2
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -18,95 +18,38 @@
# define TRACE(x...) ; # define TRACE(x...) ;
#endif #endif
// TODO: add possibility to remove teams/ports that are gone
class NetNotificationService : public DefaultUserNotificationService {
static UserMessagingMessageSender sNotificationSender;
struct net_listener : public DoublyLinkedListLinkImpl<net_listener> {
~net_listener();
uint32 flags;
NotificationListener* listener;
};
typedef DoublyLinkedList<net_listener> 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<const UserNetListener*>(&_other);
return other != NULL && other->Port() == Port()
&& other->Token() == Token();
}
};
class NetNotificationService : public NotificationService {
public: public:
NetNotificationService(); NetNotificationService();
virtual ~NetNotificationService(); virtual ~NetNotificationService();
void Notify(const KMessage& event); void Notify(const KMessage& event);
status_t AddListener(const KMessage* eventSpecifier, protected:
NotificationListener& listener); virtual status_t _ToFlags(const KMessage& eventSpecifier,
status_t UpdateListener(const KMessage* eventSpecifier, uint32& flags);
NotificationListener& listener); virtual void _FirstAdded();
status_t RemoveListener(const KMessage* eventSpecifier, virtual void _LastRemoved();
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;
}; };
static NetNotificationService sNotificationService; static NetNotificationService sNotificationService;
net_listener::~net_listener()
{
// Only delete the listener if it's one of ours
if (dynamic_cast<UserNetListener*>(listener) != NULL) {
TRACE("delete user listener %p\n", listener);
delete listener;
}
}
// #pragma mark - NetNotificationService // #pragma mark - NetNotificationService
NetNotificationService::NetNotificationService() NetNotificationService::NetNotificationService()
: DefaultUserNotificationService("network")
{ {
recursive_lock_init(&fRecursiveLock, "net notifications");
} }
NetNotificationService::~NetNotificationService() NetNotificationService::~NetNotificationService()
{ {
recursive_lock_destroy(&fRecursiveLock);
} }
/*! \brief Notifies all registered listeners.
\param event The message defining the event
*/
void void
NetNotificationService::Notify(const KMessage& event) NetNotificationService::Notify(const KMessage& event)
{ {
@@ -116,173 +59,36 @@ NetNotificationService::Notify(const KMessage& event)
TRACE("notify for %lx\n", opcode); TRACE("notify for %lx\n", opcode);
RecursiveLocker _(fRecursiveLock); DefaultUserNotificationService::Notify(event, opcode);
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);
}
} }
status_t status_t
NetNotificationService::AddListener(const KMessage* eventSpecifier, NetNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags)
NotificationListener& listener)
{ {
if (eventSpecifier == NULL) flags = eventSpecifier.GetInt32("flags", 0);
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 == &notificationListener) {
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<UserNetListener*>(&notificationListener) != NULL
? "user " : "", listener, flags);
listener->flags = flags;
listener->listener = &notificationListener;
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);
return B_OK; 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 // #pragma mark - User generic syscall
@@ -326,7 +132,6 @@ notifications_std_ops(int32 op, ...)
case B_MODULE_INIT: case B_MODULE_INIT:
TRACE("init\n"); TRACE("init\n");
new(&sNotificationSender) UserMessagingMessageSender();
new(&sNotificationService) NetNotificationService(); new(&sNotificationService) NetNotificationService();
register_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, register_generic_syscall(NET_NOTIFICATIONS_SYSCALLS,
@@ -338,7 +143,6 @@ notifications_std_ops(int32 op, ...)
unregister_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, 1); unregister_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, 1);
sNotificationSender.~UserMessagingMessageSender();
sNotificationService.~NetNotificationService(); sNotificationService.~NetNotificationService();
return B_OK; return B_OK;
+314 -2
View File
@@ -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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -10,11 +10,13 @@
#include <Notifications.h> #include <Notifications.h>
#include <team.h>
NotificationManager NotificationManager::sManager; NotificationManager NotificationManager::sManager;
// #pragma mark - UserMessagingListener // #pragma mark - NotificationListener
NotificationListener::~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<UserMessagingListener*>(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 = &notificationListener;
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 == &notificationListener) {
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 == &notificationListener) {
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 = &notificationListener;
RecursiveLocker _(fLock);
if (fListeners.IsEmpty())
_FirstAdded();
fListeners.Add(listener);
return B_OK;
}
// #pragma mark - NotificationManager // #pragma mark - NotificationManager
+2 -2
View File
@@ -130,6 +130,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
boot_item_init(); boot_item_init();
driver_settings_init(&sKernelArgs); driver_settings_init(&sKernelArgs);
debug_init_post_vm(&sKernelArgs); debug_init_post_vm(&sKernelArgs);
TRACE("init notification services\n");
notifications_init();
TRACE("init teams\n"); TRACE("init teams\n");
team_init(&sKernelArgs); team_init(&sKernelArgs);
TRACE("init ELF loader\n"); TRACE("init ELF loader\n");
@@ -180,8 +182,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
TRACE("init VM threads\n"); TRACE("init VM threads\n");
vm_init_post_thread(&sKernelArgs); vm_init_post_thread(&sKernelArgs);
low_resource_manager_init_post_thread(); low_resource_manager_init_post_thread();
TRACE("init notification services\n");
notifications_init();
TRACE("init VFS\n"); TRACE("init VFS\n");
vfs_init(&sKernelArgs); vfs_init(&sKernelArgs);
#if ENABLE_SWAP_SUPPORT #if ENABLE_SWAP_SUPPORT
+53 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2007, Axel Dörfler, [email protected]. * Copyright 2002-2009, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Copyright 2001, Mark-Jan Bastian. All rights reserved. * Copyright 2001, Mark-Jan Bastian. All rights reserved.
@@ -20,6 +20,7 @@
#include <arch/int.h> #include <arch/int.h>
#include <cbuf.h> #include <cbuf.h>
#include <kernel.h> #include <kernel.h>
#include <Notifications.h>
#include <sem.h> #include <sem.h>
#include <syscall_restart.h> #include <syscall_restart.h>
#include <team.h> #include <team.h>
@@ -59,6 +60,16 @@ struct port_entry {
struct list msg_queue; 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 MAX_QUEUE_LENGTH 4096
#define PORT_MAX_MESSAGE_SIZE (256 * 1024) #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
@@ -73,6 +84,8 @@ static bool sPortsActive = false;
static port_id sNextPort = 1; static port_id sNextPort = 1;
static int32 sFirstFreeSlot = 1; static int32 sFirstFreeSlot = 1;
static PortNotificationService sNotificationService;
static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER; static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER;
#define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock) #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) #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 static int
dump_port_list(int argc, char **argv) dump_port_list(int argc, char **argv)
{ {
@@ -362,6 +408,7 @@ port_init(kernel_args *args)
" <name> - Name of the port.\n" " <name> - Name of the port.\n"
" <sem> - ID of the port's read or write semaphore.\n", 0); " <sem> - ID of the port's read or write semaphore.\n", 0);
new(&sNotificationService) PortNotificationService();
sPortsActive = true; sPortsActive = true;
return B_OK; return B_OK;
} }
@@ -380,7 +427,8 @@ create_port(int32 queueLength, const char *name)
team_id owner; team_id owner;
int32 slot; int32 slot;
TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, name)); TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
name));
if (!sPortsActive) if (!sPortsActive)
return B_BAD_PORT_ID; 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)); TRACE(("create_port() done: port created %ld\n", id));
sNotificationService.Notify(PORT_ADDED, id);
return id; return id;
} }
} }
// not enough ports... // 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 // long as sMaxPorts stays constant over the kernel run
// time (which it should be). IOW we could simply panic() // time (which it should be). IOW we could simply panic()
// here. // 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 // read_port() will see the B_BAD_SEM_ID acq_sem() return value, and act accordingly
delete_sem(readSem); delete_sem(readSem);
delete_sem(writeSem); delete_sem(writeSem);
sNotificationService.Notify(PORT_REMOVED, id);
return B_OK; return B_OK;
} }
+49 -1
View File
@@ -29,6 +29,7 @@
#include <kimage.h> #include <kimage.h>
#include <kscheduler.h> #include <kscheduler.h>
#include <ksignal.h> #include <ksignal.h>
#include <Notifications.h>
#include <port.h> #include <port.h>
#include <posix/realtime_sem.h> #include <posix/realtime_sem.h>
#include <posix/xsi_semaphore.h> #include <posix/xsi_semaphore.h>
@@ -81,6 +82,17 @@ struct fork_arg {
struct arch_fork_arg arch_info; 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 *sTeamHash = NULL;
static hash_table *sGroupHash = NULL; static hash_table *sGroupHash = NULL;
@@ -91,6 +103,8 @@ static struct team *sKernelTeam = NULL;
static int32 sMaxTeams = 2048; static int32 sMaxTeams = 2048;
static int32 sUsedTeams = 1; static int32 sUsedTeams = 1;
static TeamNotificationService sNotificationService;
spinlock gTeamSpinlock = B_SPINLOCK_INITIALIZER; spinlock gTeamSpinlock = B_SPINLOCK_INITIALIZER;
@@ -288,6 +302,35 @@ private:
#endif #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 // #pragma mark - Private functions
@@ -2020,7 +2063,10 @@ team_init(kernel_args *args)
add_debugger_command_etc("teams", &dump_teams, "List all teams", add_debugger_command_etc("teams", &dump_teams, "List all teams",
"\n" "\n"
"Prints a list of all existing teams.\n", 0); "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 // free team resources
vfs_put_io_context(team->io_context); vfs_put_io_context(team->io_context);