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

Side by Side Diff: base/files/file_path_watcher_linux.cc

Issue 2596273003: Remove ref-counting from FilePathWatcher. (Closed)
Patch Set: fix mac build error Created 3 years, 11 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 unified diff | Download patch
« no previous file with comments | « base/files/file_path_watcher_kqueue.cc ('k') | base/files/file_path_watcher_mac.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_path_watcher.h" 5 #include "base/files/file_path_watcher.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <string.h> 9 #include <string.h>
10 #include <sys/inotify.h> 10 #include <sys/inotify.h>
(...skipping 10 matching lines...) Expand all
21 21
22 #include "base/bind.h" 22 #include "base/bind.h"
23 #include "base/containers/hash_tables.h" 23 #include "base/containers/hash_tables.h"
24 #include "base/files/file_enumerator.h" 24 #include "base/files/file_enumerator.h"
25 #include "base/files/file_path.h" 25 #include "base/files/file_path.h"
26 #include "base/files/file_util.h" 26 #include "base/files/file_util.h"
27 #include "base/lazy_instance.h" 27 #include "base/lazy_instance.h"
28 #include "base/location.h" 28 #include "base/location.h"
29 #include "base/logging.h" 29 #include "base/logging.h"
30 #include "base/macros.h" 30 #include "base/macros.h"
31 #include "base/memory/ptr_util.h"
32 #include "base/memory/weak_ptr.h"
31 #include "base/posix/eintr_wrapper.h" 33 #include "base/posix/eintr_wrapper.h"
32 #include "base/single_thread_task_runner.h" 34 #include "base/single_thread_task_runner.h"
33 #include "base/stl_util.h" 35 #include "base/stl_util.h"
34 #include "base/synchronization/lock.h" 36 #include "base/synchronization/lock.h"
35 #include "base/threading/sequenced_task_runner_handle.h" 37 #include "base/threading/sequenced_task_runner_handle.h"
36 #include "base/threading/thread.h" 38 #include "base/threading/thread.h"
37 #include "base/trace_event/trace_event.h" 39 #include "base/trace_event/trace_event.h"
38 40
39 namespace base { 41 namespace base {
40 42
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 86
85 // Flag set to true when startup was successful. 87 // Flag set to true when startup was successful.
86 bool valid_; 88 bool valid_;
87 89
88 DISALLOW_COPY_AND_ASSIGN(InotifyReader); 90 DISALLOW_COPY_AND_ASSIGN(InotifyReader);
89 }; 91 };
90 92
91 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { 93 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
92 public: 94 public:
93 FilePathWatcherImpl(); 95 FilePathWatcherImpl();
96 ~FilePathWatcherImpl() override;
94 97
95 // Called for each event coming from the watch. |fired_watch| identifies the 98 // Called for each event coming from the watch. |fired_watch| identifies the
96 // watch that fired, |child| indicates what has changed, and is relative to 99 // watch that fired, |child| indicates what has changed, and is relative to
97 // the currently watched path for |fired_watch|. 100 // the currently watched path for |fired_watch|.
98 // 101 //
99 // |created| is true if the object appears. 102 // |created| is true if the object appears.
100 // |deleted| is true if the object disappears. 103 // |deleted| is true if the object disappears.
101 // |is_dir| is true if the object is a directory. 104 // |is_dir| is true if the object is a directory.
102 void OnFilePathChanged(InotifyReader::Watch fired_watch, 105 void OnFilePathChanged(InotifyReader::Watch fired_watch,
103 const FilePath::StringType& child, 106 const FilePath::StringType& child,
104 bool created, 107 bool created,
105 bool deleted, 108 bool deleted,
106 bool is_dir); 109 bool is_dir);
107 110
108 protected: 111 private:
109 ~FilePathWatcherImpl() override { 112 void OnFilePathChangedOnOriginSequence(InotifyReader::Watch fired_watch,
110 in_destructor_ = true; 113 const FilePath::StringType& child,
111 CancelOnMessageLoopThreadOrInDestructor(); 114 bool created,
112 } 115 bool deleted,
116 bool is_dir);
113 117
114 private:
115 // Start watching |path| for changes and notify |delegate| on each change. 118 // Start watching |path| for changes and notify |delegate| on each change.
116 // Returns true if watch for |path| has been added successfully. 119 // Returns true if watch for |path| has been added successfully.
117 bool Watch(const FilePath& path, 120 bool Watch(const FilePath& path,
118 bool recursive, 121 bool recursive,
119 const FilePathWatcher::Callback& callback) override; 122 const FilePathWatcher::Callback& callback) override;
120 123
121 // Cancel the watch. This unregisters the instance with InotifyReader. 124 // Cancel the watch. This unregisters the instance with InotifyReader.
122 void Cancel() override; 125 void Cancel() override;
123 void CancelOnMessageLoopThreadOrInDestructor();
124 126
125 // Inotify watches are installed for all directory components of |target_|. 127 // Inotify watches are installed for all directory components of |target_|.
126 // A WatchEntry instance holds: 128 // A WatchEntry instance holds:
127 // - |watch|: the watch descriptor for a component. 129 // - |watch|: the watch descriptor for a component.
128 // - |subdir|: the subdirectory that identifies the next component. 130 // - |subdir|: the subdirectory that identifies the next component.
129 // - For the last component, there is no next component, so it is empty. 131 // - For the last component, there is no next component, so it is empty.
130 // - |linkname|: the target of the symlink. 132 // - |linkname|: the target of the symlink.
131 // - Only if the target being watched is a symbolic link. 133 // - Only if the target being watched is a symbolic link.
132 struct WatchEntry { 134 struct WatchEntry {
133 explicit WatchEntry(const FilePath::StringType& dirname) 135 explicit WatchEntry(const FilePath::StringType& dirname)
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 bool recursive_; 180 bool recursive_;
179 181
180 // The vector of watches and next component names for all path components, 182 // The vector of watches and next component names for all path components,
181 // starting at the root directory. The last entry corresponds to the watch for 183 // starting at the root directory. The last entry corresponds to the watch for
182 // |target_| and always stores an empty next component name in |subdir|. 184 // |target_| and always stores an empty next component name in |subdir|.
183 WatchVector watches_; 185 WatchVector watches_;
184 186
185 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; 187 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_;
186 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; 188 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_;
187 189
188 bool in_destructor_ = false; 190 WeakPtrFactory<FilePathWatcherImpl> weak_factory_;
189 191
190 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 192 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
191 }; 193 };
192 194
193 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd) { 195 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd) {
194 // Make sure the file descriptors are good for use with select(). 196 // Make sure the file descriptors are good for use with select().
195 CHECK_LE(0, inotify_fd); 197 CHECK_LE(0, inotify_fd);
196 CHECK_GT(FD_SETSIZE, inotify_fd); 198 CHECK_GT(FD_SETSIZE, inotify_fd);
197 199
198 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); 200 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 ++watcher) { 307 ++watcher) {
306 (*watcher)->OnFilePathChanged(event->wd, 308 (*watcher)->OnFilePathChanged(event->wd,
307 child, 309 child,
308 event->mask & (IN_CREATE | IN_MOVED_TO), 310 event->mask & (IN_CREATE | IN_MOVED_TO),
309 event->mask & (IN_DELETE | IN_MOVED_FROM), 311 event->mask & (IN_DELETE | IN_MOVED_FROM),
310 event->mask & IN_ISDIR); 312 event->mask & IN_ISDIR);
311 } 313 }
312 } 314 }
313 315
314 FilePathWatcherImpl::FilePathWatcherImpl() 316 FilePathWatcherImpl::FilePathWatcherImpl()
315 : recursive_(false) { 317 : recursive_(false), weak_factory_(this) {}
318
319 FilePathWatcherImpl::~FilePathWatcherImpl() {
320 DCHECK(!task_runner() || task_runner()->RunsTasksOnCurrentThread());
316 } 321 }
317 322
318 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, 323 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
319 const FilePath::StringType& child, 324 const FilePath::StringType& child,
320 bool created, 325 bool created,
321 bool deleted, 326 bool deleted,
322 bool is_dir) { 327 bool is_dir) {
323 if (!task_runner()->RunsTasksOnCurrentThread()) { 328 DCHECK(!task_runner()->RunsTasksOnCurrentThread());
324 // Switch to task_runner() to access |watches_| safely.
325 task_runner()->PostTask(FROM_HERE,
326 Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
327 fired_watch, child, created, deleted, is_dir));
328 return;
329 }
330 329
331 // Check to see if CancelOnMessageLoopThreadOrInDestructor() has already been 330 // This method is invoked on the Inotify thread. Switch to task_runner() to
332 // called. May happen when code flow reaches here from the PostTask() above. 331 // access |watches_| safely. Use a WeakPtr to prevent the callback from
333 if (watches_.empty()) { 332 // running after |this| is destroyed (i.e. after the watch is cancelled).
334 DCHECK(target_.empty()); 333 task_runner()->PostTask(
335 return; 334 FROM_HERE, Bind(&FilePathWatcherImpl::OnFilePathChangedOnOriginSequence,
336 } 335 weak_factory_.GetWeakPtr(), fired_watch, child, created,
336 deleted, is_dir));
337 }
337 338
339 void FilePathWatcherImpl::OnFilePathChangedOnOriginSequence(
340 InotifyReader::Watch fired_watch,
341 const FilePath::StringType& child,
342 bool created,
343 bool deleted,
344 bool is_dir) {
338 DCHECK(task_runner()->RunsTasksOnCurrentThread()); 345 DCHECK(task_runner()->RunsTasksOnCurrentThread());
346 DCHECK(!watches_.empty());
339 DCHECK(HasValidWatchVector()); 347 DCHECK(HasValidWatchVector());
340 348
341 // Used below to avoid multiple recursive updates. 349 // Used below to avoid multiple recursive updates.
342 bool did_update = false; 350 bool did_update = false;
343 351
344 // Find the entry in |watches_| that corresponds to |fired_watch|. 352 // Find the entry in |watches_| that corresponds to |fired_watch|.
345 for (size_t i = 0; i < watches_.size(); ++i) { 353 for (size_t i = 0; i < watches_.size(); ++i) {
346 const WatchEntry& watch_entry = watches_[i]; 354 const WatchEntry& watch_entry = watches_[i];
347 if (fired_watch != watch_entry.watch) 355 if (fired_watch != watch_entry.watch)
348 continue; 356 continue;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 target_.GetComponents(&comps); 438 target_.GetComponents(&comps);
431 DCHECK(!comps.empty()); 439 DCHECK(!comps.empty());
432 for (size_t i = 1; i < comps.size(); ++i) 440 for (size_t i = 1; i < comps.size(); ++i)
433 watches_.push_back(WatchEntry(comps[i])); 441 watches_.push_back(WatchEntry(comps[i]));
434 watches_.push_back(WatchEntry(FilePath::StringType())); 442 watches_.push_back(WatchEntry(FilePath::StringType()));
435 UpdateWatches(); 443 UpdateWatches();
436 return true; 444 return true;
437 } 445 }
438 446
439 void FilePathWatcherImpl::Cancel() { 447 void FilePathWatcherImpl::Cancel() {
440 if (callback_.is_null()) { 448 if (!callback_) {
441 // Watch was never called, or the message_loop() thread is already gone. 449 // Watch() was never called.
442 set_cancelled(); 450 set_cancelled();
443 return; 451 return;
444 } 452 }
445 453
446 // Switch to the task_runner() if necessary so we can access |watches_|. 454 DCHECK(task_runner()->RunsTasksOnCurrentThread());
447 if (!task_runner()->RunsTasksOnCurrentThread()) { 455 DCHECK(!is_cancelled());
448 task_runner()->PostTask(
449 FROM_HERE,
450 Bind(&FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor,
451 this));
452 } else {
453 CancelOnMessageLoopThreadOrInDestructor();
454 }
455 }
456
457 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() {
458 DCHECK(in_destructor_ || task_runner()->RunsTasksOnCurrentThread());
459
460 if (is_cancelled())
461 return;
462 456
463 set_cancelled(); 457 set_cancelled();
464 458 callback_.Reset();
465 if (!callback_.is_null())
466 callback_.Reset();
467 459
468 for (size_t i = 0; i < watches_.size(); ++i) 460 for (size_t i = 0; i < watches_.size(); ++i)
469 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this); 461 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this);
470 watches_.clear(); 462 watches_.clear();
471 target_.clear(); 463 target_.clear();
472 464 RemoveRecursiveWatches();
473 if (recursive_)
474 RemoveRecursiveWatches();
475 } 465 }
476 466
477 void FilePathWatcherImpl::UpdateWatches() { 467 void FilePathWatcherImpl::UpdateWatches() {
478 // Ensure this runs on the task_runner() exclusively in order to avoid 468 // Ensure this runs on the task_runner() exclusively in order to avoid
479 // concurrency issues. 469 // concurrency issues.
480 DCHECK(task_runner()->RunsTasksOnCurrentThread()); 470 DCHECK(task_runner()->RunsTasksOnCurrentThread());
481 DCHECK(HasValidWatchVector()); 471 DCHECK(HasValidWatchVector());
482 472
483 // Walk the list of watches and update them as we go. 473 // Walk the list of watches and update them as we go.
484 FilePath path(FILE_PATH_LITERAL("/")); 474 FilePath path(FILE_PATH_LITERAL("/"));
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 if (watches_[i].subdir.empty()) 640 if (watches_[i].subdir.empty())
651 return false; 641 return false;
652 } 642 }
653 return watches_.back().subdir.empty(); 643 return watches_.back().subdir.empty();
654 } 644 }
655 645
656 } // namespace 646 } // namespace
657 647
658 FilePathWatcher::FilePathWatcher() { 648 FilePathWatcher::FilePathWatcher() {
659 sequence_checker_.DetachFromSequence(); 649 sequence_checker_.DetachFromSequence();
660 impl_ = new FilePathWatcherImpl(); 650 impl_ = MakeUnique<FilePathWatcherImpl>();
661 } 651 }
662 652
663 } // namespace base 653 } // namespace base
OLDNEW
« no previous file with comments | « base/files/file_path_watcher_kqueue.cc ('k') | base/files/file_path_watcher_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698