From bec0386d8215cd1c8538d004322f275e05ad3bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 31 Jul 2007 16:23:40 +0000 Subject: [PATCH] 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 --- headers/private/kernel/Notifications.h | 196 ++++++++++++++ src/system/kernel/Notifications.cpp | 344 +++++++++++++++++++++++++ src/system/kernel/lib/Jamfile | 10 + src/system/kernel/main.c | 3 + 4 files changed, 553 insertions(+) create mode 100644 headers/private/kernel/Notifications.h create mode 100644 src/system/kernel/Notifications.cpp diff --git a/headers/private/kernel/Notifications.h b/headers/private/kernel/Notifications.h new file mode 100644 index 0000000000..f88e3357e8 --- /dev/null +++ b/headers/private/kernel/Notifications.h @@ -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 + +#include + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus + +class NotificationService; + +class NotificationListener + : public DoublyLinkedListLinkImpl { + 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& Link() { return fLink; } + + private: + HashTableLink 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* GetLink( + NotificationService* service) const + { return &service->Link(); } + }; + + static NotificationManager sManager; + + mutex fLock; + typedef OpenHashTable ServiceHash; + ServiceHash fServiceHash; +}; + +extern "C" { + +#endif // __cplusplus + +void notifications_init(void); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // _KERNEL_NOTIFICATIONS_H diff --git a/src/system/kernel/Notifications.cpp b/src/system/kernel/Notifications.cpp new file mode 100644 index 0000000000..0e2f1d8b8a --- /dev/null +++ b/src/system/kernel/Notifications.cpp @@ -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 + + +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(&_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 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 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 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)); + } +} + diff --git a/src/system/kernel/lib/Jamfile b/src/system/kernel/lib/Jamfile index 017c47b6f0..cf7dd1eb96 100644 --- a/src/system/kernel/lib/Jamfile +++ b/src/system/kernel/lib/Jamfile @@ -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) +; diff --git a/src/system/kernel/main.c b/src/system/kernel/main.c index ed87d6ec73..5a6e2f8570 100644 --- a/src/system/kernel/main.c +++ b/src/system/kernel/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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);