* 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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -17,12 +17,14 @@ class BLooper;
class BMessageFilter; class BMessageFilter;
class BMessage; class BMessage;
class BList; class BList;
class _ObserverList;
#define B_OBSERVE_WHAT_CHANGE "be:observe_change_what" #define B_OBSERVE_WHAT_CHANGE "be:observe_change_what"
#define B_OBSERVE_ORIGINAL_WHAT "be:observe_orig_what" #define B_OBSERVE_ORIGINAL_WHAT "be:observe_orig_what"
const uint32 B_OBSERVER_OBSERVE_ALL = 0xffffffff; const uint32 B_OBSERVER_OBSERVE_ALL = 0xffffffff;
namespace BPrivate {
class ObserverList;
}
class BHandler : public BArchivable { class BHandler : public BArchivable {
public: public:
@ -53,31 +55,29 @@ public:
void UnlockLooper(); void UnlockLooper();
// Scripting // Scripting
virtual BHandler* ResolveSpecifier(BMessage* msg, virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index,
int32 index, BMessage* specifier, int32 form,
BMessage* specifier,
int32 form,
const char* property); const char* property);
virtual status_t GetSupportedSuites(BMessage* data); virtual status_t GetSupportedSuites(BMessage* data);
// Observer calls, inter-looper and inter-team // Observer calls, inter-looper and inter-team
status_t StartWatching(BMessenger, uint32 what); status_t StartWatching(BMessenger target, uint32 what);
status_t StartWatchingAll(BMessenger); status_t StartWatchingAll(BMessenger target);
status_t StopWatching(BMessenger, uint32 what); status_t StopWatching(BMessenger target, uint32 what);
status_t StopWatchingAll(BMessenger); status_t StopWatchingAll(BMessenger target);
// Observer calls for observing targets in the same BLooper // Observer calls for observing targets in the local team
status_t StartWatching(BHandler* , uint32 what); status_t StartWatching(BHandler* observer, uint32 what);
status_t StartWatchingAll(BHandler* ); status_t StartWatchingAll(BHandler* observer);
status_t StopWatching(BHandler* , uint32 what); status_t StopWatching(BHandler* observer, uint32 what);
status_t StopWatchingAll(BHandler* ); status_t StopWatchingAll(BHandler* observer);
// Reserved // Reserved
virtual status_t Perform(perform_code d, void* arg); virtual status_t Perform(perform_code d, void* arg);
// Notifier calls // Notifier calls
virtual void SendNotices(uint32 what, const BMessage* = 0); virtual void SendNotices(uint32 what, const BMessage* notice = NULL);
bool IsWatched() const; bool IsWatched() const;
private: private:
@ -90,18 +90,19 @@ private:
virtual void _ReservedHandler3(); virtual void _ReservedHandler3();
virtual void _ReservedHandler4(); virtual void _ReservedHandler4();
void InitData(const char* name); void _InitData(const char* name);
BPrivate::ObserverList* _ObserverList();
BHandler(const BHandler&); BHandler(const BHandler&);
BHandler& operator=(const BHandler&); BHandler& operator=(const BHandler&);
void SetLooper(BLooper* loop); void SetLooper(BLooper* looper);
int32 fToken; int32 fToken;
char* fName; char* fName;
BLooper* fLooper; BLooper* fLooper;
BHandler* fNextHandler; BHandler* fNextHandler;
BList* fFilters; BList* fFilters;
_ObserverList* fObserverList; BPrivate::ObserverList* fObserverList;
uint32 _reserved[3]; 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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -19,6 +19,7 @@
#include <PropertyInfo.h> #include <PropertyInfo.h>
#include <algorithm> #include <algorithm>
#include <new>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -29,7 +30,12 @@ using std::vector;
using BPrivate::gDefaultTokens; 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[] = { static property_info sHandlerPropInfo[] = {
{ {
@ -82,28 +88,35 @@ static property_info sHandlerPropInfo[] = {
bool FilterDeleter(void *filter); bool FilterDeleter(void *filter);
typedef map<unsigned long, vector<BHandler *> > THandlerObserverMap; namespace BPrivate {
typedef map<unsigned long, vector<BMessenger> > TMessengerObserverMap;
//------------------------------------------------------------------------------ class ObserverList {
// TODO: Change to BPrivate::BObserverList if possible
class _ObserverList {
public: public:
_ObserverList(void); ObserverList();
~_ObserverList(void); ~ObserverList();
status_t SendNotices(unsigned long, BMessage const *); status_t SendNotices(uint32 what, const BMessage* notice);
status_t StartObserving(BHandler *, unsigned long); status_t Add(const BHandler* handler, uint32 what);
status_t StartObserving(const BMessenger&, unsigned long); status_t Add(const BMessenger& messenger, uint32 what);
status_t StopObserving(BHandler *, unsigned long); status_t Remove(const BHandler* handler, uint32 what);
status_t StopObserving(const BMessenger&, unsigned long); status_t Remove(const BMessenger& messenger, uint32 what);
bool IsEmpty(); bool IsEmpty();
private: private:
THandlerObserverMap fHandlerMap; typedef map<uint32, vector<const BHandler *> > HandlerObserverMap;
TMessengerObserverMap fMessengerMap; 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 - // #pragma mark -
@ -112,7 +125,7 @@ BHandler::BHandler(const char *name)
: BArchivable(), : BArchivable(),
fName(NULL) fName(NULL)
{ {
InitData(name); _InitData(name);
} }
@ -144,7 +157,7 @@ BHandler::BHandler(BMessage *data)
if (data) if (data)
data->FindString(kArchiveNameField, &name); data->FindString(kArchiveNameField, &name);
InitData(name); _InitData(name);
} }
@ -175,7 +188,24 @@ BHandler::MessageReceived(BMessage *message)
BMessage reply(B_REPLY); BMessage reply(B_REPLY);
switch (message->what) { 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: case B_GET_PROPERTY:
{ {
@ -479,59 +509,67 @@ BMessage: what = (0x0, or 0)
status_t status_t
BHandler::StartWatching(BMessenger messenger, uint32 what) BHandler::StartWatching(BMessenger target, uint32 what)
{ {
if (fObserverList == NULL) BMessage message(kMsgStartObserving);
fObserverList = new _ObserverList; message.AddMessenger(kObserveTarget, this);
return fObserverList->StartObserving(messenger, what); message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
} }
status_t 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 status_t
BHandler::StopWatching(BMessenger messenger, uint32 what) BHandler::StopWatching(BMessenger target, uint32 what)
{ {
if (fObserverList == NULL) BMessage message(kMsgStopObserving);
fObserverList = new _ObserverList; message.AddMessenger(kObserveTarget, this);
return fObserverList->StopObserving(messenger, what); message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
} }
status_t 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 status_t
BHandler::StartWatching(BHandler *handler, uint32 what) BHandler::StartWatching(BHandler* handler, uint32 what)
{ {
if (fObserverList == NULL) ObserverList* list = _ObserverList();
fObserverList = new _ObserverList; if (list == NULL)
return fObserverList->StartObserving(handler, what); return B_NO_MEMORY;
return list->Add(handler, what);
} }
status_t status_t
BHandler::StartWatchingAll(BHandler *handler) BHandler::StartWatchingAll(BHandler* handler)
{ {
return StartWatching(handler, B_OBSERVER_OBSERVE_ALL); return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
} }
status_t status_t
BHandler::StopWatching(BHandler *handler, uint32 what) BHandler::StopWatching(BHandler* handler, uint32 what)
{ {
if (fObserverList == NULL) ObserverList* list = _ObserverList();
fObserverList = new _ObserverList; if (list == NULL)
return fObserverList->StopObserving(handler, what); return B_NO_MEMORY;
return list->Remove(handler, what);
} }
@ -565,7 +603,7 @@ BHandler::IsWatched() const
void void
BHandler::InitData(const char *name) BHandler::_InitData(const char *name)
{ {
SetName(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 &) BHandler::BHandler(const BHandler &)
{ {
// No copy construction allowed. // No copy construction allowed.
@ -618,73 +666,92 @@ void BHandler::_ReservedHandler4() {}
// #pragma mark - // #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 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 *copy = NULL;
BMessage *copyMsg = NULL;
if (message) { if (message) {
copyMsg = new BMessage(*message); copy = new BMessage(*message);
copyMsg->what = B_OBSERVER_NOTICE_CHANGE; copy->what = B_OBSERVER_NOTICE_CHANGE;
copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what); copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
} else } 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]; _SendNotices(what, copy);
for (uint32 i = 0; i < handlers.size(); ++i) { _SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
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;
delete copy;
return B_OK; return B_OK;
} }
status_t status_t
_ObserverList::StartObserving(BHandler *handler, unsigned long what) ObserverList::Add(const BHandler *handler, uint32 what)
{ {
if (handler == NULL) if (handler == NULL)
return B_BAD_HANDLER; 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); iter = find(handlers.begin(), handlers.end(), handler);
if (iter != handlers.end()) { if (iter != handlers.end()) {
// TODO: verify // TODO: do we want to have a reference count for this?
return B_OK; return B_OK;
} }
@ -694,15 +761,14 @@ _ObserverList::StartObserving(BHandler *handler, unsigned long what)
status_t status_t
_ObserverList::StartObserving(const BMessenger &messenger, ObserverList::Add(const BMessenger &messenger, uint32 what)
unsigned long what)
{ {
vector<BMessenger> &messengers = fMessengerMap[what]; vector<BMessenger> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iter; vector<BMessenger>::iterator iter;
iter = find(messengers.begin(), messengers.end(), messenger); iter = find(messengers.begin(), messengers.end(), messenger);
if (iter != messengers.end()) { if (iter != messengers.end()) {
// TODO: verify // TODO: do we want to have a reference count for this?
return B_OK; return B_OK;
} }
@ -712,14 +778,19 @@ _ObserverList::StartObserving(const BMessenger &messenger,
status_t status_t
_ObserverList::StopObserving(BHandler *handler, unsigned long what) ObserverList::Remove(const BHandler *handler, uint32 what)
{ {
if (handler == NULL) if (handler == NULL)
return B_BAD_HANDLER; 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); iter = find(handlers.begin(), handlers.end(), handler);
if (iter != handlers.end()) { if (iter != handlers.end()) {
handlers.erase(iter); handlers.erase(iter);
@ -734,14 +805,8 @@ _ObserverList::StopObserving(BHandler *handler, unsigned long what)
status_t status_t
_ObserverList::StopObserving(const BMessenger &messenger, ObserverList::Remove(const BMessenger &messenger, uint32 what)
unsigned long 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> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iter; vector<BMessenger>::iterator iter;
@ -759,7 +824,7 @@ _ObserverList::StopObserving(const BMessenger &messenger,
bool bool
_ObserverList::IsEmpty() ObserverList::IsEmpty()
{ {
return fHandlerMap.empty() && fMessengerMap.empty(); return fHandlerMap.empty() && fMessengerMap.empty();
} }