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:
Axel Dörfler 2007-07-31 16:23:40 +00:00
parent 2851dbad53
commit bec0386d82
4 changed files with 553 additions and 0 deletions

View File

@ -0,0 +1,196 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Ingo Weinhold, bonefish@cs.tu-berlin.de
*/
#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

View File

@ -0,0 +1,344 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Ingo Weinhold, bonefish@cs.tu-berlin.de
*/
#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));
}
}

View File

@ -132,3 +132,13 @@ KernelMergeObject kernel_posix_arch_$(TARGET_ARCH).o :
: $(TARGET_KERNEL_PIC_CCFLAGS)
;
UsePrivateHeaders shared ;
SEARCH_SOURCE = [ FDirName $(HAIKU_TOP) src kits support ] ;
KernelMergeObject kernel_misc.o :
Referenceable.cpp
: $(TARGET_KERNEL_PIC_CCFLAGS)
;

View File

@ -26,6 +26,7 @@
#include <kscheduler.h>
#include <ksyscalls.h>
#include <messaging.h>
#include <Notifications.h>
#include <port.h>
#include <real_time_clock.h>
#include <sem.h>
@ -156,6 +157,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
elf_init(&sKernelArgs);
TRACE("init scheduler\n");
scheduler_init();
TRACE("init notification services\n");
notifications_init();
TRACE("init VFS\n");
vfs_init(&sKernelArgs);