| OLD | NEW |
| 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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 113 |
| 114 private: | 114 private: |
| 115 // Start watching |path| for changes and notify |delegate| on each change. | 115 // Start watching |path| for changes and notify |delegate| on each change. |
| 116 // Returns true if watch for |path| has been added successfully. | 116 // Returns true if watch for |path| has been added successfully. |
| 117 bool Watch(const FilePath& path, | 117 bool Watch(const FilePath& path, |
| 118 bool recursive, | 118 bool recursive, |
| 119 const FilePathWatcher::Callback& callback) override; | 119 const FilePathWatcher::Callback& callback) override; |
| 120 | 120 |
| 121 // Cancel the watch. This unregisters the instance with InotifyReader. | 121 // Cancel the watch. This unregisters the instance with InotifyReader. |
| 122 void Cancel() override; | 122 void Cancel() override; |
| 123 void CancelOnMessageLoopThread() override; | |
| 124 void CancelOnMessageLoopThreadOrInDestructor(); | 123 void CancelOnMessageLoopThreadOrInDestructor(); |
| 125 | 124 |
| 126 // Inotify watches are installed for all directory components of |target_|. | 125 // Inotify watches are installed for all directory components of |target_|. |
| 127 // A WatchEntry instance holds: | 126 // A WatchEntry instance holds: |
| 128 // - |watch|: the watch descriptor for a component. | 127 // - |watch|: the watch descriptor for a component. |
| 129 // - |subdir|: the subdirectory that identifies the next component. | 128 // - |subdir|: the subdirectory that identifies the next component. |
| 130 // - For the last component, there is no next component, so it is empty. | 129 // - For the last component, there is no next component, so it is empty. |
| 131 // - |linkname|: the target of the symlink. | 130 // - |linkname|: the target of the symlink. |
| 132 // - Only if the target being watched is a symbolic link. | 131 // - Only if the target being watched is a symbolic link. |
| 133 struct WatchEntry { | 132 struct WatchEntry { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 bool deleted, | 321 bool deleted, |
| 323 bool is_dir) { | 322 bool is_dir) { |
| 324 if (!task_runner()->BelongsToCurrentThread()) { | 323 if (!task_runner()->BelongsToCurrentThread()) { |
| 325 // Switch to task_runner() to access |watches_| safely. | 324 // Switch to task_runner() to access |watches_| safely. |
| 326 task_runner()->PostTask(FROM_HERE, | 325 task_runner()->PostTask(FROM_HERE, |
| 327 Bind(&FilePathWatcherImpl::OnFilePathChanged, this, | 326 Bind(&FilePathWatcherImpl::OnFilePathChanged, this, |
| 328 fired_watch, child, created, deleted, is_dir)); | 327 fired_watch, child, created, deleted, is_dir)); |
| 329 return; | 328 return; |
| 330 } | 329 } |
| 331 | 330 |
| 332 // Check to see if CancelOnMessageLoopThread() has already been called. | 331 // Check to see if CancelOnMessageLoopThreadOrInDestructor() has already been |
| 333 // May happen when code flow reaches here from the PostTask() above. | 332 // called. May happen when code flow reaches here from the PostTask() above. |
| 334 if (watches_.empty()) { | 333 if (watches_.empty()) { |
| 335 DCHECK(target_.empty()); | 334 DCHECK(target_.empty()); |
| 336 return; | 335 return; |
| 337 } | 336 } |
| 338 | 337 |
| 339 DCHECK(MessageLoopForIO::current()); | 338 DCHECK(MessageLoopForIO::current()); |
| 340 DCHECK(HasValidWatchVector()); | 339 DCHECK(HasValidWatchVector()); |
| 341 | 340 |
| 342 // Used below to avoid multiple recursive updates. | 341 // Used below to avoid multiple recursive updates. |
| 343 bool did_update = false; | 342 bool did_update = false; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 return true; | 437 return true; |
| 439 } | 438 } |
| 440 | 439 |
| 441 void FilePathWatcherImpl::Cancel() { | 440 void FilePathWatcherImpl::Cancel() { |
| 442 if (callback_.is_null()) { | 441 if (callback_.is_null()) { |
| 443 // Watch was never called, or the message_loop() thread is already gone. | 442 // Watch was never called, or the message_loop() thread is already gone. |
| 444 set_cancelled(); | 443 set_cancelled(); |
| 445 return; | 444 return; |
| 446 } | 445 } |
| 447 | 446 |
| 448 // Switch to the message_loop() if necessary so we can access |watches_|. | 447 // Switch to the task_runner() if necessary so we can access |watches_|. |
| 449 if (!task_runner()->BelongsToCurrentThread()) { | 448 if (!task_runner()->BelongsToCurrentThread()) { |
| 450 task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch, | 449 task_runner()->PostTask( |
| 451 make_scoped_refptr(this))); | 450 FROM_HERE, |
| 451 Bind(&FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor, |
| 452 this)); |
| 452 } else { | 453 } else { |
| 453 CancelOnMessageLoopThread(); | 454 CancelOnMessageLoopThreadOrInDestructor(); |
| 454 } | 455 } |
| 455 } | 456 } |
| 456 | 457 |
| 457 void FilePathWatcherImpl::CancelOnMessageLoopThread() { | |
| 458 CancelOnMessageLoopThreadOrInDestructor(); | |
| 459 } | |
| 460 | |
| 461 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() { | 458 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() { |
| 462 DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread()); | 459 DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread()); |
| 463 | 460 |
| 464 if (is_cancelled()) | 461 if (is_cancelled()) |
| 465 return; | 462 return; |
| 466 | 463 |
| 467 set_cancelled(); | 464 set_cancelled(); |
| 468 | 465 |
| 469 if (!callback_.is_null()) | 466 if (!callback_.is_null()) |
| 470 callback_.Reset(); | 467 callback_.Reset(); |
| 471 | 468 |
| 472 for (size_t i = 0; i < watches_.size(); ++i) | 469 for (size_t i = 0; i < watches_.size(); ++i) |
| 473 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this); | 470 g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this); |
| 474 watches_.clear(); | 471 watches_.clear(); |
| 475 target_.clear(); | 472 target_.clear(); |
| 476 | 473 |
| 477 if (recursive_) | 474 if (recursive_) |
| 478 RemoveRecursiveWatches(); | 475 RemoveRecursiveWatches(); |
| 479 } | 476 } |
| 480 | 477 |
| 481 void FilePathWatcherImpl::UpdateWatches() { | 478 void FilePathWatcherImpl::UpdateWatches() { |
| 482 // Ensure this runs on the message_loop() exclusively in order to avoid | 479 // Ensure this runs on the task_runner() exclusively in order to avoid |
| 483 // concurrency issues. | 480 // concurrency issues. |
| 484 DCHECK(task_runner()->BelongsToCurrentThread()); | 481 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 485 DCHECK(HasValidWatchVector()); | 482 DCHECK(HasValidWatchVector()); |
| 486 | 483 |
| 487 // Walk the list of watches and update them as we go. | 484 // Walk the list of watches and update them as we go. |
| 488 FilePath path(FILE_PATH_LITERAL("/")); | 485 FilePath path(FILE_PATH_LITERAL("/")); |
| 489 for (size_t i = 0; i < watches_.size(); ++i) { | 486 for (size_t i = 0; i < watches_.size(); ++i) { |
| 490 WatchEntry& watch_entry = watches_[i]; | 487 WatchEntry& watch_entry = watches_[i]; |
| 491 InotifyReader::Watch old_watch = watch_entry.watch; | 488 InotifyReader::Watch old_watch = watch_entry.watch; |
| 492 watch_entry.watch = InotifyReader::kInvalidWatch; | 489 watch_entry.watch = InotifyReader::kInvalidWatch; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 return watches_.back().subdir.empty(); | 654 return watches_.back().subdir.empty(); |
| 658 } | 655 } |
| 659 | 656 |
| 660 } // namespace | 657 } // namespace |
| 661 | 658 |
| 662 FilePathWatcher::FilePathWatcher() { | 659 FilePathWatcher::FilePathWatcher() { |
| 663 impl_ = new FilePathWatcherImpl(); | 660 impl_ = new FilePathWatcherImpl(); |
| 664 } | 661 } |
| 665 | 662 |
| 666 } // namespace base | 663 } // namespace base |
| OLD | NEW |