From efd536ff89954302f42c59e2c71fba45e5cb4c25 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 11 Apr 2009 21:45:25 +0000 Subject: [PATCH] * Cleared up a misconception in the notification mechanism. We already had methods that used an "event mask" field. There was no need to introduce a "flags" field for the same purpose. * Renamed protected DefaultNotificationService methods (removed "_" prefix). * Adjusted the code providing a notification service accordingly. * Changed the event message several notification services generated by renaming the "opcode" field to "event". * Implemented the TEAM_ADDED event and also added a TEAM_EXEC event. * Added notifications for threads and images. * Added visitor-like iteration functions for teams, threads, and images. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30126 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/Notifications.h | 16 ++-- headers/private/kernel/kimage.h | 26 +++++- headers/private/kernel/port.h | 4 +- headers/private/kernel/team.h | 11 ++- headers/private/kernel/thread.h | 10 +++ .../network/notifications/notifications.cpp | 18 +---- src/system/kernel/Notifications.cpp | 81 ++++++++++--------- .../KDiskDeviceManager.cpp | 7 -- src/system/kernel/image.cpp | 57 ++++++++++--- src/system/kernel/port.cpp | 16 +--- src/system/kernel/team.cpp | 56 ++++++++----- src/system/kernel/thread.cpp | 53 ++++++++++++ 12 files changed, 242 insertions(+), 113 deletions(-) diff --git a/headers/private/kernel/Notifications.h b/headers/private/kernel/Notifications.h index 61d8125f63..6ab3c4475f 100644 --- a/headers/private/kernel/Notifications.h +++ b/headers/private/kernel/Notifications.h @@ -118,7 +118,7 @@ private: struct default_listener : public DoublyLinkedListLinkImpl { ~default_listener(); - uint32 flags; + uint32 eventMask; team_id team; NotificationListener* listener; }; @@ -131,7 +131,7 @@ public: DefaultNotificationService(const char* name); virtual ~DefaultNotificationService(); - void Notify(const KMessage& event, uint32 flags); + void Notify(const KMessage& event, uint32 eventMask); virtual status_t AddListener(const KMessage* eventSpecifier, NotificationListener& listener); @@ -143,10 +143,10 @@ public: virtual const char* Name() { return fName; } protected: - virtual status_t _ToFlags(const KMessage& eventSpecifier, - uint32& flags); - virtual void _FirstAdded(); - virtual void _LastRemoved(); + virtual status_t ToEventMask(const KMessage& eventSpecifier, + uint32& eventMask); + virtual void FirstAdded(); + virtual void LastRemoved(); recursive_lock fLock; DefaultListenerList fListeners; @@ -168,7 +168,7 @@ public: NotificationListener& listener); status_t RemoveUserListeners(port_id port, uint32 token); - status_t UpdateUserListener(uint32 flags, + status_t UpdateUserListener(uint32 eventMask, port_id port, uint32 token); private: @@ -176,7 +176,7 @@ private: const KMessage* event); virtual void AllListenersNotified( NotificationService& service); - status_t _AddListener(uint32 flags, + status_t _AddListener(uint32 eventMask, NotificationListener& listener); UserMessagingMessageSender fSender; diff --git a/headers/private/kernel/kimage.h b/headers/private/kernel/kimage.h index e2233b2970..619e7e3707 100644 --- a/headers/private/kernel/kimage.h +++ b/headers/private/kernel/kimage.h @@ -5,12 +5,32 @@ #ifndef _KERNEL_IMAGE_H #define _KERNEL_IMAGE_H - #include +struct image; struct team; +#ifdef __cplusplus + +#include + +struct image { + struct image* next; + struct image* prev; + HashTableLink hash_link; + image_info info; + team_id team; +}; + +#endif // __cplusplus + +// image notifications +#define IMAGE_MONITOR '_Im_' +#define IMAGE_ADDED 0x01 +#define IMAGE_REMOVED 0x02 + + #ifdef __cplusplus extern "C" { #endif @@ -20,6 +40,10 @@ extern status_t unregister_image(struct team *team, image_id id); extern int32 count_images(struct team *team); extern status_t remove_images(struct team *team); +typedef bool (*image_iterator_callback)(struct image* image, void* cookie); +struct image* image_iterate_through_images(image_iterator_callback callback, + void* cookie); + extern status_t image_debug_lookup_user_symbol_address(struct team *team, addr_t address, addr_t *_baseAddress, const char **_symbolName, const char **_imageName, bool *_exactMatch); diff --git a/headers/private/kernel/port.h b/headers/private/kernel/port.h index fa5f905d50..9f64bd60f2 100644 --- a/headers/private/kernel/port.h +++ b/headers/private/kernel/port.h @@ -24,8 +24,8 @@ enum { // port notifications #define PORT_MONITOR '_Pm_' -#define PORT_ADDED 1 -#define PORT_REMOVED 2 +#define PORT_ADDED 0x01 +#define PORT_REMOVED 0x02 #ifdef __cplusplus extern "C" { diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index bb497382e5..a98e64fd9f 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -9,10 +9,11 @@ #include -// Team notifications +// team notifications #define TEAM_MONITOR '_Tm_' -#define TEAM_ADDED 1 -#define TEAM_REMOVED 2 +#define TEAM_ADDED 0x01 +#define TEAM_REMOVED 0x02 +#define TEAM_EXEC 0x04 #ifdef __cplusplus @@ -40,6 +41,10 @@ struct team *team_get_team_struct_locked(team_id id); int32 team_max_teams(void); int32 team_used_teams(void); +typedef bool (*team_iterator_callback)(struct team* team, void* cookie); +struct team* team_iterate_through_teams(team_iterator_callback callback, + void* cookie); + thread_id load_image_etc(int32 argCount, const char* const* args, const char* const* env, int32 priority, team_id parentID, uint32 flags); diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index 864859b35b..af92205304 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -23,6 +23,12 @@ struct select_info; struct thread_creation_attributes; +// thread notifications +#define THREAD_MONITOR '_tm_' +#define THREAD_ADDED 0x01 +#define THREAD_REMOVED 0x02 + + #ifdef __cplusplus extern "C" { #endif @@ -70,6 +76,10 @@ thread_is_idle_thread(struct thread *thread) return thread->entry == NULL; } +typedef bool (*thread_iterator_callback)(struct thread* thread, void* cookie); +struct thread* thread_iterate_through_threads(thread_iterator_callback callback, + void* cookie); + thread_id allocate_thread_id(void); thread_id peek_next_thread_id(void); diff --git a/src/add-ons/kernel/network/notifications/notifications.cpp b/src/add-ons/kernel/network/notifications/notifications.cpp index 2181ff6ad4..7c2544cbc8 100644 --- a/src/add-ons/kernel/network/notifications/notifications.cpp +++ b/src/add-ons/kernel/network/notifications/notifications.cpp @@ -27,10 +27,8 @@ public: void Notify(const KMessage& event); protected: - virtual status_t _ToFlags(const KMessage& eventSpecifier, - uint32& flags); - virtual void _FirstAdded(); - virtual void _LastRemoved(); + virtual void FirstAdded(); + virtual void LastRemoved(); }; static NetNotificationService sNotificationService; @@ -63,16 +61,8 @@ NetNotificationService::Notify(const KMessage& event) } -status_t -NetNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) -{ - flags = eventSpecifier.GetInt32("flags", 0); - return B_OK; -} - - void -NetNotificationService::_FirstAdded() +NetNotificationService::FirstAdded() { // The reference counting doesn't work for us, as we'll have to // ensure our module stays loaded. @@ -82,7 +72,7 @@ NetNotificationService::_FirstAdded() void -NetNotificationService::_LastRemoved() +NetNotificationService::LastRemoved() { // Give up the reference _AddListener() put_module(NET_NOTIFICATIONS_MODULE_NAME); diff --git a/src/system/kernel/Notifications.cpp b/src/system/kernel/Notifications.cpp index 7e2c0bac16..36a4702abf 100644 --- a/src/system/kernel/Notifications.cpp +++ b/src/system/kernel/Notifications.cpp @@ -13,6 +13,9 @@ #include +static const char* kEventMaskString = "event mask"; + + NotificationManager NotificationManager::sManager; @@ -158,22 +161,28 @@ DefaultNotificationService::~DefaultNotificationService() /*! \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 + \param eventMask Only listeners with an event mask sharing at least one + common bit with this mask will receive the event. */ void -DefaultNotificationService::Notify(const KMessage& event, uint32 flags) +DefaultNotificationService::Notify(const KMessage& event, uint32 eventMask) { RecursiveLocker _(fLock); + // Note: The following iterations support that the listener removes itself + // in the hook method. That's a property of the DoublyLinkedList iterator. + + // notify all listeners about the event DefaultListenerList::Iterator iterator = fListeners.GetIterator(); while (default_listener* listener = iterator.Next()) { - if ((flags & listener->flags) != 0) + if ((eventMask & listener->eventMask) != 0) listener->listener->EventOccured(*this, &event); } + // notify all listeners that all listeners have been notified iterator = fListeners.GetIterator(); while (default_listener* listener = iterator.Next()) { - if ((flags & listener->flags) != 0) + if ((eventMask & listener->eventMask) != 0) listener->listener->AllListenersNotified(*this); } } @@ -186,8 +195,8 @@ DefaultNotificationService::AddListener(const KMessage* eventSpecifier, if (eventSpecifier == NULL) return B_BAD_VALUE; - uint32 flags; - status_t status = _ToFlags(*eventSpecifier, flags); + uint32 eventMask; + status_t status = ToEventMask(*eventSpecifier, eventMask); if (status != B_OK) return status; @@ -195,13 +204,13 @@ DefaultNotificationService::AddListener(const KMessage* eventSpecifier, if (listener == NULL) return B_NO_MEMORY; - listener->flags = flags; + listener->eventMask = eventMask; listener->team = -1; listener->listener = ¬ificationListener; RecursiveLocker _(fLock); if (fListeners.IsEmpty()) - _FirstAdded(); + FirstAdded(); fListeners.Add(listener); return B_OK; @@ -227,9 +236,9 @@ DefaultNotificationService::RemoveListener(const KMessage* eventSpecifier, if (listener->listener == ¬ificationListener) { iterator.Remove(); delete listener; - + if (fListeners.IsEmpty()) - _LastRemoved(); + LastRemoved(); return B_OK; } } @@ -239,21 +248,21 @@ DefaultNotificationService::RemoveListener(const KMessage* eventSpecifier, status_t -DefaultNotificationService::_ToFlags(const KMessage& eventSpecifier, - uint32& flags) +DefaultNotificationService::ToEventMask(const KMessage& eventSpecifier, + uint32& eventMask) { - return eventSpecifier.FindInt32("flags", (int32*)&flags); + return eventSpecifier.FindInt32("event mask", (int32*)&eventMask); } void -DefaultNotificationService::_FirstAdded() +DefaultNotificationService::FirstAdded() { } void -DefaultNotificationService::_LastRemoved() +DefaultNotificationService::LastRemoved() { } @@ -281,9 +290,9 @@ DefaultUserNotificationService::AddListener(const KMessage* eventSpecifier, if (eventSpecifier == NULL) return B_BAD_VALUE; - uint32 flags = eventSpecifier->GetInt32("flags", 0); + uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0); - return _AddListener(flags, listener); + return _AddListener(eventMask, listener); } @@ -294,18 +303,18 @@ DefaultUserNotificationService::UpdateListener(const KMessage* eventSpecifier, if (eventSpecifier == NULL) return B_BAD_VALUE; - uint32 flags = eventSpecifier->GetInt32("flags", 0); - bool addFlags = eventSpecifier->GetBool("add flags", false); + uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0); + bool addEvents = eventSpecifier->GetBool("add events", false); RecursiveLocker _(fLock); DefaultListenerList::Iterator iterator = fListeners.GetIterator(); while (default_listener* listener = iterator.Next()) { if (*listener->listener == notificationListener) { - if (addFlags) - listener->flags |= flags; + if (addEvents) + listener->eventMask |= eventMask; else - listener->flags = flags; + listener->eventMask = eventMask; return B_OK; } } @@ -345,9 +354,9 @@ DefaultUserNotificationService::RemoveUserListeners(port_id port, uint32 token) if (*listener->listener == userListener) { iterator.Remove(); delete listener; - + if (fListeners.IsEmpty()) - _LastRemoved(); + LastRemoved(); return B_OK; } } @@ -357,8 +366,8 @@ DefaultUserNotificationService::RemoveUserListeners(port_id port, uint32 token) status_t -DefaultUserNotificationService::UpdateUserListener(uint32 flags, port_id port, - uint32 token) +DefaultUserNotificationService::UpdateUserListener(uint32 eventMask, + port_id port, uint32 token) { UserMessagingListener userListener(fSender, port, token); @@ -367,7 +376,7 @@ DefaultUserNotificationService::UpdateUserListener(uint32 flags, port_id port, DefaultListenerList::Iterator iterator = fListeners.GetIterator(); while (default_listener* listener = iterator.Next()) { if (*listener->listener == userListener) { - listener->flags |= flags; + listener->eventMask |= eventMask; return B_OK; } } @@ -377,7 +386,7 @@ DefaultUserNotificationService::UpdateUserListener(uint32 flags, port_id port, if (copiedListener == NULL) return B_NO_MEMORY; - status_t status = _AddListener(flags, *copiedListener); + status_t status = _AddListener(eventMask, *copiedListener); if (status != B_OK) delete copiedListener; @@ -389,13 +398,13 @@ void DefaultUserNotificationService::EventOccured(NotificationService& service, const KMessage* event) { - int32 opcode = event->GetInt32("opcode", -1); + int32 eventCode = event->GetInt32("event", -1); team_id team = event->GetInt32("team", -1); - if (opcode == TEAM_REMOVED && team >= B_OK) { + if (eventCode == 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) { @@ -415,20 +424,20 @@ DefaultUserNotificationService::AllListenersNotified( status_t -DefaultUserNotificationService::_AddListener(uint32 flags, +DefaultUserNotificationService::_AddListener(uint32 eventMask, NotificationListener& notificationListener) { default_listener* listener = new(std::nothrow) default_listener; if (listener == NULL) return B_NO_MEMORY; - listener->flags = flags; + listener->eventMask = eventMask; listener->team = team_get_current_team_id(); listener->listener = ¬ificationListener; RecursiveLocker _(fLock); if (fListeners.IsEmpty()) - _FirstAdded(); + FirstAdded(); fListeners.Add(listener); return B_OK; @@ -511,7 +520,7 @@ NotificationManager::AddListener(const char* serviceName, char buffer[96]; KMessage specifier; specifier.SetTo(buffer, sizeof(buffer), 0); - specifier.AddInt32("event mask", eventMask); + specifier.AddInt32(kEventMaskString, eventMask); return AddListener(serviceName, &specifier, listener); } @@ -540,7 +549,7 @@ NotificationManager::UpdateListener(const char* serviceName, char buffer[96]; KMessage specifier; specifier.SetTo(buffer, sizeof(buffer), 0); - specifier.AddInt32("event mask", eventMask); + specifier.AddInt32(kEventMaskString, eventMask); return UpdateListener(serviceName, &specifier, listener); } diff --git a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp index ed113a0a76..523054f1e6 100644 --- a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp +++ b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp @@ -195,13 +195,6 @@ public: virtual ~DiskNotifications() { } - -protected: - status_t _ToFlags(const KMessage& eventSpecifier, uint32& flags) - { - flags = eventSpecifier.GetInt32("flags", 0); - return B_OK; - } }; diff --git a/src/system/kernel/image.cpp b/src/system/kernel/image.cpp index 6d5035676b..e24b23c976 100644 --- a/src/system/kernel/image.cpp +++ b/src/system/kernel/image.cpp @@ -12,11 +12,12 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include @@ -31,14 +32,6 @@ #define ADD_DEBUGGER_COMMANDS -struct image { - struct image* next; - struct image* prev; - HashTableLink hash_link; - image_info info; - team_id team; -}; - struct ImageTableDefinition { typedef image_id KeyType; @@ -55,9 +48,31 @@ struct ImageTableDefinition { typedef OpenHashTable ImageTable; +class ImageNotificationService : public DefaultNotificationService { +public: + ImageNotificationService() + : DefaultNotificationService("images") + { + } + + void Notify(uint32 eventCode, struct image* image) + { + char eventBuffer[128]; + KMessage event; + event.SetTo(eventBuffer, sizeof(eventBuffer), IMAGE_MONITOR); + event.AddInt32("event", eventCode); + event.AddInt32("image", image->info.id); + event.AddPointer("imageStruct", image); + + DefaultNotificationService::Notify(event, eventCode); + } +}; + + static image_id sNextImageID = 1; static mutex sImageMutex = MUTEX_INITIALIZER("image"); static ImageTable* sImageTable; +static ImageNotificationService sNotificationService; /*! Registers an image with the specified team. @@ -87,6 +102,9 @@ register_image(struct team *team, image_info *_info, size_t size) list_add_item(&team->image_list, image); sImageTable->Insert(image); + // notify listeners + sNotificationService.Notify(IMAGE_ADDED, image); + mutex_unlock(&sImageMutex); TRACE(("register_image(team = %p, image id = %ld, image = %p\n", team, id, image)); @@ -116,6 +134,9 @@ unregister_image(struct team *team, image_id id) // notify the debugger user_debug_image_deleted(&image->info); + // notify listeners + sNotificationService.Notify(IMAGE_REMOVED, image); + free(image); } @@ -263,6 +284,22 @@ dump_images_list(int argc, char **argv) #endif +struct image* +image_iterate_through_images(image_iterator_callback callback, void* cookie) +{ + MutexLocker locker(sImageMutex); + + ImageTable::Iterator it = sImageTable->GetIterator(); + struct image* image = NULL; + while ((image = it.Next()) != NULL) { + if (callback(image, cookie)) + break; + } + + return image; +} + + status_t image_debug_lookup_user_symbol_address(struct team *team, addr_t address, addr_t *_baseAddress, const char **_symbolName, const char **_imageName, @@ -310,6 +347,8 @@ image_init(void) return error; } + new(&sNotificationService) ImageNotificationService(); + #ifdef ADD_DEBUGGER_COMMANDS add_debugger_command("team_images", &dump_images_list, "Dump all registered images from the current team"); #endif diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index ca35f0af51..700fd10fb5 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -65,10 +65,6 @@ public: PortNotificationService(); void Notify(uint32 opcode, port_id team); - -protected: - virtual status_t _ToFlags(const KMessage& eventSpecifier, - uint32& flags); }; #define MAX_QUEUE_LENGTH 4096 @@ -109,18 +105,10 @@ 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("event", opcode); event.AddInt32("port", port); - DefaultNotificationService::Notify(event, ~0U); -} - - -status_t -PortNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) -{ - flags = ~0U; - return B_OK; + DefaultNotificationService::Notify(event, opcode); } diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index c2358f97d4..d220ef00e9 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -86,11 +86,7 @@ class TeamNotificationService : public DefaultNotificationService { public: TeamNotificationService(); - void Notify(uint32 opcode, team_id team); - -protected: - virtual status_t _ToFlags(const KMessage& eventSpecifier, - uint32& flags); + void Notify(uint32 eventCode, struct team* team); }; @@ -312,23 +308,16 @@ TeamNotificationService::TeamNotificationService() void -TeamNotificationService::Notify(uint32 opcode, team_id team) +TeamNotificationService::Notify(uint32 eventCode, struct team* team) { - char eventBuffer[64]; + char eventBuffer[128]; KMessage event; event.SetTo(eventBuffer, sizeof(eventBuffer), TEAM_MONITOR); - event.AddInt32("opcode", opcode); - event.AddInt32("team", team); + event.AddInt32("event", eventCode); + event.AddInt32("team", team->id); + event.AddPointer("teamStruct", team); - DefaultNotificationService::Notify(event, ~0U); -} - - -status_t -TeamNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags) -{ - flags = ~0U; - return B_OK; + DefaultNotificationService::Notify(event, eventCode); } @@ -1236,6 +1225,9 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, if (status != B_OK) goto err4; + // notify team listeners + sNotificationService.Notify(TEAM_ADDED, team); + // Create a kernel thread, but under the context of the new team // The new thread will take over ownership of teamArgs thread = spawn_kernel_thread_etc(team_create_thread_start, threadName, @@ -1430,6 +1422,9 @@ exec_team(const char *path, char**& _flatArgs, size_t flatArgsSize, user_debug_team_exec(); + // notify team listeners + sNotificationService.Notify(TEAM_EXEC, team); + status = team_create_thread_start(teamArgs); // this one usually doesn't return... @@ -1603,6 +1598,9 @@ fork_team(void) goto err5; } + // notify team listeners + sNotificationService.Notify(TEAM_ADDED, team); + // create a kernel thread under the context of the new team threadID = spawn_kernel_thread_etc(fork_team_thread_start, parentThread->name, parentThread->priority, forkArgs, @@ -2084,6 +2082,26 @@ team_used_teams(void) } +/*! Iterates through the list of teams. The team spinlock must be held. + */ +struct team* +team_iterate_through_teams(team_iterator_callback callback, void* cookie) +{ + struct hash_iterator iterator; + hash_open(sTeamHash, &iterator); + + struct team* team; + while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) { + if (callback(team, cookie)) + break; + } + + hash_close(sTeamHash, &iterator, false); + + return team; +} + + /*! Fills the provided death entry if it's in the team. You need to have the team lock held when calling this function. */ @@ -2420,7 +2438,7 @@ team_delete_team(struct team *team) } } - sNotificationService.Notify(TEAM_REMOVED, team->id); + sNotificationService.Notify(TEAM_REMOVED, team); // free team resources diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index c20a049fdb..7506b801e8 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -86,8 +87,32 @@ struct UndertakerEntry : DoublyLinkedListLinkImpl { } }; + +class ThreadNotificationService : public DefaultNotificationService { +public: + ThreadNotificationService() + : DefaultNotificationService("threads") + { + } + + void Notify(uint32 eventCode, struct thread* thread) + { + char eventBuffer[128]; + KMessage event; + event.SetTo(eventBuffer, sizeof(eventBuffer), THREAD_MONITOR); + event.AddInt32("event", eventCode); + event.AddInt32("thread", thread->id); + event.AddPointer("threadStruct", thread); + + DefaultNotificationService::Notify(event, eventCode); + } +}; + + static DoublyLinkedList sUndertakerEntries; static ConditionVariable sUndertakerCondition; +static ThreadNotificationService sNotificationService; + // The dead queue is used as a pool from which to retrieve and reuse previously // allocated thread structs when creating a new thread. It should be gone once @@ -504,6 +529,9 @@ create_thread(thread_creation_attributes& attributes, bool kernel) thread->entry = attributes.entry; status = thread->id; + // notify listeners + sNotificationService.Notify(THREAD_ADDED, thread); + if (kernel) { // this sets up an initial kthread stack that runs the entry @@ -1507,6 +1535,9 @@ thread_exit(void) put_select_sync(sync); } + // notify listeners + sNotificationService.Notify(THREAD_REMOVED, thread); + // shutdown the thread messaging status = acquire_sem_etc(thread->msg.write_sem, 1, B_RELATIVE_TIMEOUT, 0); @@ -1740,6 +1771,25 @@ thread_dequeue_id(struct thread_queue *q, thread_id id) } +struct thread* +thread_iterate_through_threads(thread_iterator_callback callback, void* cookie) +{ + struct hash_iterator iterator; + hash_open(sThreadHash, &iterator); + + struct thread* thread; + while ((thread = (struct thread*)hash_next(sThreadHash, &iterator)) + != NULL) { + if (callback(thread, cookie)) + break; + } + + hash_close(sThreadHash, &iterator, false); + + return thread; +} + + thread_id allocate_thread_id(void) { @@ -2099,6 +2149,9 @@ thread_init(kernel_args *args) } sUsedThreads = args->num_cpus; + // init the notification service + new(&sNotificationService) ThreadNotificationService(); + // start the undertaker thread new(&sUndertakerEntries) DoublyLinkedList(); sUndertakerCondition.Init(&sUndertakerEntries, "undertaker entries");