Index: content/common/file_path_watcher/file_path_watcher_mac.cc |
diff --git a/content/common/file_path_watcher/file_path_watcher_mac.cc b/content/common/file_path_watcher/file_path_watcher_mac.cc |
index 6e89ad1a6b588d792fdd1e8132c6960e4bc4e3d4..c8cfc6b9faa7e05b3bcb3acf52f4169ff7ce476e 100644 |
--- a/content/common/file_path_watcher/file_path_watcher_mac.cc |
+++ b/content/common/file_path_watcher/file_path_watcher_mac.cc |
@@ -32,7 +32,8 @@ namespace { |
const CFAbsoluteTime kEventLatencySeconds = 0.3; |
// Mac-specific file watcher implementation based on the FSEvents API. |
-class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
+ public MessageLoop::DestructionObserver { |
public: |
FilePathWatcherImpl(); |
@@ -49,6 +50,11 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
base::MessageLoopProxy* loop) OVERRIDE; |
virtual void Cancel() OVERRIDE; |
+ // Deletion of the FilePathWatcher will call Cancel() to dispose of this |
+ // object in the right thread. This also observes destruction of the required |
+ // cleanup thread, in case it quits before Cancel() is called. |
+ virtual void WillDestroyCurrentMessageLoop() OVERRIDE; |
+ |
scoped_refptr<base::MessageLoopProxy> run_loop_message_loop() { |
return run_loop_message_loop_; |
} |
@@ -59,6 +65,13 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
// Destroy the event stream. |
void DestroyEventStream(); |
+ // Start observing the destruction of the |run_loop_message_loop_| thread, |
+ // and watching the FSEventStream. |
+ void StartObserverAndEventStream(FSEventStreamEventId start_event); |
+ |
+ // Cleans up and stops observing the |run_loop_message_loop_| thread. |
+ void CancelOnMessageLoopThread() OVERRIDE; |
+ |
// Delegate to notify upon changes. |
scoped_refptr<FilePathWatcher::Delegate> delegate_; |
@@ -79,9 +92,6 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
// Run loop for FSEventStream to run on. |
scoped_refptr<base::MessageLoopProxy> run_loop_message_loop_; |
- // Used to detect early cancellation. |
- bool canceled_; |
- |
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); |
}; |
@@ -120,8 +130,7 @@ void FSEventsCallback(ConstFSEventStreamRef stream, |
// FilePathWatcherImpl implementation: |
FilePathWatcherImpl::FilePathWatcherImpl() |
- : fsevent_stream_(NULL), |
- canceled_(false) { |
+ : fsevent_stream_(NULL) { |
} |
void FilePathWatcherImpl::OnFilePathChanged() { |
@@ -191,15 +200,23 @@ bool FilePathWatcherImpl::Watch(const FilePath& path, |
} |
run_loop_message_loop()->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &FilePathWatcherImpl::UpdateEventStream, |
+ NewRunnableMethod(this, &FilePathWatcherImpl::StartObserverAndEventStream, |
start_event)); |
return true; |
} |
+void FilePathWatcherImpl::StartObserverAndEventStream( |
+ FSEventStreamEventId start_event) { |
+ DCHECK(run_loop_message_loop()->BelongsToCurrentThread()); |
+ MessageLoop::current()->AddDestructionObserver(this); |
+ UpdateEventStream(start_event); |
+} |
+ |
void FilePathWatcherImpl::Cancel() { |
if (!run_loop_message_loop().get()) { |
// Watch was never called, so exit. |
+ set_cancelled(); |
return; |
} |
@@ -207,13 +224,23 @@ void FilePathWatcherImpl::Cancel() { |
// the event stream. |
if (!run_loop_message_loop()->BelongsToCurrentThread()) { |
run_loop_message_loop()->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &FilePathWatcherImpl::Cancel)); |
- return; |
+ new FilePathWatcher::CancelTask(this)); |
+ } else { |
+ CancelOnMessageLoopThread(); |
} |
+} |
- canceled_ = true; |
- if (fsevent_stream_) |
+void FilePathWatcherImpl::CancelOnMessageLoopThread() { |
+ set_cancelled(); |
+ if (fsevent_stream_) { |
DestroyEventStream(); |
+ MessageLoop::current()->RemoveDestructionObserver(this); |
+ delegate_ = NULL; |
+ } |
+} |
+ |
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { |
+ CancelOnMessageLoopThread(); |
} |
void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) { |
@@ -222,7 +249,7 @@ void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) { |
// It can happen that the watcher gets canceled while tasks that call this |
// function are still in flight, so abort if this situation is detected. |
- if (canceled_) |
+ if (is_cancelled()) |
return; |
if (fsevent_stream_) |
@@ -259,7 +286,6 @@ void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) { |
} |
void FilePathWatcherImpl::DestroyEventStream() { |
- DCHECK(run_loop_message_loop()->BelongsToCurrentThread()); |
FSEventStreamStop(fsevent_stream_); |
FSEventStreamUnscheduleFromRunLoop(fsevent_stream_, CFRunLoopGetCurrent(), |
kCFRunLoopDefaultMode); |