* The BHandler observer mechanism was completely broken in Haiku for remote targets;

this fixes bug #1005. As a result, the Disks icon will now appear in file panels
  when you change that setting with a panel open.
* _ObserverList is now in the BPrivate namespace (and renamed to ObserverList).
* its BHandler map is now only temporarily used for handlers that do not belong to
  a looper yet; when BHandler::SendNotices() is called, they will be transferred
  into the BMessenger map.
* Invalid messengers are now removed from the map when encountered.
* Added TODO comments about a possible reference counting if a handler is added
  twice to a list (right now, this will be ignored).
* All {Start|Stop}Watching() methods are now more or less safe to be used in low
  memory situations (adding some items to the map can still throw an exception...).
* Renamed BHandler::InitData() to _InitData().
* Some refactoring and cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20029 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-02-01 16:08:01 +00:00
parent fe70b87d91
commit f6c0820638
2 changed files with 181 additions and 115 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2006, Haiku Inc. All Rights Reserved.
* Copyright 2001-2007, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -17,12 +17,14 @@ class BLooper;
class BMessageFilter;
class BMessage;
class BList;
class _ObserverList;
#define B_OBSERVE_WHAT_CHANGE "be:observe_change_what"
#define B_OBSERVE_ORIGINAL_WHAT "be:observe_orig_what"
const uint32 B_OBSERVER_OBSERVE_ALL = 0xffffffff;
namespace BPrivate {
class ObserverList;
}
class BHandler : public BArchivable {
public:
@ -53,31 +55,29 @@ public:
void UnlockLooper();
// Scripting
virtual BHandler* ResolveSpecifier(BMessage* msg,
int32 index,
BMessage* specifier,
int32 form,
const char* property);
virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index,
BMessage* specifier, int32 form,
const char* property);
virtual status_t GetSupportedSuites(BMessage* data);
// Observer calls, inter-looper and inter-team
status_t StartWatching(BMessenger, uint32 what);
status_t StartWatchingAll(BMessenger);
status_t StopWatching(BMessenger, uint32 what);
status_t StopWatchingAll(BMessenger);
status_t StartWatching(BMessenger target, uint32 what);
status_t StartWatchingAll(BMessenger target);
status_t StopWatching(BMessenger target, uint32 what);
status_t StopWatchingAll(BMessenger target);
// Observer calls for observing targets in the same BLooper
status_t StartWatching(BHandler* , uint32 what);
status_t StartWatchingAll(BHandler* );
status_t StopWatching(BHandler* , uint32 what);
status_t StopWatchingAll(BHandler* );
// Observer calls for observing targets in the local team
status_t StartWatching(BHandler* observer, uint32 what);
status_t StartWatchingAll(BHandler* observer);
status_t StopWatching(BHandler* observer, uint32 what);
status_t StopWatchingAll(BHandler* observer);
// Reserved
virtual status_t Perform(perform_code d, void* arg);
// Notifier calls
virtual void SendNotices(uint32 what, const BMessage* = 0);
virtual void SendNotices(uint32 what, const BMessage* notice = NULL);
bool IsWatched() const;
private:
@ -90,18 +90,19 @@ private:
virtual void _ReservedHandler3();
virtual void _ReservedHandler4();
void InitData(const char* name);
void _InitData(const char* name);
BPrivate::ObserverList* _ObserverList();
BHandler(const BHandler&);
BHandler& operator=(const BHandler&);
void SetLooper(BLooper* loop);
void SetLooper(BLooper* looper);
int32 fToken;
char* fName;
BLooper* fLooper;
BHandler* fNextHandler;
BList* fFilters;
_ObserverList* fObserverList;
BPrivate::ObserverList* fObserverList;
uint32 _reserved[3];
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2006, Haiku.
* Copyright 2001-2007, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -19,6 +19,7 @@
#include <PropertyInfo.h>
#include <algorithm>
#include <new>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -29,7 +30,12 @@ using std::vector;
using BPrivate::gDefaultTokens;
static const char *kArchiveNameField = "_name";
static const char* kArchiveNameField = "_name";
static const uint32 kMsgStartObserving = '_OBS';
static const uint32 kMsgStopObserving = '_OBP';
static const char* kObserveTarget = "be:observe_target";
static property_info sHandlerPropInfo[] = {
{
@ -82,28 +88,35 @@ static property_info sHandlerPropInfo[] = {
bool FilterDeleter(void *filter);
typedef map<unsigned long, vector<BHandler *> > THandlerObserverMap;
typedef map<unsigned long, vector<BMessenger> > TMessengerObserverMap;
namespace BPrivate {
//------------------------------------------------------------------------------
// TODO: Change to BPrivate::BObserverList if possible
class _ObserverList {
class ObserverList {
public:
_ObserverList(void);
~_ObserverList(void);
ObserverList();
~ObserverList();
status_t SendNotices(unsigned long, BMessage const *);
status_t StartObserving(BHandler *, unsigned long);
status_t StartObserving(const BMessenger&, unsigned long);
status_t StopObserving(BHandler *, unsigned long);
status_t StopObserving(const BMessenger&, unsigned long);
status_t SendNotices(uint32 what, const BMessage* notice);
status_t Add(const BHandler* handler, uint32 what);
status_t Add(const BMessenger& messenger, uint32 what);
status_t Remove(const BHandler* handler, uint32 what);
status_t Remove(const BMessenger& messenger, uint32 what);
bool IsEmpty();
private:
THandlerObserverMap fHandlerMap;
TMessengerObserverMap fMessengerMap;
typedef map<uint32, vector<const BHandler *> > HandlerObserverMap;
typedef map<uint32, vector<BMessenger> > MessengerObserverMap;
void _ValidateHandlers(uint32 what);
void _SendNotices(uint32 what, BMessage* notice);
HandlerObserverMap fHandlerMap;
MessengerObserverMap fMessengerMap;
};
} // namespace BPrivate
using namespace BPrivate;
// #pragma mark -
@ -112,7 +125,7 @@ BHandler::BHandler(const char *name)
: BArchivable(),
fName(NULL)
{
InitData(name);
_InitData(name);
}
@ -144,7 +157,7 @@ BHandler::BHandler(BMessage *data)
if (data)
data->FindString(kArchiveNameField, &name);
InitData(name);
_InitData(name);
}
@ -175,7 +188,24 @@ BHandler::MessageReceived(BMessage *message)
BMessage reply(B_REPLY);
switch (message->what) {
// ToDo: am I missing something or is the "observed" stuff handshake completely missing?
case kMsgStartObserving:
case kMsgStopObserving:
{
BMessenger target;
uint32 what;
if (message->FindMessenger(kObserveTarget, &target) != B_OK
|| message->FindInt32(B_OBSERVE_WHAT_CHANGE, (int32*)&what) != B_OK)
break;
ObserverList* list = _ObserverList();
if (list != NULL) {
if (message->what == kMsgStartObserving)
list->Add(target, what);
else
list->Remove(target, what);
}
break;
}
case B_GET_PROPERTY:
{
@ -479,59 +509,67 @@ BMessage: what = (0x0, or 0)
status_t
BHandler::StartWatching(BMessenger messenger, uint32 what)
BHandler::StartWatching(BMessenger target, uint32 what)
{
if (fObserverList == NULL)
fObserverList = new _ObserverList;
return fObserverList->StartObserving(messenger, what);
BMessage message(kMsgStartObserving);
message.AddMessenger(kObserveTarget, this);
message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
}
status_t
BHandler::StartWatchingAll(BMessenger messenger)
BHandler::StartWatchingAll(BMessenger target)
{
return StartWatching(messenger, B_OBSERVER_OBSERVE_ALL);
return StartWatching(target, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StopWatching(BMessenger messenger, uint32 what)
BHandler::StopWatching(BMessenger target, uint32 what)
{
if (fObserverList == NULL)
fObserverList = new _ObserverList;
return fObserverList->StopObserving(messenger, what);
BMessage message(kMsgStopObserving);
message.AddMessenger(kObserveTarget, this);
message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
}
status_t
BHandler::StopWatchingAll(BMessenger messenger)
BHandler::StopWatchingAll(BMessenger target)
{
return StopWatching(messenger, B_OBSERVER_OBSERVE_ALL);
return StopWatching(target, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StartWatching(BHandler *handler, uint32 what)
BHandler::StartWatching(BHandler* handler, uint32 what)
{
if (fObserverList == NULL)
fObserverList = new _ObserverList;
return fObserverList->StartObserving(handler, what);
ObserverList* list = _ObserverList();
if (list == NULL)
return B_NO_MEMORY;
return list->Add(handler, what);
}
status_t
BHandler::StartWatchingAll(BHandler *handler)
BHandler::StartWatchingAll(BHandler* handler)
{
return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StopWatching(BHandler *handler, uint32 what)
BHandler::StopWatching(BHandler* handler, uint32 what)
{
if (fObserverList == NULL)
fObserverList = new _ObserverList;
return fObserverList->StopObserving(handler, what);
ObserverList* list = _ObserverList();
if (list == NULL)
return B_NO_MEMORY;
return list->Remove(handler, what);
}
@ -565,7 +603,7 @@ BHandler::IsWatched() const
void
BHandler::InitData(const char *name)
BHandler::_InitData(const char *name)
{
SetName(name);
@ -578,6 +616,16 @@ BHandler::InitData(const char *name)
}
ObserverList*
BHandler::_ObserverList()
{
if (fObserverList == NULL)
fObserverList = new (std::nothrow) BPrivate::ObserverList();
return fObserverList;
}
BHandler::BHandler(const BHandler &)
{
// No copy construction allowed.
@ -618,73 +666,92 @@ void BHandler::_ReservedHandler4() {}
// #pragma mark -
_ObserverList::_ObserverList(void)
ObserverList::ObserverList()
{
}
_ObserverList::~_ObserverList(void)
ObserverList::~ObserverList()
{
}
void
ObserverList::_ValidateHandlers(uint32 what)
{
vector<const BHandler *>& handlers = fHandlerMap[what];
vector<const BHandler *>::iterator iterator = handlers.begin();
for (; iterator != handlers.end(); iterator++) {
BMessenger target(*iterator);
if (!target.IsValid())
continue;
handlers.erase(iterator);
Add(target, what);
}
}
void
ObserverList::_SendNotices(uint32 what, BMessage* message)
{
// first iterate over the list of handlers and try to make valid messengers out of them
_ValidateHandlers(what);
// now send it to all messengers we know
vector<BMessenger>& messengers = fMessengerMap[what];
vector<BMessenger>::iterator iterator = messengers.begin();
for (; iterator != messengers.end(); iterator++) {
if (!(*iterator).IsValid()) {
messengers.erase(iterator);
continue;
}
(*iterator).SendMessage(message);
}
}
status_t
_ObserverList::SendNotices(unsigned long what, BMessage const *message)
ObserverList::SendNotices(uint32 what, const BMessage* message)
{
// Having to new a temporary is really irritating ...
BMessage *copyMsg = NULL;
BMessage *copy = NULL;
if (message) {
copyMsg = new BMessage(*message);
copyMsg->what = B_OBSERVER_NOTICE_CHANGE;
copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
copy = new BMessage(*message);
copy->what = B_OBSERVER_NOTICE_CHANGE;
copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
} else
copyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE);
copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
copyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
vector<BHandler *> &handlers = fHandlerMap[what];
for (uint32 i = 0; i < handlers.size(); ++i) {
BMessenger msgr(handlers[i]);
msgr.SendMessage(copyMsg);
}
vector<BMessenger> &messengers = fMessengerMap[what];
for (uint32 i = 0; i < messengers.size(); ++i)
messengers[i].SendMessage(copyMsg);
// We have to send the message also to the handlers
// and messengers which were subscribed to ALL events,
// since they aren't caught by the above loops.
// TODO: cleanup
vector<BHandler *> &handlersAll = fHandlerMap[B_OBSERVER_OBSERVE_ALL];
for (uint32 i = 0; i < handlersAll.size(); ++i) {
BMessenger msgr(handlersAll[i]);
msgr.SendMessage(copyMsg);
}
vector<BMessenger> &messengersAll = fMessengerMap[B_OBSERVER_OBSERVE_ALL];
for (uint32 i = 0; i < messengersAll.size(); ++i)
messengers[i].SendMessage(copyMsg);
// Gotta make sure to clean up the annoying temporary ...
delete copyMsg;
_SendNotices(what, copy);
_SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
delete copy;
return B_OK;
}
status_t
_ObserverList::StartObserving(BHandler *handler, unsigned long what)
ObserverList::Add(const BHandler *handler, uint32 what)
{
if (handler == NULL)
return B_BAD_HANDLER;
vector<BHandler*> &handlers = fHandlerMap[what];
// if this handler already represents a valid target, add its messenger
BMessenger target(handler);
if (target.IsValid())
return Add(target, what);
vector<BHandler*>::iterator iter;
vector<const BHandler*> &handlers = fHandlerMap[what];
vector<const BHandler*>::iterator iter;
iter = find(handlers.begin(), handlers.end(), handler);
if (iter != handlers.end()) {
// TODO: verify
// TODO: do we want to have a reference count for this?
return B_OK;
}
@ -694,15 +761,14 @@ _ObserverList::StartObserving(BHandler *handler, unsigned long what)
status_t
_ObserverList::StartObserving(const BMessenger &messenger,
unsigned long what)
ObserverList::Add(const BMessenger &messenger, uint32 what)
{
vector<BMessenger> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iter;
iter = find(messengers.begin(), messengers.end(), messenger);
if (iter != messengers.end()) {
// TODO: verify
// TODO: do we want to have a reference count for this?
return B_OK;
}
@ -712,14 +778,19 @@ _ObserverList::StartObserving(const BMessenger &messenger,
status_t
_ObserverList::StopObserving(BHandler *handler, unsigned long what)
ObserverList::Remove(const BHandler *handler, uint32 what)
{
if (handler == NULL)
return B_BAD_HANDLER;
vector<BHandler*> &handlers = fHandlerMap[what];
// look into the list of messengers
BMessenger target(handler);
if (target.IsValid() && Remove(target, what) == B_OK)
return B_OK;
vector<BHandler*>::iterator iter;
vector<const BHandler*> &handlers = fHandlerMap[what];
vector<const BHandler*>::iterator iter;
iter = find(handlers.begin(), handlers.end(), handler);
if (iter != handlers.end()) {
handlers.erase(iter);
@ -734,14 +805,8 @@ _ObserverList::StopObserving(BHandler *handler, unsigned long what)
status_t
_ObserverList::StopObserving(const BMessenger &messenger,
unsigned long what)
ObserverList::Remove(const BMessenger &messenger, uint32 what)
{
// ???: What if you call StartWatching(MyMsngr, aWhat) and then call
// StopWatchingAll(MyMsnger)? Will MyMsnger be removed from the aWhat
// watcher list? For now, we'll assume that they're discreet lists
// which do no cross checking; i.e., MyMsnger would *not* be removed in
// this scenario.
vector<BMessenger> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iter;
@ -759,7 +824,7 @@ _ObserverList::StopObserving(const BMessenger &messenger,
bool
_ObserverList::IsEmpty()
ObserverList::IsEmpty()
{
return fHandlerMap.empty() && fMessengerMap.empty();
}