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

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

Issue 2123053004: No destruction observer in file_path_watcher_linux.cc (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 3 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 | « no previous file | no next file » | 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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 81
82 // File descriptor returned by inotify_init. 82 // File descriptor returned by inotify_init.
83 const int inotify_fd_; 83 const int inotify_fd_;
84 84
85 // Flag set to true when startup was successful. 85 // Flag set to true when startup was successful.
86 bool valid_; 86 bool valid_;
87 87
88 DISALLOW_COPY_AND_ASSIGN(InotifyReader); 88 DISALLOW_COPY_AND_ASSIGN(InotifyReader);
89 }; 89 };
90 90
91 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 91 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
92 public MessageLoop::DestructionObserver {
93 public: 92 public:
94 FilePathWatcherImpl(); 93 FilePathWatcherImpl();
95 94
96 // Called for each event coming from the watch. |fired_watch| identifies the 95 // Called for each event coming from the watch. |fired_watch| identifies the
97 // watch that fired, |child| indicates what has changed, and is relative to 96 // watch that fired, |child| indicates what has changed, and is relative to
98 // the currently watched path for |fired_watch|. 97 // the currently watched path for |fired_watch|.
99 // 98 //
100 // |created| is true if the object appears. 99 // |created| is true if the object appears.
101 // |deleted| is true if the object disappears. 100 // |deleted| is true if the object disappears.
102 // |is_dir| is true if the object is a directory. 101 // |is_dir| is true if the object is a directory.
103 void OnFilePathChanged(InotifyReader::Watch fired_watch, 102 void OnFilePathChanged(InotifyReader::Watch fired_watch,
104 const FilePath::StringType& child, 103 const FilePath::StringType& child,
105 bool created, 104 bool created,
106 bool deleted, 105 bool deleted,
107 bool is_dir); 106 bool is_dir);
108 107
109 protected: 108 protected:
110 ~FilePathWatcherImpl() override {} 109 ~FilePathWatcherImpl() override {
110 in_destructor_ = true;
111 CancelOnMessageLoopThreadOrInDestructor();
112 }
111 113
112 private: 114 private:
113 // Start watching |path| for changes and notify |delegate| on each change. 115 // Start watching |path| for changes and notify |delegate| on each change.
114 // Returns true if watch for |path| has been added successfully. 116 // Returns true if watch for |path| has been added successfully.
115 bool Watch(const FilePath& path, 117 bool Watch(const FilePath& path,
116 bool recursive, 118 bool recursive,
117 const FilePathWatcher::Callback& callback) override; 119 const FilePathWatcher::Callback& callback) override;
118 120
119 // Cancel the watch. This unregisters the instance with InotifyReader. 121 // Cancel the watch. This unregisters the instance with InotifyReader.
120 void Cancel() override; 122 void Cancel() override;
121
122 // Cleans up and stops observing the message_loop() thread.
123 void CancelOnMessageLoopThread() override; 123 void CancelOnMessageLoopThread() override;
124 124 void CancelOnMessageLoopThreadOrInDestructor();
125 // Deletion of the FilePathWatcher will call Cancel() to dispose of this
126 // object in the right thread. This also observes destruction of the required
127 // cleanup thread, in case it quits before Cancel() is called.
128 void WillDestroyCurrentMessageLoop() override;
129 125
130 // Inotify watches are installed for all directory components of |target_|. 126 // Inotify watches are installed for all directory components of |target_|.
131 // A WatchEntry instance holds: 127 // A WatchEntry instance holds:
132 // - |watch|: the watch descriptor for a component. 128 // - |watch|: the watch descriptor for a component.
133 // - |subdir|: the subdirectory that identifies the next component. 129 // - |subdir|: the subdirectory that identifies the next component.
134 // - For the last component, there is no next component, so it is empty. 130 // - For the last component, there is no next component, so it is empty.
135 // - |linkname|: the target of the symlink. 131 // - |linkname|: the target of the symlink.
136 // - Only if the target being watched is a symbolic link. 132 // - Only if the target being watched is a symbolic link.
137 struct WatchEntry { 133 struct WatchEntry {
138 explicit WatchEntry(const FilePath::StringType& dirname) 134 explicit WatchEntry(const FilePath::StringType& dirname)
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 bool recursive_; 179 bool recursive_;
184 180
185 // The vector of watches and next component names for all path components, 181 // The vector of watches and next component names for all path components,
186 // starting at the root directory. The last entry corresponds to the watch for 182 // starting at the root directory. The last entry corresponds to the watch for
187 // |target_| and always stores an empty next component name in |subdir|. 183 // |target_| and always stores an empty next component name in |subdir|.
188 WatchVector watches_; 184 WatchVector watches_;
189 185
190 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; 186 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_;
191 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; 187 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_;
192 188
189 bool in_destructor_ = false;
190
193 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 191 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
194 }; 192 };
195 193
196 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd) { 194 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd) {
197 // Make sure the file descriptors are good for use with select(). 195 // Make sure the file descriptors are good for use with select().
198 CHECK_LE(0, inotify_fd); 196 CHECK_LE(0, inotify_fd);
199 CHECK_GT(FD_SETSIZE, inotify_fd); 197 CHECK_GT(FD_SETSIZE, inotify_fd);
200 198
201 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); 199 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
202 200
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 bool FilePathWatcherImpl::Watch(const FilePath& path, 420 bool FilePathWatcherImpl::Watch(const FilePath& path,
423 bool recursive, 421 bool recursive,
424 const FilePathWatcher::Callback& callback) { 422 const FilePathWatcher::Callback& callback) {
425 DCHECK(target_.empty()); 423 DCHECK(target_.empty());
426 DCHECK(MessageLoopForIO::current()); 424 DCHECK(MessageLoopForIO::current());
427 425
428 set_task_runner(ThreadTaskRunnerHandle::Get()); 426 set_task_runner(ThreadTaskRunnerHandle::Get());
429 callback_ = callback; 427 callback_ = callback;
430 target_ = path; 428 target_ = path;
431 recursive_ = recursive; 429 recursive_ = recursive;
432 MessageLoop::current()->AddDestructionObserver(this);
433 430
434 std::vector<FilePath::StringType> comps; 431 std::vector<FilePath::StringType> comps;
435 target_.GetComponents(&comps); 432 target_.GetComponents(&comps);
436 DCHECK(!comps.empty()); 433 DCHECK(!comps.empty());
437 for (size_t i = 1; i < comps.size(); ++i) 434 for (size_t i = 1; i < comps.size(); ++i)
438 watches_.push_back(WatchEntry(comps[i])); 435 watches_.push_back(WatchEntry(comps[i]));
439 watches_.push_back(WatchEntry(FilePath::StringType())); 436 watches_.push_back(WatchEntry(FilePath::StringType()));
440 UpdateWatches(); 437 UpdateWatches();
441 return true; 438 return true;
442 } 439 }
443 440
444 void FilePathWatcherImpl::Cancel() { 441 void FilePathWatcherImpl::Cancel() {
445 if (callback_.is_null()) { 442 if (callback_.is_null()) {
446 // Watch was never called, or the message_loop() thread is already gone. 443 // Watch was never called, or the message_loop() thread is already gone.
447 set_cancelled(); 444 set_cancelled();
448 return; 445 return;
449 } 446 }
450 447
451 // Switch to the message_loop() if necessary so we can access |watches_|. 448 // Switch to the message_loop() if necessary so we can access |watches_|.
452 if (!task_runner()->BelongsToCurrentThread()) { 449 if (!task_runner()->BelongsToCurrentThread()) {
453 task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch, 450 task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
454 make_scoped_refptr(this))); 451 make_scoped_refptr(this)));
455 } else { 452 } else {
456 CancelOnMessageLoopThread(); 453 CancelOnMessageLoopThread();
457 } 454 }
458 } 455 }
459 456
460 void FilePathWatcherImpl::CancelOnMessageLoopThread() { 457 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
461 DCHECK(task_runner()->BelongsToCurrentThread()); 458 CancelOnMessageLoopThreadOrInDestructor();
459 }
460
461 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() {
462 DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread());
463
464 if (is_cancelled())
465 return;
466
462 set_cancelled(); 467 set_cancelled();
463 468
464 if (!callback_.is_null()) { 469 if (!callback_.is_null())
465 MessageLoop::current()->RemoveDestructionObserver(this);
466 callback_.Reset(); 470 callback_.Reset();
467 }
468 471
469 for (size_t i = 0; i < watches_.size(); ++i) 472 for (size_t i = 0; i < watches_.size(); ++i)
470 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this); 473 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this);
471 watches_.clear(); 474 watches_.clear();
472 target_.clear(); 475 target_.clear();
473 476
474 if (recursive_) 477 if (recursive_)
475 RemoveRecursiveWatches(); 478 RemoveRecursiveWatches();
476 } 479 }
477 480
478 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
479 CancelOnMessageLoopThread();
480 }
481
482 void FilePathWatcherImpl::UpdateWatches() { 481 void FilePathWatcherImpl::UpdateWatches() {
483 // Ensure this runs on the message_loop() exclusively in order to avoid 482 // Ensure this runs on the message_loop() exclusively in order to avoid
484 // concurrency issues. 483 // concurrency issues.
485 DCHECK(task_runner()->BelongsToCurrentThread()); 484 DCHECK(task_runner()->BelongsToCurrentThread());
486 DCHECK(HasValidWatchVector()); 485 DCHECK(HasValidWatchVector());
487 486
488 // Walk the list of watches and update them as we go. 487 // Walk the list of watches and update them as we go.
489 FilePath path(FILE_PATH_LITERAL("/")); 488 FilePath path(FILE_PATH_LITERAL("/"));
490 for (size_t i = 0; i < watches_.size(); ++i) { 489 for (size_t i = 0; i < watches_.size(); ++i) {
491 WatchEntry& watch_entry = watches_[i]; 490 WatchEntry& watch_entry = watches_[i];
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 return watches_.back().subdir.empty(); 651 return watches_.back().subdir.empty();
653 } 652 }
654 653
655 } // namespace 654 } // namespace
656 655
657 FilePathWatcher::FilePathWatcher() { 656 FilePathWatcher::FilePathWatcher() {
658 impl_ = new FilePathWatcherImpl(); 657 impl_ = new FilePathWatcherImpl();
659 } 658 }
660 659
661 } // namespace base 660 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698