* 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:
@@ -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<const UserMessagingListener*>(&_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<NotificationService>& Link() { return fLink; }
|
||||
virtual const char* Name() = 0;
|
||||
HashTableLink<NotificationService>&
|
||||
Link() { return fLink; }
|
||||
|
||||
private:
|
||||
HashTableLink<NotificationService> fLink;
|
||||
private:
|
||||
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 {
|
||||
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<NotificationService>* GetLink(
|
||||
NotificationService* service) const
|
||||
{ return &service->Link(); }
|
||||
};
|
||||
typedef OpenHashTable<HashDefinition> 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<NotificationService>* GetLink(
|
||||
NotificationService* service) const
|
||||
{ return &service->Link(); }
|
||||
};
|
||||
static NotificationManager sManager;
|
||||
|
||||
static NotificationManager sManager;
|
||||
|
||||
mutex fLock;
|
||||
typedef OpenHashTable<HashDefinition> ServiceHash;
|
||||
ServiceHash fServiceHash;
|
||||
mutex fLock;
|
||||
ServiceHash fServiceHash;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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 <thread_types.h>
|
||||
|
||||
|
||||
// Team notifications
|
||||
#define TEAM_MONITOR '_Tm_'
|
||||
#define TEAM_ADDED 1
|
||||
#define TEAM_REMOVED 2
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -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> {
|
||||
~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 {
|
||||
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<UserNetListener*>(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<UserNetListener*>(¬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;
|
||||
|
||||
|
||||
@@ -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 <Notifications.h>
|
||||
|
||||
#include <team.h>
|
||||
|
||||
|
||||
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<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 = ¬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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <arch/int.h>
|
||||
#include <cbuf.h>
|
||||
#include <kernel.h>
|
||||
#include <Notifications.h>
|
||||
#include <sem.h>
|
||||
#include <syscall_restart.h>
|
||||
#include <team.h>
|
||||
@@ -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> - Name of the port.\n"
|
||||
" <sem> - 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;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <kimage.h>
|
||||
#include <kscheduler.h>
|
||||
#include <ksignal.h>
|
||||
#include <Notifications.h>
|
||||
#include <port.h>
|
||||
#include <posix/realtime_sem.h>
|
||||
#include <posix/xsi_semaphore.h>
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user