[haiku-commits] r39862 - in haiku/trunk: headers/private/kernel headers/private/system src/system/kernel src/system/libroot/os

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 16 Dec 2010 02:49:53 +0100 (CET)

Author: bonefish
Date: 2010-12-16 02:49:52 +0100 (Thu, 16 Dec 2010)
New Revision: 39862
Changeset: http://dev.haiku-os.org/changeset/39862

Modified:
   haiku/trunk/headers/private/kernel/ksystem_info.h
   haiku/trunk/headers/private/system/syscalls.h
   haiku/trunk/headers/private/system/system_info.h
   haiku/trunk/src/system/kernel/main.cpp
   haiku/trunk/src/system/kernel/system_info.cpp
   haiku/trunk/src/system/libroot/os/system_info.c
Log:
Implemented a generic system watching mechanism with a userland API. Currently
only a few events can be watched (team creation/deletion/exec, thread creation/
deletion/name changes). The functions start_system_watching()/
stop_system_watching start/stop watching events.


Modified: haiku/trunk/headers/private/kernel/ksystem_info.h
===================================================================
--- haiku/trunk/headers/private/kernel/ksystem_info.h   2010-12-16 01:44:15 UTC 
(rev 39861)
+++ haiku/trunk/headers/private/kernel/ksystem_info.h   2010-12-16 01:49:52 UTC 
(rev 39862)
@@ -8,6 +8,7 @@
 
 #include <OS.h>
 
+
 struct kernel_args;
 
 
@@ -15,15 +16,24 @@
 extern "C" {
 #endif
 
-extern status_t system_info_init(struct kernel_args *args);
-extern uint32 get_haiku_revision(void);
 
-extern status_t _user_get_system_info(system_info *userInfo, size_t size);
-extern status_t _user_get_system_info_etc(int32 id, void *buffer,
-       size_t bufferSize);
+status_t system_info_init(struct kernel_args *args);
+status_t system_notifications_init();
+uint32 get_haiku_revision(void);
 
+status_t _user_get_system_info(system_info *userInfo, size_t size);
+status_t _user_get_system_info_etc(int32 id, void *buffer,
+                       size_t bufferSize);
+
+status_t _user_start_system_watching(int32 object, uint32 flags,
+                       port_id port, int32 token);
+status_t _user_stop_system_watching(int32 object, uint32 flags,
+                       port_id port, int32 token);
+
+
 #ifdef __cplusplus
 }
 #endif
 
+
 #endif /* _KERNEL_SYSTEM_INFO_H */

Modified: haiku/trunk/headers/private/system/syscalls.h
===================================================================
--- haiku/trunk/headers/private/system/syscalls.h       2010-12-16 01:44:15 UTC 
(rev 39861)
+++ haiku/trunk/headers/private/system/syscalls.h       2010-12-16 01:49:52 UTC 
(rev 39862)
@@ -174,6 +174,11 @@
 extern status_t                _kern_get_extended_team_info(team_id teamID, 
uint32 flags,
                                                void* buffer, size_t size, 
size_t* _sizeNeeded);
 
+extern status_t                _kern_start_system_watching(int32 object, 
uint32 flags,
+                                               port_id port, int32 token);
+extern status_t                _kern_stop_system_watching(int32 object, uint32 
flags,
+                                               port_id port, int32 token);
+
 extern status_t                _kern_block_thread(uint32 flags, bigtime_t 
timeout);
 extern status_t                _kern_unblock_thread(thread_id thread, status_t 
status);
 extern status_t                _kern_unblock_threads(thread_id* threads, 
uint32 count,

Modified: haiku/trunk/headers/private/system/system_info.h
===================================================================
--- haiku/trunk/headers/private/system/system_info.h    2010-12-16 01:44:15 UTC 
(rev 39861)
+++ haiku/trunk/headers/private/system/system_info.h    2010-12-16 01:49:52 UTC 
(rev 39862)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Haiku, Inc. All rights reserved.
+ * Copyright 2008-2010, Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _SYSTEM_INFO_H
@@ -24,14 +24,56 @@
 };
 
 
+enum {
+       // team creation or deletion; object == -1; either one also triggers on
+       // exec()
+       B_WATCH_SYSTEM_TEAM_CREATION            = 0x01,
+       B_WATCH_SYSTEM_TEAM_DELETION            = 0x02,
+
+       // thread creation or deletion or property (name, priority) changes;
+       // object == team ID or -1 for all teams
+       B_WATCH_SYSTEM_THREAD_CREATION          = 0x04,
+       B_WATCH_SYSTEM_THREAD_DELETION          = 0x08,
+       B_WATCH_SYSTEM_THREAD_PROPERTIES        = 0x10,
+
+       B_WATCH_SYSTEM_ALL
+               = B_WATCH_SYSTEM_TEAM_CREATION
+               | B_WATCH_SYSTEM_TEAM_DELETION
+               | B_WATCH_SYSTEM_THREAD_CREATION
+               | B_WATCH_SYSTEM_THREAD_DELETION
+               | B_WATCH_SYSTEM_THREAD_PROPERTIES
+};
+
+enum {
+       // message what for the notification messages
+       B_SYSTEM_OBJECT_UPDATE                          = 'SOUP',
+
+       // "opcode" values
+       B_TEAM_CREATED                                          = 0,
+       B_TEAM_DELETED                                          = 1,
+       B_TEAM_EXEC                                                     = 2,
+       B_THREAD_CREATED                                        = 3,
+       B_THREAD_DELETED                                        = 4,
+       B_THREAD_NAME_CHANGED                           = 5
+};
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-extern status_t get_system_info_etc(int32 id, void *buffer, size_t bufferSize);
 
+status_t get_system_info_etc(int32 id, void* buffer, size_t bufferSize);
+
+status_t start_system_watching(int32 object, uint32 flags, port_id port,
+                       int32 token);
+status_t stop_system_watching(int32 object, uint32 flags, port_id port,
+                       int32 token);
+
+
 #ifdef __cplusplus
 }
 #endif
 
+
 #endif /* _SYSTEM_INFO_H */

Modified: haiku/trunk/src/system/kernel/main.cpp
===================================================================
--- haiku/trunk/src/system/kernel/main.cpp      2010-12-16 01:44:15 UTC (rev 
39861)
+++ haiku/trunk/src/system/kernel/main.cpp      2010-12-16 01:49:52 UTC (rev 
39862)
@@ -270,6 +270,9 @@
        TRACE("init user mutex\n");
        user_mutex_init();
 
+       TRACE("init system notifications\n");
+       system_notifications_init();
+
        TRACE("Init modules\n");
        boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES);
        module_init_post_threads();

Modified: haiku/trunk/src/system/kernel/system_info.cpp
===================================================================
--- haiku/trunk/src/system/kernel/system_info.cpp       2010-12-16 01:44:15 UTC 
(rev 39861)
+++ haiku/trunk/src/system/kernel/system_info.cpp       2010-12-16 01:49:52 UTC 
(rev 39862)
@@ -5,6 +5,7 @@
  * Authors:
  *             Stefano Ceccherini
  *             Axel Dörfler, axeld@xxxxxxxxxxxxxxxx
+ *             Ingo Weinhold, ingo_weinhold@xxxxxx
  */
 
 
@@ -17,16 +18,22 @@
 #include <OS.h>
 #include <KernelExport.h>
 
+#include <AutoDeleter.h>
+
 #include <block_cache.h>
 #include <cpu.h>
 #include <debug.h>
 #include <kernel.h>
+#include <lock.h>
+#include <Notifications.h>
+#include <messaging.h>
 #include <port.h>
 #include <real_time_clock.h>
 #include <sem.h>
 #include <smp.h>
 #include <team.h>
 #include <thread.h>
+#include <util/AutoLock.h>
 #include <vm/vm.h>
 #include <vm/vm_page.h>
 
@@ -66,6 +73,335 @@
 }
 
 
+//     #pragma mark - user notifications
+
+
+class SystemNotificationService : private NotificationListener {
+public:
+       SystemNotificationService()
+       {
+               mutex_init(&fLock, "system notification service");
+       }
+
+       status_t Init()
+       {
+               status_t error = fTeamListeners.Init();
+               if (error != B_OK)
+                       return error;
+
+               error = NotificationManager::Manager().AddListener("teams",
+                       TEAM_ADDED | TEAM_REMOVED | TEAM_EXEC, *this);
+               if (error != B_OK)
+                       return error;
+
+               error = NotificationManager::Manager().AddListener("threads",
+                       THREAD_ADDED | THREAD_REMOVED | TEAM_EXEC, *this);
+               if (error != B_OK)
+                       return error;
+
+               return B_OK;
+       }
+
+       status_t StartListening(int32 object, uint32 flags, port_id port,
+               int32 token)
+       {
+               // check the parameters
+               if ((object < 0 && object != -1) || port < 0)
+                       return B_BAD_VALUE;
+
+               if ((flags & B_WATCH_SYSTEM_ALL) == 0
+                       || (flags & ~(uint32)B_WATCH_SYSTEM_ALL) != 0) {
+                       return B_BAD_VALUE;
+               }
+
+               MutexLocker locker(fLock);
+
+               // maybe the listener already exists
+               ListenerList* listenerList;
+               Listener* listener = _FindListener(object, port, token, 
listenerList);
+               if (listener != NULL) {
+                       // just add the new flags
+                       listener->flags |= flags;
+                       return B_OK;
+               }
+
+               // create a new listener
+               listener = new(std::nothrow) Listener;
+               if (listener == NULL)
+                       return B_NO_MEMORY;
+               ObjectDeleter<Listener> listenerDeleter(listener);
+
+               listener->port = port;
+               listener->token = token;
+               listener->flags = flags;
+
+               // if there's no list yet, create a new list
+               if (listenerList == NULL) {
+                       listenerList = new(std::nothrow) ListenerList;
+                       if (listenerList == NULL)
+                               return B_NO_MEMORY;
+
+                       listenerList->object = object;
+
+                       fTeamListeners.Insert(listenerList);
+               }
+
+               listener->list = listenerList;
+               listenerList->listeners.Add(listener);
+               listenerDeleter.Detach();
+
+               team_associate_data(listener);
+
+               return B_OK;
+       }
+
+       status_t StopListening(int32 object, uint32 flags, port_id port,
+               int32 token)
+       {
+               MutexLocker locker(fLock);
+
+               // find the listener
+               ListenerList* listenerList;
+               Listener* listener = _FindListener(object, port, token, 
listenerList);
+               if (listener == NULL)
+                       return B_ENTRY_NOT_FOUND;
+
+               // clear the given flags
+               listener->flags &= ~flags;
+
+               if (listener->flags != 0)
+                       return B_OK;
+
+               team_dissociate_data(listener);
+               _RemoveListener(listener);
+
+               return B_OK;
+       }
+
+private:
+       struct ListenerList;
+
+       struct Listener : AssociatedData {
+               DoublyLinkedListLink<Listener>  listLink;
+               ListenerList*                                   list;
+               port_id                                                 port;
+               int32                                                   token;
+               uint32                                                  flags;
+
+               virtual void OwnerDeleted(AssociatedDataOwner* owner);
+       };
+
+       friend struct Listener;
+
+       struct ListenerList {
+               typedef DoublyLinkedList<Listener,
+                       DoublyLinkedListMemberGetLink<Listener, 
&Listener::listLink> > List;
+
+               ListenerList*   hashNext;
+               List                    listeners;
+               int32                   object;
+       };
+
+       struct ListenerHashDefinition {
+               typedef int32                   KeyType;
+               typedef ListenerList    ValueType;
+
+               size_t HashKey(int32 key) const
+               {
+                       return key;
+               }
+
+               size_t Hash(const ListenerList* value) const
+               {
+                       return HashKey(value->object);
+               }
+
+               bool Compare(int32 key, const ListenerList* value) const
+               {
+                       return value->object == key;
+               }
+
+               ListenerList*& GetLink(ListenerList* value) const
+               {
+                       return value->hashNext;
+               }
+       };
+
+       typedef BOpenHashTable<ListenerHashDefinition> ListenerHash;
+
+private:
+       virtual void EventOccurred(NotificationService& service,
+               const KMessage* event)
+       {
+               MutexLocker locker(fLock);
+
+               int32 eventCode;
+               int32 teamID;
+               if (event->FindInt32("event", &eventCode) != B_OK
+                       || event->FindInt32("team", &teamID) != B_OK) {
+                       return;
+               }
+
+               int32 object;
+               uint32 opcode;
+               uint32 flags;
+
+               // translate the event
+               if (event->What() == TEAM_MONITOR) {
+                       switch (eventCode) {
+                               case TEAM_ADDED:
+                                       opcode = B_TEAM_CREATED;
+                                       flags = B_WATCH_SYSTEM_TEAM_CREATION;
+                                       break;
+                               case TEAM_REMOVED:
+                                       opcode = B_TEAM_DELETED;
+                                       flags = B_WATCH_SYSTEM_TEAM_DELETION;
+                                       break;
+                               case TEAM_EXEC:
+                                       opcode = B_TEAM_EXEC;
+                                       flags = B_WATCH_SYSTEM_TEAM_CREATION
+                                               | B_WATCH_SYSTEM_TEAM_DELETION;
+                                       break;
+                               default:
+                                       return;
+                       }
+
+                       object = teamID;
+               } else if (event->What() == THREAD_MONITOR) {
+                       if (event->FindInt32("thread", &object) != B_OK)
+                               return;
+
+                       switch (eventCode) {
+                               case THREAD_ADDED:
+                                       opcode = B_THREAD_CREATED;
+                                       flags = B_WATCH_SYSTEM_THREAD_CREATION;
+                                       break;
+                               case THREAD_REMOVED:
+                                       opcode = B_THREAD_DELETED;
+                                       flags = B_WATCH_SYSTEM_THREAD_DELETION;
+                                       break;
+                               case THREAD_NAME_CHANGED:
+                                       opcode = B_THREAD_NAME_CHANGED;
+                                       flags = 
B_WATCH_SYSTEM_THREAD_PROPERTIES;
+                                       break;
+                               default:
+                                       return;
+                       }
+               } else
+                       return;
+
+               // find matching listeners
+               messaging_target targets[kMaxMessagingTargetCount];
+               int32 targetCount = 0;
+
+               _AddTargets(fTeamListeners.Lookup(teamID), flags, targets,
+                       targetCount, object, opcode);
+               _AddTargets(fTeamListeners.Lookup(-1), flags, targets, 
targetCount,
+                       object, opcode);
+
+               // send the message
+               if (targetCount > 0)
+                       _SendMessage(targets, targetCount, teamID, opcode);
+       }
+
+       void _AddTargets(ListenerList* listenerList, uint32 flags,
+               messaging_target* targets, int32& targetCount, int32 object,
+               uint32 opcode)
+       {
+               if (listenerList == NULL)
+                       return;
+
+               for (ListenerList::List::Iterator it
+                               = listenerList->listeners.GetIterator();
+                       Listener* listener = it.Next();) {
+                       if ((listener->flags & flags) == 0)
+                               continue;
+
+                       // array is full -- need to flush it first
+                       if (targetCount == kMaxMessagingTargetCount) {
+                               _SendMessage(targets, targetCount, object, 
opcode);
+                               targetCount = 0;
+                       }
+
+                       // add the listener
+                       targets[targetCount].port = listener->port;
+                       targets[targetCount++].token = listener->token;
+               }
+       }
+
+       void _SendMessage(messaging_target* targets, int32 targetCount,
+               int32 object, uint32 opcode)
+       {
+               // prepare the message
+               char buffer[128];
+               KMessage message;
+               message.SetTo(buffer, sizeof(buffer), B_SYSTEM_OBJECT_UPDATE);
+               message.AddInt32("opcode", opcode);
+               if (opcode < B_THREAD_CREATED)
+                       message.AddInt32("team", object);
+               else
+                       message.AddInt32("thread", object);
+
+               // send it
+               send_message(message.Buffer(), message.ContentSize(), targets,
+                       targetCount);
+       }
+
+       Listener* _FindListener(int32 object, port_id port, int32 token,
+               ListenerList*& _listenerList)
+       {
+               _listenerList = fTeamListeners.Lookup(object);
+               if (_listenerList == NULL)
+                       return NULL;
+
+               for (ListenerList::List::Iterator it
+                               = _listenerList->listeners.GetIterator();
+                       Listener* listener = it.Next();) {
+                       if (listener->port == port && listener->token == token)
+                               return listener;
+               }
+
+               return NULL;
+       }
+
+       void _RemoveObsoleteListener(Listener* listener)
+       {
+               MutexLocker locker(fLock);
+               _RemoveListener(listener);
+       }
+
+       void _RemoveListener(Listener* listener)
+       {
+               // no flags anymore -- remove the listener
+               ListenerList* listenerList = listener->list;
+               listenerList->listeners.Remove(listener);
+               listener->ReleaseReference();
+
+               if (listenerList->listeners.IsEmpty()) {
+                       // no listeners in the list anymore -- remove the list 
from the hash
+                       // table
+                       fTeamListeners.Remove(listenerList);
+                       delete listenerList;
+               }
+       }
+
+private:
+       static const int32 kMaxMessagingTargetCount = 8;
+
+       mutex                   fLock;
+       ListenerHash    fTeamListeners;
+};
+
+static SystemNotificationService sSystemNotificationService;
+
+
+void
+SystemNotificationService::Listener::OwnerDeleted(AssociatedDataOwner* owner)
+{
+       sSystemNotificationService._RemoveObsoleteListener(this);
+}
+
+
 //     #pragma mark -
 
 
@@ -115,6 +451,21 @@
 }
 
 
+status_t
+system_notifications_init()
+{
+       new (&sSystemNotificationService) SystemNotificationService;
+
+       status_t error = sSystemNotificationService.Init();
+       if (error != B_OK) {
+               panic("system_info_init(): Failed to init system notification 
service");
+               return error;
+       }
+
+       return B_OK;
+}
+
+
 uint32
 get_haiku_revision(void)
 {
@@ -170,3 +521,20 @@
                        return B_BAD_VALUE;
        }
 }
+
+
+status_t
+_user_start_system_watching(int32 object, uint32 flags, port_id port,
+       int32 token)
+{
+       return sSystemNotificationService.StartListening(object, flags, port,
+               token);
+}
+
+
+status_t
+_user_stop_system_watching(int32 object, uint32 flags, port_id port,
+       int32 token)
+{
+       return sSystemNotificationService.StopListening(object, flags, port, 
token);
+}

Modified: haiku/trunk/src/system/libroot/os/system_info.c
===================================================================
--- haiku/trunk/src/system/libroot/os/system_info.c     2010-12-16 01:44:15 UTC 
(rev 39861)
+++ haiku/trunk/src/system/libroot/os/system_info.c     2010-12-16 01:49:52 UTC 
(rev 39862)
@@ -30,6 +30,20 @@
 }
 
 
+status_t
+start_system_watching(int32 object, uint32 flags, port_id port, int32 token)
+{
+       return _kern_start_system_watching(object, flags, port, token);
+}
+
+
+status_t
+stop_system_watching(int32 object, uint32 flags, port_id port, int32 token)
+{
+       return _kern_stop_system_watching(object, flags, port, token);
+}
+
+
 int32
 is_computer_on(void)
 {


Other related posts: