Index: base/files/file_path_watcher_linux.cc |
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc |
index bf17cde45f7036aea326d33190b478eb3d1df8d2..a129bc3c6aa036e175f18f67859fad299caf3082 100644 |
--- a/base/files/file_path_watcher_linux.cc |
+++ b/base/files/file_path_watcher_linux.cc |
@@ -28,6 +28,7 @@ |
#include "base/location.h" |
#include "base/logging.h" |
#include "base/macros.h" |
+#include "base/memory/weak_ptr.h" |
#include "base/posix/eintr_wrapper.h" |
#include "base/single_thread_task_runner.h" |
#include "base/stl_util.h" |
@@ -106,12 +107,15 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
bool is_dir); |
protected: |
- ~FilePathWatcherImpl() override { |
- in_destructor_ = true; |
- CancelOnMessageLoopThreadOrInDestructor(); |
- } |
+ ~FilePathWatcherImpl() override = default; |
private: |
+ void OnFilePathChangedOnOriginSequence(InotifyReader::Watch fired_watch, |
+ const FilePath::StringType& child, |
+ bool created, |
+ bool deleted, |
+ bool is_dir); |
+ |
// Start watching |path| for changes and notify |delegate| on each change. |
// Returns true if watch for |path| has been added successfully. |
bool Watch(const FilePath& path, |
@@ -120,7 +124,6 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
// Cancel the watch. This unregisters the instance with InotifyReader. |
void Cancel() override; |
- void CancelOnMessageLoopThreadOrInDestructor(); |
// Inotify watches are installed for all directory components of |target_|. |
// A WatchEntry instance holds: |
@@ -185,7 +188,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { |
hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; |
std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; |
- bool in_destructor_ = false; |
+ WeakPtrFactory<FilePathWatcherImpl> weak_factory_; |
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); |
}; |
@@ -312,30 +315,31 @@ void InotifyReader::OnInotifyEvent(const inotify_event* event) { |
} |
FilePathWatcherImpl::FilePathWatcherImpl() |
- : recursive_(false) { |
-} |
+ : recursive_(false), weak_factory_(this) {} |
void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, |
const FilePath::StringType& child, |
bool created, |
bool deleted, |
bool is_dir) { |
- if (!task_runner()->BelongsToCurrentThread()) { |
- // Switch to task_runner() to access |watches_| safely. |
- task_runner()->PostTask(FROM_HERE, |
- Bind(&FilePathWatcherImpl::OnFilePathChanged, this, |
- fired_watch, child, created, deleted, is_dir)); |
- return; |
- } |
- |
- // Check to see if CancelOnMessageLoopThreadOrInDestructor() has already been |
- // called. May happen when code flow reaches here from the PostTask() above. |
- if (watches_.empty()) { |
- DCHECK(target_.empty()); |
- return; |
- } |
+ // This method is invoked on the Inotify thread. Switch to task_runner() to |
gab
2016/12/23 16:05:06
DCHECK not on TaskRunner thread?
fdoray
2016/12/23 21:16:07
Done.
|
+ // access |watches_| safely. Use a WeakPtr to prevent the callback from |
+ // running after the destructor is invoked (i.e. after the watch is |
+ // cancelled). |
fdoray
2016/12/23 15:34:45
Cancel() is only called from ~FilePathWatcher http
gab
2016/12/23 16:05:06
Ah cool now I see why you'd made all those changes
fdoray
2016/12/23 21:16:07
Done.
|
+ task_runner()->PostTask( |
+ FROM_HERE, Bind(&FilePathWatcherImpl::OnFilePathChangedOnOriginSequence, |
+ weak_factory_.GetWeakPtr(), fired_watch, child, created, |
gab
2016/12/23 16:05:06
It's not safe to vend WeakPtr from one sequence an
fdoray
2016/12/23 21:16:07
Actually, the WeakPtrs of a given WeakPtrFactory a
gab
2017/01/05 21:22:53
Good point, and it's implicit that FilePathWatcher
|
+ deleted, is_dir)); |
+} |
+void FilePathWatcherImpl::OnFilePathChangedOnOriginSequence( |
+ InotifyReader::Watch fired_watch, |
+ const FilePath::StringType& child, |
+ bool created, |
+ bool deleted, |
+ bool is_dir) { |
DCHECK(task_runner()->BelongsToCurrentThread()); |
+ DCHECK(!watches_.empty()); |
DCHECK(HasValidWatchVector()); |
// Used below to avoid multiple recursive updates. |
@@ -437,41 +441,23 @@ bool FilePathWatcherImpl::Watch(const FilePath& path, |
} |
void FilePathWatcherImpl::Cancel() { |
- if (callback_.is_null()) { |
- // Watch was never called, or the message_loop() thread is already gone. |
+ if (!callback_) { |
+ // Watch() was never called. |
set_cancelled(); |
return; |
} |
- // Switch to the task_runner() if necessary so we can access |watches_|. |
- if (!task_runner()->BelongsToCurrentThread()) { |
- task_runner()->PostTask( |
- FROM_HERE, |
- Bind(&FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor, |
- this)); |
- } else { |
- CancelOnMessageLoopThreadOrInDestructor(); |
- } |
-} |
- |
-void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() { |
- DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread()); |
- |
- if (is_cancelled()) |
- return; |
+ DCHECK(task_runner()->BelongsToCurrentThread()); |
+ DCHECK(!is_cancelled()); |
set_cancelled(); |
- |
- if (!callback_.is_null()) |
- callback_.Reset(); |
+ callback_.Reset(); |
for (size_t i = 0; i < watches_.size(); ++i) |
g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this); |
watches_.clear(); |
target_.clear(); |
- |
- if (recursive_) |
- RemoveRecursiveWatches(); |
+ RemoveRecursiveWatches(); |
} |
void FilePathWatcherImpl::UpdateWatches() { |