Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3649)

Unified Diff: chrome/browser/file_path_watcher/file_path_watcher_win.cc

Issue 6697020: Fixed shutdown concurrency issues in FilePathWatcher. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698