| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 | 59 |
| 60 // Callback for InotifyReaderTask. | 60 // Callback for InotifyReaderTask. |
| 61 void OnInotifyEvent(const inotify_event* event); | 61 void OnInotifyEvent(const inotify_event* event); |
| 62 | 62 |
| 63 private: | 63 private: |
| 64 friend struct DefaultLazyInstanceTraits<InotifyReader>; | 64 friend struct DefaultLazyInstanceTraits<InotifyReader>; |
| 65 | 65 |
| 66 typedef std::set<FilePathWatcherImpl*> WatcherSet; | 66 typedef std::set<FilePathWatcherImpl*> WatcherSet; |
| 67 | 67 |
| 68 InotifyReader(); | 68 InotifyReader(); |
| 69 ~InotifyReader(); | 69 // There is no destructor because |g_inotify_reader| is a |
| 70 // base::LazyInstace::Leaky object. Having a destructor causes build |
| 71 // issues with GCC 6 (http://crbug.com/636346). |
| 70 | 72 |
| 71 // We keep track of which delegates want to be notified on which watches. | 73 // We keep track of which delegates want to be notified on which watches. |
| 72 hash_map<Watch, WatcherSet> watchers_; | 74 hash_map<Watch, WatcherSet> watchers_; |
| 73 | 75 |
| 74 // Lock to protect watchers_. | 76 // Lock to protect watchers_. |
| 75 Lock lock_; | 77 Lock lock_; |
| 76 | 78 |
| 77 // Separate thread on which we run blocking read for inotify events. | 79 // Separate thread on which we run blocking read for inotify events. |
| 78 Thread thread_; | 80 Thread thread_; |
| 79 | 81 |
| 80 // File descriptor returned by inotify_init. | 82 // File descriptor returned by inotify_init. |
| 81 const int inotify_fd_; | 83 const int inotify_fd_; |
| 82 | 84 |
| 83 // Use self-pipe trick to unblock select during shutdown. | |
| 84 int shutdown_pipe_[2]; | |
| 85 | |
| 86 // Flag set to true when startup was successful. | 85 // Flag set to true when startup was successful. |
| 87 bool valid_; | 86 bool valid_; |
| 88 | 87 |
| 89 DISALLOW_COPY_AND_ASSIGN(InotifyReader); | 88 DISALLOW_COPY_AND_ASSIGN(InotifyReader); |
| 90 }; | 89 }; |
| 91 | 90 |
| 92 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, | 91 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
| 93 public MessageLoop::DestructionObserver { | 92 public MessageLoop::DestructionObserver { |
| 94 public: | 93 public: |
| 95 FilePathWatcherImpl(); | 94 FilePathWatcherImpl(); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 // starting at the root directory. The last entry corresponds to the watch for | 186 // starting at the root directory. The last entry corresponds to the watch for |
| 188 // |target_| and always stores an empty next component name in |subdir|. | 187 // |target_| and always stores an empty next component name in |subdir|. |
| 189 WatchVector watches_; | 188 WatchVector watches_; |
| 190 | 189 |
| 191 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; | 190 hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_; |
| 192 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; | 191 std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_; |
| 193 | 192 |
| 194 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); | 193 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); |
| 195 }; | 194 }; |
| 196 | 195 |
| 197 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd, | 196 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd) { |
| 198 int shutdown_fd) { | |
| 199 // Make sure the file descriptors are good for use with select(). | 197 // Make sure the file descriptors are good for use with select(). |
| 200 CHECK_LE(0, inotify_fd); | 198 CHECK_LE(0, inotify_fd); |
| 201 CHECK_GT(FD_SETSIZE, inotify_fd); | 199 CHECK_GT(FD_SETSIZE, inotify_fd); |
| 202 CHECK_LE(0, shutdown_fd); | |
| 203 CHECK_GT(FD_SETSIZE, shutdown_fd); | |
| 204 | 200 |
| 205 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); | 201 trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); |
| 206 | 202 |
| 207 while (true) { | 203 while (true) { |
| 208 fd_set rfds; | 204 fd_set rfds; |
| 209 FD_ZERO(&rfds); | 205 FD_ZERO(&rfds); |
| 210 FD_SET(inotify_fd, &rfds); | 206 FD_SET(inotify_fd, &rfds); |
| 211 FD_SET(shutdown_fd, &rfds); | |
| 212 | 207 |
| 213 // Wait until some inotify events are available. | 208 // Wait until some inotify events are available. |
| 214 int select_result = | 209 int select_result = |
| 215 HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1, | 210 HANDLE_EINTR(select(inotify_fd + 1, &rfds, NULL, NULL, NULL)); |
| 216 &rfds, NULL, NULL, NULL)); | |
| 217 if (select_result < 0) { | 211 if (select_result < 0) { |
| 218 DPLOG(WARNING) << "select failed"; | 212 DPLOG(WARNING) << "select failed"; |
| 219 return; | 213 return; |
| 220 } | 214 } |
| 221 | 215 |
| 222 if (FD_ISSET(shutdown_fd, &rfds)) | |
| 223 return; | |
| 224 | |
| 225 // Adjust buffer size to current event queue size. | 216 // Adjust buffer size to current event queue size. |
| 226 int buffer_size; | 217 int buffer_size; |
| 227 int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD, | 218 int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD, |
| 228 &buffer_size)); | 219 &buffer_size)); |
| 229 | 220 |
| 230 if (ioctl_result != 0) { | 221 if (ioctl_result != 0) { |
| 231 DPLOG(WARNING) << "ioctl failed"; | 222 DPLOG(WARNING) << "ioctl failed"; |
| 232 return; | 223 return; |
| 233 } | 224 } |
| 234 | 225 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 256 static LazyInstance<InotifyReader>::Leaky g_inotify_reader = | 247 static LazyInstance<InotifyReader>::Leaky g_inotify_reader = |
| 257 LAZY_INSTANCE_INITIALIZER; | 248 LAZY_INSTANCE_INITIALIZER; |
| 258 | 249 |
| 259 InotifyReader::InotifyReader() | 250 InotifyReader::InotifyReader() |
| 260 : thread_("inotify_reader"), | 251 : thread_("inotify_reader"), |
| 261 inotify_fd_(inotify_init()), | 252 inotify_fd_(inotify_init()), |
| 262 valid_(false) { | 253 valid_(false) { |
| 263 if (inotify_fd_ < 0) | 254 if (inotify_fd_ < 0) |
| 264 PLOG(ERROR) << "inotify_init() failed"; | 255 PLOG(ERROR) << "inotify_init() failed"; |
| 265 | 256 |
| 266 shutdown_pipe_[0] = -1; | 257 if (inotify_fd_ >= 0 && thread_.Start()) { |
| 267 shutdown_pipe_[1] = -1; | |
| 268 if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { | |
| 269 thread_.task_runner()->PostTask( | 258 thread_.task_runner()->PostTask( |
| 270 FROM_HERE, | 259 FROM_HERE, |
| 271 Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0])); | 260 Bind(&InotifyReaderCallback, this, inotify_fd_)); |
| 272 valid_ = true; | 261 valid_ = true; |
| 273 } | 262 } |
| 274 } | 263 } |
| 275 | 264 |
| 276 InotifyReader::~InotifyReader() { | |
| 277 if (valid_) { | |
| 278 // Write to the self-pipe so that the select call in InotifyReaderTask | |
| 279 // returns. | |
| 280 ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); | |
| 281 DPCHECK(ret > 0); | |
| 282 DCHECK_EQ(ret, 1); | |
| 283 thread_.Stop(); | |
| 284 } | |
| 285 if (inotify_fd_ >= 0) | |
| 286 close(inotify_fd_); | |
| 287 if (shutdown_pipe_[0] >= 0) | |
| 288 close(shutdown_pipe_[0]); | |
| 289 if (shutdown_pipe_[1] >= 0) | |
| 290 close(shutdown_pipe_[1]); | |
| 291 } | |
| 292 | |
| 293 InotifyReader::Watch InotifyReader::AddWatch( | 265 InotifyReader::Watch InotifyReader::AddWatch( |
| 294 const FilePath& path, FilePathWatcherImpl* watcher) { | 266 const FilePath& path, FilePathWatcherImpl* watcher) { |
| 295 if (!valid_) | 267 if (!valid_) |
| 296 return kInvalidWatch; | 268 return kInvalidWatch; |
| 297 | 269 |
| 298 AutoLock auto_lock(lock_); | 270 AutoLock auto_lock(lock_); |
| 299 | 271 |
| 300 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), | 272 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), |
| 301 IN_ATTRIB | IN_CREATE | IN_DELETE | | 273 IN_ATTRIB | IN_CREATE | IN_DELETE | |
| 302 IN_CLOSE_WRITE | IN_MOVE | | 274 IN_CLOSE_WRITE | IN_MOVE | |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 return watches_.back().subdir.empty(); | 652 return watches_.back().subdir.empty(); |
| 681 } | 653 } |
| 682 | 654 |
| 683 } // namespace | 655 } // namespace |
| 684 | 656 |
| 685 FilePathWatcher::FilePathWatcher() { | 657 FilePathWatcher::FilePathWatcher() { |
| 686 impl_ = new FilePathWatcherImpl(); | 658 impl_ = new FilePathWatcherImpl(); |
| 687 } | 659 } |
| 688 | 660 |
| 689 } // namespace base | 661 } // namespace base |
| OLD | NEW |