Index: chrome/browser/file_path_watcher/file_path_watcher_win.cc |
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_win.cc b/chrome/browser/file_path_watcher/file_path_watcher_win.cc |
index c2f49b937ca55a352853e9b79e44a2ffcad28e2e..19668d40b453d86488309379efd5aa9a00ec460c 100644 |
--- a/chrome/browser/file_path_watcher/file_path_watcher_win.cc |
+++ b/chrome/browser/file_path_watcher/file_path_watcher_win.cc |
@@ -10,11 +10,13 @@ |
#include "base/ref_counted.h" |
#include "base/time.h" |
#include "base/win/object_watcher.h" |
+#include "content/browser/browser_thread.h" |
namespace { |
class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
- public base::win::ObjectWatcher::Delegate { |
+ public base::win::ObjectWatcher::Delegate, |
+ public MessageLoop::DestructionObserver { |
public: |
FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} |
@@ -24,6 +26,10 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
// Callback from MessageLoopForIO. |
virtual void OnObjectSignaled(HANDLE object); |
+ // MessageLoop::DestructionObserver overrides. |
+ // This allows cleaning up when the File thread is shutting down. |
+ virtual void WillDestroyCurrentMessageLoop(); |
+ |
private: |
virtual ~FilePathWatcherImpl(); |
@@ -39,6 +45,9 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
// Destroy the watch handle. |
void DestroyWatch(); |
+ // Start observing the destruction of the File thread. |
+ void StartWatchingAndObserving(); |
+ |
// Delegate to notify upon changes. |
scoped_refptr<FilePathWatcher::Delegate> delegate_; |
@@ -71,11 +80,23 @@ bool FilePathWatcherImpl::Watch(const FilePath& path, |
if (!UpdateWatch()) |
return false; |
- watcher_.StartWatching(handle_, this); |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
Mattias Nissler (ping if slow)
2011/03/16 09:41:14
We are guaranteed to run on the file thread here.
Joao da Silva
2011/03/18 16:09:17
Done.
|
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &FilePathWatcherImpl::StartWatchingAndObserving)); |
+ } else { |
+ StartWatchingAndObserving(); |
+ } |
return true; |
} |
+void FilePathWatcherImpl::StartWatchingAndObserving() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ MessageLoop::current()->AddDestructionObserver(this); |
+ watcher_.StartWatching(handle_, this); |
+} |
+ |
void FilePathWatcherImpl::Cancel() { |
// Switch to the file thread if necessary so we can stop |watcher_|. |
if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
@@ -88,6 +109,26 @@ void FilePathWatcherImpl::Cancel() { |
DestroyWatch(); |
} |
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { |
+ if (handle_ != INVALID_HANDLE_VALUE) |
+ DestroyWatch(); |
+} |
+ |
+FilePathWatcherImpl::~FilePathWatcherImpl() { |
+ // Deletion of the FilePathWatcher will call Cancel() to dispose of this |
+ // object in the right thread. In that case, |this| is already cleaned up |
+ // and |handle_| is INVALID_HANDLE_VALUE. |
+ // |
+ // However, Cancel() might have to switch threads and its Task might never be |
+ // called during shutdown. In that case, either |this| gets notified that the |
+ // thread is shutting down and cleans up, or the Task (that wasn't executed) |
+ // is deleted and releases a handle on |this|, triggering the dtor. |
+ // In either case, we are on the right thread. |
+ |
+ if (handle_ != INVALID_HANDLE_VALUE) |
+ DestroyWatch(); |
Mattias Nissler (ping if slow)
2011/03/16 09:41:14
Same comment as for Mac: Shouldn't we already have
Joao da Silva
2011/03/18 16:09:17
Same reply as for Mac: this might be required when
|
+} |
+ |
void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { |
DCHECK(object == handle_); |
// Make sure we stay alive through the body of this function. |
@@ -137,11 +178,6 @@ void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { |
watcher_.StartWatching(handle_, this); |
} |
-FilePathWatcherImpl::~FilePathWatcherImpl() { |
- if (handle_ != INVALID_HANDLE_VALUE) |
- DestroyWatch(); |
-} |
- |
// static |
bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, |
HANDLE* handle) { |
@@ -235,6 +271,9 @@ void FilePathWatcherImpl::DestroyWatch() { |
watcher_.StopWatching(); |
FindCloseChangeNotification(handle_); |
handle_ = INVALID_HANDLE_VALUE; |
+ |
+ MessageLoop::current()->RemoveDestructionObserver(this); |
Mattias Nissler (ping if slow)
2011/03/16 09:41:14
Oh, so what happens when UpdateWatch is executed m
Joao da Silva
2011/03/18 16:09:17
Same mistake as on the Mac version.
|
+ delegate_ = NULL; |
} |
} // namespace |