bonefish+axeld: Implemented a robust notification framework for the kernel.
Will be used for node monitoring and other stuff, too (like the Registrar or the VM low memory handler). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21768 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
* Ingo Weinhold, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef _KERNEL_NOTIFICATIONS_H
|
||||||
|
#define _KERNEL_NOTIFICATIONS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
#include <lock.h>
|
||||||
|
#include <messaging.h>
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/khash.h>
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
class NotificationService;
|
||||||
|
|
||||||
|
class NotificationListener
|
||||||
|
: public DoublyLinkedListLinkImpl<NotificationListener> {
|
||||||
|
public:
|
||||||
|
virtual ~NotificationListener();
|
||||||
|
|
||||||
|
virtual void EventOccured(NotificationService& service,
|
||||||
|
const KMessage* event);
|
||||||
|
virtual void AllListenersNotified();
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserMessagingMessageSender {
|
||||||
|
public:
|
||||||
|
UserMessagingMessageSender();
|
||||||
|
|
||||||
|
void SendMessage(const KMessage* message, port_id port, int32 token);
|
||||||
|
void FlushMessage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
MAX_MESSAGING_TARGET_COUNT = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
virtual void EventOccured(NotificationService& service,
|
||||||
|
const KMessage* event);
|
||||||
|
virtual void AllListenersNotified();
|
||||||
|
|
||||||
|
port_id Port() { return fPort; }
|
||||||
|
int32 Token() { return fToken; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
UserMessagingMessageSender& fSender;
|
||||||
|
port_id fPort;
|
||||||
|
int32 fToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotificationListenerUpdater {
|
||||||
|
public:
|
||||||
|
enum update_action {
|
||||||
|
UPDATED,
|
||||||
|
SKIP,
|
||||||
|
DELETE,
|
||||||
|
REMOVE
|
||||||
|
};
|
||||||
|
|
||||||
|
NotificationListenerUpdater(const KMessage* eventSpecifier);
|
||||||
|
virtual ~NotificationListenerUpdater();
|
||||||
|
|
||||||
|
virtual status_t UpdateListener(NotificationListener& listener,
|
||||||
|
enum update_action& action);
|
||||||
|
|
||||||
|
virtual status_t CreateListener(NotificationListener** _listener);
|
||||||
|
|
||||||
|
virtual void SetEventSpecifier(const KMessage* eventSpecifier);
|
||||||
|
const KMessage* EventSpecifier() const { return fEventSpecifier; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const KMessage* fEventSpecifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserMessagingListenerUpdater : public NotificationListenerUpdater {
|
||||||
|
public:
|
||||||
|
UserMessagingListenerUpdater(const KMessage* eventSpecifier, port_id port,
|
||||||
|
int32 token);
|
||||||
|
|
||||||
|
virtual status_t UpdateListener(NotificationListener& listener,
|
||||||
|
enum update_action& action);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual status_t UpdateListener(UserMessagingListener& listener,
|
||||||
|
enum update_action& action) = 0;
|
||||||
|
|
||||||
|
port_id fPort;
|
||||||
|
int32 fToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotificationService : public Referenceable {
|
||||||
|
public:
|
||||||
|
virtual ~NotificationService() = 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(NotificationListenerUpdater& updater) = 0;
|
||||||
|
|
||||||
|
virtual const char* Name() = 0;
|
||||||
|
HashTableLink<NotificationService>& Link() { return fLink; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashTableLink<NotificationService> fLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotificationManager {
|
||||||
|
public:
|
||||||
|
static NotificationManager& Manager();
|
||||||
|
static status_t CreateManager();
|
||||||
|
|
||||||
|
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 RemoveListener(const char* service, uint32 eventMask,
|
||||||
|
NotificationListener& listener);
|
||||||
|
status_t RemoveListener(const char* service,
|
||||||
|
const KMessage* eventSpecifier, NotificationListener& listener);
|
||||||
|
|
||||||
|
status_t UpdateListener(const char* service,
|
||||||
|
NotificationListenerUpdater& updater);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotificationManager();
|
||||||
|
~NotificationManager();
|
||||||
|
|
||||||
|
status_t _Init();
|
||||||
|
NotificationService* _ServiceFor(const char* name);
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static NotificationManager sManager;
|
||||||
|
|
||||||
|
mutex fLock;
|
||||||
|
typedef OpenHashTable<HashDefinition> ServiceHash;
|
||||||
|
ServiceHash fServiceHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
void notifications_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // _KERNEL_NOTIFICATIONS_H
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
* Ingo Weinhold, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <Notifications.h>
|
||||||
|
|
||||||
|
|
||||||
|
NotificationManager NotificationManager::sManager;
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserMessagingListener
|
||||||
|
|
||||||
|
|
||||||
|
NotificationListener::~NotificationListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationListener::EventOccured(NotificationService& service,
|
||||||
|
const KMessage* event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationListener::AllListenersNotified()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserMessagingMessageSender
|
||||||
|
|
||||||
|
|
||||||
|
UserMessagingMessageSender::UserMessagingMessageSender()
|
||||||
|
:
|
||||||
|
fMessage(NULL),
|
||||||
|
fTargetCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserMessagingMessageSender::SendMessage(const KMessage* message, port_id port,
|
||||||
|
int32 token)
|
||||||
|
{
|
||||||
|
if (message != fMessage && fMessage != NULL
|
||||||
|
|| fTargetCount == MAX_MESSAGING_TARGET_COUNT) {
|
||||||
|
FlushMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
fMessage = message;
|
||||||
|
fTargets[fTargetCount].port = port;
|
||||||
|
fTargets[fTargetCount].token = token;
|
||||||
|
fTargetCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserMessagingMessageSender::FlushMessage()
|
||||||
|
{
|
||||||
|
if (fMessage != NULL && fTargetCount > 0) {
|
||||||
|
send_message(fMessage->Buffer(), fMessage->ContentSize(),
|
||||||
|
fTargets, fTargetCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
fMessage = NULL;
|
||||||
|
fTargetCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserMessagingListener
|
||||||
|
|
||||||
|
|
||||||
|
UserMessagingListener::UserMessagingListener(UserMessagingMessageSender& sender,
|
||||||
|
port_id port, int32 token)
|
||||||
|
:
|
||||||
|
fSender(sender),
|
||||||
|
fPort(port),
|
||||||
|
fToken(token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UserMessagingListener::~UserMessagingListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserMessagingListener::EventOccured(NotificationService& service,
|
||||||
|
const KMessage* event)
|
||||||
|
{
|
||||||
|
fSender.SendMessage(event, fPort, fToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserMessagingListener::AllListenersNotified()
|
||||||
|
{
|
||||||
|
fSender.FlushMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NotificationListenerUpdater
|
||||||
|
|
||||||
|
|
||||||
|
NotificationListenerUpdater::NotificationListenerUpdater(
|
||||||
|
const KMessage* eventSpecifier)
|
||||||
|
: fEventSpecifier(eventSpecifier)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotificationListenerUpdater::~NotificationListenerUpdater()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationListenerUpdater::UpdateListener(NotificationListener& listener,
|
||||||
|
enum update_action& action)
|
||||||
|
{
|
||||||
|
action = SKIP;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationListenerUpdater::CreateListener(NotificationListener** _listener)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationListenerUpdater::SetEventSpecifier(const KMessage* eventSpecifier)
|
||||||
|
{
|
||||||
|
fEventSpecifier = eventSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NotificationListenerUpdater
|
||||||
|
|
||||||
|
|
||||||
|
UserMessagingListenerUpdater::UserMessagingListenerUpdater(
|
||||||
|
const KMessage* eventSpecifier, port_id port, int32 token)
|
||||||
|
:
|
||||||
|
NotificationListenerUpdater(eventSpecifier),
|
||||||
|
fPort(port),
|
||||||
|
fToken(token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UserMessagingListenerUpdater::UpdateListener(NotificationListener& _listener,
|
||||||
|
enum update_action& action)
|
||||||
|
{
|
||||||
|
UserMessagingListener* listener
|
||||||
|
= dynamic_cast<UserMessagingListener*>(&_listener);
|
||||||
|
if (listener != NULL && listener->Port() == fPort
|
||||||
|
&& listener->Token() == fToken) {
|
||||||
|
return UpdateListener(*listener, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
action = SKIP;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NotificationManager
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
NotificationService::~NotificationService()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NotificationManager
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ NotificationManager&
|
||||||
|
NotificationManager::Manager()
|
||||||
|
{
|
||||||
|
return sManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ status_t
|
||||||
|
NotificationManager::CreateManager()
|
||||||
|
{
|
||||||
|
new(&sManager) NotificationManager;
|
||||||
|
return sManager._Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotificationManager::NotificationManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotificationManager::~NotificationManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::_Init()
|
||||||
|
{
|
||||||
|
status_t status = mutex_init(&fLock, "notification manager");
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
return fServiceHash.InitCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotificationService*
|
||||||
|
NotificationManager::_ServiceFor(const char* name)
|
||||||
|
{
|
||||||
|
return fServiceHash.Lookup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::RegisterService(NotificationService& service)
|
||||||
|
{
|
||||||
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
|
if (_ServiceFor(service.Name()))
|
||||||
|
return B_NAME_IN_USE;
|
||||||
|
|
||||||
|
status_t status = fServiceHash.Insert(&service);
|
||||||
|
if (status == B_OK)
|
||||||
|
service.AddReference();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationManager::UnregisterService(NotificationService& service)
|
||||||
|
{
|
||||||
|
MutexLocker _(fLock);
|
||||||
|
fServiceHash.Remove(&service);
|
||||||
|
service.RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::AddListener(const char* serviceName,
|
||||||
|
uint32 eventMask, NotificationListener& listener)
|
||||||
|
{
|
||||||
|
char buffer[96];
|
||||||
|
KMessage specifier;
|
||||||
|
specifier.SetTo(buffer, sizeof(buffer), 0);
|
||||||
|
specifier.AddInt32("event mask", eventMask);
|
||||||
|
|
||||||
|
return AddListener(serviceName, &specifier, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::AddListener(const char* serviceName,
|
||||||
|
const KMessage* eventSpecifier, NotificationListener& listener)
|
||||||
|
{
|
||||||
|
MutexLocker locker(fLock);
|
||||||
|
NotificationService* service = _ServiceFor(serviceName);
|
||||||
|
if (service == NULL)
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
Reference<NotificationService> reference(service);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
return service->AddListener(eventSpecifier, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::RemoveListener(const char* serviceName, uint32 eventMask,
|
||||||
|
NotificationListener& listener)
|
||||||
|
{
|
||||||
|
char buffer[96];
|
||||||
|
KMessage specifier;
|
||||||
|
specifier.SetTo(buffer, sizeof(buffer), 0);
|
||||||
|
specifier.AddInt32("event mask", eventMask);
|
||||||
|
|
||||||
|
return RemoveListener(serviceName, &specifier, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::RemoveListener(const char* serviceName,
|
||||||
|
const KMessage* eventSpecifier, NotificationListener& listener)
|
||||||
|
{
|
||||||
|
MutexLocker locker(fLock);
|
||||||
|
NotificationService* service = _ServiceFor(serviceName);
|
||||||
|
if (service == NULL)
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
Reference<NotificationService> reference(service);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
return service->RemoveListener(eventSpecifier, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotificationManager::UpdateListener(const char* serviceName,
|
||||||
|
NotificationListenerUpdater& updater)
|
||||||
|
{
|
||||||
|
MutexLocker locker(fLock);
|
||||||
|
NotificationService* service = _ServiceFor(serviceName);
|
||||||
|
if (service == NULL)
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
Reference<NotificationService> reference(service);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
return service->UpdateListener(updater);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
notifications_init(void)
|
||||||
|
{
|
||||||
|
status_t status = NotificationManager::CreateDefault();
|
||||||
|
if (status < B_OK) {
|
||||||
|
panic("Creating the notification manager failed: %s\n",
|
||||||
|
strerror(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -132,3 +132,13 @@ KernelMergeObject kernel_posix_arch_$(TARGET_ARCH).o :
|
|||||||
|
|
||||||
: $(TARGET_KERNEL_PIC_CCFLAGS)
|
: $(TARGET_KERNEL_PIC_CCFLAGS)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
UsePrivateHeaders shared ;
|
||||||
|
|
||||||
|
SEARCH_SOURCE = [ FDirName $(HAIKU_TOP) src kits support ] ;
|
||||||
|
|
||||||
|
KernelMergeObject kernel_misc.o :
|
||||||
|
Referenceable.cpp
|
||||||
|
|
||||||
|
: $(TARGET_KERNEL_PIC_CCFLAGS)
|
||||||
|
;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <kscheduler.h>
|
#include <kscheduler.h>
|
||||||
#include <ksyscalls.h>
|
#include <ksyscalls.h>
|
||||||
#include <messaging.h>
|
#include <messaging.h>
|
||||||
|
#include <Notifications.h>
|
||||||
#include <port.h>
|
#include <port.h>
|
||||||
#include <real_time_clock.h>
|
#include <real_time_clock.h>
|
||||||
#include <sem.h>
|
#include <sem.h>
|
||||||
@@ -156,6 +157,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
|
|||||||
elf_init(&sKernelArgs);
|
elf_init(&sKernelArgs);
|
||||||
TRACE("init scheduler\n");
|
TRACE("init scheduler\n");
|
||||||
scheduler_init();
|
scheduler_init();
|
||||||
|
TRACE("init notification services\n");
|
||||||
|
notifications_init();
|
||||||
TRACE("init VFS\n");
|
TRACE("init VFS\n");
|
||||||
vfs_init(&sKernelArgs);
|
vfs_init(&sKernelArgs);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user