* 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
This commit is contained in:
Ingo Weinhold
2009-04-11 21:45:25 +00:00
parent 78c00a4a53
commit efd536ff89
12 changed files with 242 additions and 113 deletions
+8 -8
View File
@@ -118,7 +118,7 @@ private:
struct default_listener : public DoublyLinkedListLinkImpl<default_listener> {
~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;
+25 -1
View File
@@ -5,12 +5,32 @@
#ifndef _KERNEL_IMAGE_H
#define _KERNEL_IMAGE_H
#include <image.h>
struct image;
struct team;
#ifdef __cplusplus
#include <util/OpenHashTable.h>
struct image {
struct image* next;
struct image* prev;
HashTableLink<image> 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);
+2 -2
View File
@@ -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" {
+8 -3
View File
@@ -9,10 +9,11 @@
#include <thread_types.h>
// 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);
+10
View File
@@ -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);
@@ -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);
+45 -36
View File
@@ -13,6 +13,9 @@
#include <team.h>
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 = &notificationListener;
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 == &notificationListener) {
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 = &notificationListener;
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);
}
@@ -195,13 +195,6 @@ public:
virtual ~DiskNotifications()
{
}
protected:
status_t _ToFlags(const KMessage& eventSpecifier, uint32& flags)
{
flags = eventSpecifier.GetInt32("flags", 0);
return B_OK;
}
};
+48 -9
View File
@@ -12,11 +12,12 @@
#include <kimage.h>
#include <kscheduler.h>
#include <lock.h>
#include <Notifications.h>
#include <team.h>
#include <thread.h>
#include <thread_types.h>
#include <user_debugger.h>
#include <util/OpenHashTable.h>
#include <util/AutoLock.h>
#include <stdlib.h>
#include <string.h>
@@ -31,14 +32,6 @@
#define ADD_DEBUGGER_COMMANDS
struct image {
struct image* next;
struct image* prev;
HashTableLink<image> hash_link;
image_info info;
team_id team;
};
struct ImageTableDefinition {
typedef image_id KeyType;
@@ -55,9 +48,31 @@ struct ImageTableDefinition {
typedef OpenHashTable<ImageTableDefinition> 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
+2 -14
View File
@@ -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);
}
+37 -19
View File
@@ -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
+53
View File
@@ -30,6 +30,7 @@
#include <kimage.h>
#include <kscheduler.h>
#include <ksignal.h>
#include <Notifications.h>
#include <real_time_clock.h>
#include <smp.h>
#include <syscalls.h>
@@ -86,8 +87,32 @@ struct UndertakerEntry : DoublyLinkedListLinkImpl<UndertakerEntry> {
}
};
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<UndertakerEntry> 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<UndertakerEntry>();
sUndertakerCondition.Init(&sUndertakerEntries, "undertaker entries");