* StartWatching() now takes an optional BLooper pointer. This looper will

then be used for receiving node monitoring messages.
* Reenabled using be_app as default BLooper if the API user does not provide
  one. I think the problem that Stefano needed to work aroung in r23995 was
  actually caused by the incorrect locking (an never unlocking) of the looper
  before calling PathHandler::Quit().
->If I understand correctly, this code as supposed to work around the possible
  situation that the looper holding those PathHandlers may have already quit,
  leaving stale PathHandler pointers behind. But that case was not prevented
  by the old code anyways, since one would have had to access freed memory to
  even get the stale BLooper pointer. The real fix would be to store the
  BLooper pointer with each PathHandler so that the possible gone-ness of
  those loopers could be checked independent of accessing the PathHandler
  pointer. (The whole problem is that PathHandler adds itself to the BLooper
  and if the looper quits, it will free all its attached handlers.)
* Introduced a global fallback BLooper for the case that no BApplication is
  running, which resolves a TODO.

All this is yet untested, but should have a good chance of working.
(Famous last words...)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26843 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2008-08-06 16:56:24 +00:00
parent 20a8524cc9
commit f7c226f467
2 changed files with 72 additions and 33 deletions
+5 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2007, Haiku Inc. All Rights Reserved.
* Copyright 2007-2008, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _PATH_MONITOR_H
@@ -20,7 +20,8 @@ namespace BPrivate {
class BPathMonitor {
public:
static status_t StartWatching(const char* path, uint32 flags,
BMessenger target);
BMessenger target,
BLooper* useLooper = NULL);
static status_t StopWatching(const char* path,
BMessenger target);
@@ -30,7 +31,8 @@ private:
BPathMonitor();
~BPathMonitor();
static status_t _InitIfNeeded();
static status_t _InitLockerIfNeeded();
static status_t _InitLooperIfNeeded();
};
} // namespace BPrivate
+67 -30
View File
@@ -1,9 +1,10 @@
/*
* Copyright 2007, Haiku Inc. All Rights Reserved.
* Copyright 2007-2008, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
* Stephan Aßmus <[email protected]>
*/
@@ -22,6 +23,7 @@
#include <String.h>
#include <map>
#include <new>
#include <set>
#undef TRACE
@@ -34,6 +36,7 @@
using namespace BPrivate;
using namespace std;
using std::nothrow; // TODO: Remove this line if the above line is enough.
#define WATCH_NODE_FLAG_MASK 0x00ff
@@ -72,7 +75,8 @@ typedef map<BMessenger, watcher*> WatcherMap;
class PathHandler : public BHandler {
public:
PathHandler(const char* path, uint32 flags, BMessenger target);
PathHandler(const char* path, uint32 flags, BMessenger target,
BLooper* looper);
virtual ~PathHandler();
status_t InitCheck() const;
@@ -112,7 +116,6 @@ class PathHandler : public BHandler {
BMessenger fTarget;
uint32 fFlags;
status_t fStatus;
bool fOwnsLooper;
DirectorySet fDirectories;
FileSet fFiles;
};
@@ -120,6 +123,7 @@ class PathHandler : public BHandler {
static WatcherMap sWatchers;
static BLocker* sLocker = NULL;
static BLooper* sLooper = NULL;
static status_t
@@ -159,11 +163,11 @@ operator<(const watched_directory& a, const watched_directory& b)
// #pragma mark -
PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target)
PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target,
BLooper* looper)
: BHandler(path),
fTarget(target),
fFlags(flags),
fOwnsLooper(false)
fFlags(flags)
{
if (path == NULL || !path[0]) {
fStatus = B_BAD_VALUE;
@@ -176,13 +180,6 @@ PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target)
if (fStatus < B_OK)
return;
BLooper* looper;
// TODO: only have a single global looper!
// TODO: Use BLooper::LooperForThread(find_looper(NULL)) ?
looper = new BLooper("PathMonitor looper");
looper->Run();
fOwnsLooper = true;
looper->Lock();
looper->AddHandler(this);
looper->Unlock();
@@ -212,13 +209,8 @@ PathHandler::InitCheck() const
void
PathHandler::Quit()
{
if (!LockLooper())
return;
BMessenger me(this);
me.SendMessage(B_QUIT_REQUESTED);
UnlockLooper();
}
@@ -488,18 +480,15 @@ PathHandler::MessageReceived(BMessage* message)
case B_QUIT_REQUESTED:
{
// Obviously the looper is still valid and running
// when we receive the message here, it is also currently
// locked, because it is processing the message.
BLooper* looper = Looper();
bool ownsLooper = fOwnsLooper;
stop_watching(this);
looper->RemoveHandler(this);
delete this;
if (ownsLooper) {
looper->Lock();
looper->Quit();
}
return;
}
@@ -773,7 +762,7 @@ BPathMonitor::~BPathMonitor()
/*static*/ status_t
BPathMonitor::_InitIfNeeded()
BPathMonitor::_InitLockerIfNeeded()
{
static vint32 lock = 0;
@@ -782,7 +771,9 @@ BPathMonitor::_InitIfNeeded()
while (sLocker == NULL) {
if (atomic_add(&lock, 1) == 0) {
sLocker = new BLocker("path monitor");
sLocker = new (nothrow) BLocker("path monitor");
if (sLocker == NULL)
return B_NO_MEMORY;
}
snooze(5000);
}
@@ -792,12 +783,53 @@ BPathMonitor::_InitIfNeeded()
/*static*/ status_t
BPathMonitor::StartWatching(const char* path, uint32 flags, BMessenger target)
BPathMonitor::_InitLooperIfNeeded()
{
status_t status = _InitIfNeeded();
static vint32 lock = 0;
if (sLooper != NULL)
return B_OK;
while (sLooper == NULL) {
if (atomic_add(&lock, 1) == 0) {
// first thread initializes the global looper
sLooper = new (nothrow) BLooper("PathMonitor looper");
if (sLooper == NULL)
return B_NO_MEMORY;
thread_id thread = sLooper->Run();
if (thread < B_OK)
return (status_t)thread;
}
snooze(5000);
}
return sLooper->Thread() >= 0 ? B_OK : B_ERROR;
}
/*static*/ status_t
BPathMonitor::StartWatching(const char* path, uint32 flags, BMessenger target,
BLooper* looper)
{
status_t status = _InitLockerIfNeeded();
if (status != B_OK)
return status;
// Check which BLooper should be used to receive node monitoring messages.
// If no looper is given, prefer the BApplication if it is running,
// otherwise use a global BLooper just for node monitoring.
if (looper == NULL) {
if (be_app)
looper = be_app;
else {
// only use the global looper if no BApplication is running
status = _InitLooperIfNeeded();
if (status < B_OK)
return status;
looper = sLooper;
}
}
BAutolock _(sLocker);
WatcherMap::iterator iterator = sWatchers.find(target);
@@ -805,13 +837,18 @@ BPathMonitor::StartWatching(const char* path, uint32 flags, BMessenger target)
if (iterator != sWatchers.end())
watcher = iterator->second;
PathHandler* handler = new PathHandler(path, flags, target);
PathHandler* handler = new (nothrow) PathHandler(path, flags, target,
looper);
if (handler == NULL)
return B_NO_MEMORY;
status = handler->InitCheck();
if (status < B_OK)
return status;
if (watcher == NULL) {
watcher = new BPrivate::watcher;
watcher = new (nothrow) BPrivate::watcher;
if (watcher == NULL)
return B_NO_MEMORY;
sWatchers[target] = watcher;
}