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

Side by Side Diff: content/common/file_path_watcher/file_path_watcher_inotify.cc

Issue 6670081: Move FilePathWatcher class from browser/... to common/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix up linux clang issue, and clean up bad commented block Created 9 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/file_path_watcher/file_path_watcher.h" 5 #include "content/common/file_path_watcher/file_path_watcher.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <string.h> 8 #include <string.h>
9 #include <sys/inotify.h> 9 #include <sys/inotify.h>
10 #include <sys/ioctl.h> 10 #include <sys/ioctl.h>
11 #include <sys/select.h> 11 #include <sys/select.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <set> 15 #include <set>
16 #include <utility> 16 #include <utility>
17 #include <vector> 17 #include <vector>
18 18
19 #include "base/eintr_wrapper.h" 19 #include "base/eintr_wrapper.h"
20 #include "base/file_path.h" 20 #include "base/file_path.h"
21 #include "base/file_util.h" 21 #include "base/file_util.h"
22 #include "base/hash_tables.h" 22 #include "base/hash_tables.h"
23 #include "base/lazy_instance.h" 23 #include "base/lazy_instance.h"
24 #include "base/logging.h" 24 #include "base/logging.h"
25 #include "base/message_loop.h" 25 #include "base/message_loop.h"
26 #include "base/message_loop_proxy.h"
26 #include "base/scoped_ptr.h" 27 #include "base/scoped_ptr.h"
27 #include "base/synchronization/lock.h" 28 #include "base/synchronization/lock.h"
28 #include "base/task.h" 29 #include "base/task.h"
29 #include "base/threading/thread.h" 30 #include "base/threading/thread.h"
30 31
31 namespace { 32 namespace {
32 33
33 class FilePathWatcherImpl; 34 class FilePathWatcherImpl;
34 35
35 // Singleton to manage all inotify watches. 36 // Singleton to manage all inotify watches.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 // the currently watched path for |fired_watch|. The flag |created| is true if 89 // the currently watched path for |fired_watch|. The flag |created| is true if
89 // the object appears, and |is_directory| is set when the event refers to a 90 // the object appears, and |is_directory| is set when the event refers to a
90 // directory. 91 // directory.
91 void OnFilePathChanged(InotifyReader::Watch fired_watch, 92 void OnFilePathChanged(InotifyReader::Watch fired_watch,
92 const FilePath::StringType& child, 93 const FilePath::StringType& child,
93 bool created, 94 bool created,
94 bool is_directory); 95 bool is_directory);
95 96
96 // Start watching |path| for changes and notify |delegate| on each change. 97 // Start watching |path| for changes and notify |delegate| on each change.
97 // Returns true if watch for |path| has been added successfully. 98 // Returns true if watch for |path| has been added successfully.
98 virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate); 99 virtual bool Watch(const FilePath& path,
100 FilePathWatcher::Delegate* delegate,
101 base::MessageLoopProxy* loop) OVERRIDE;
99 102
100 // Cancel the watch. This unregisters the instance with InotifyReader. 103 // Cancel the watch. This unregisters the instance with InotifyReader.
101 virtual void Cancel(); 104 virtual void Cancel() OVERRIDE;
102 105
103 private: 106 private:
104 virtual ~FilePathWatcherImpl() {} 107 virtual ~FilePathWatcherImpl() {}
105 108
106 // Inotify watches are installed for all directory components of |target_|. A 109 // Inotify watches are installed for all directory components of |target_|. A
107 // WatchEntry instance holds the watch descriptor for a component and the 110 // WatchEntry instance holds the watch descriptor for a component and the
108 // subdirectory for that identifies the next component. 111 // subdirectory for that identifies the next component.
109 struct WatchEntry { 112 struct WatchEntry {
110 WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir) 113 WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
111 : watch_(watch), 114 : watch_(watch),
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 void InotifyReader::OnInotifyEvent(const inotify_event* event) { 276 void InotifyReader::OnInotifyEvent(const inotify_event* event) {
274 if (event->mask & IN_IGNORED) 277 if (event->mask & IN_IGNORED)
275 return; 278 return;
276 279
277 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); 280 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
278 base::AutoLock auto_lock(lock_); 281 base::AutoLock auto_lock(lock_);
279 282
280 for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); 283 for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
281 watcher != watchers_[event->wd].end(); 284 watcher != watchers_[event->wd].end();
282 ++watcher) { 285 ++watcher) {
283 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 286 (*watcher)->OnFilePathChanged(event->wd,
284 NewRunnableMethod(*watcher, 287 child,
285 &FilePathWatcherImpl::OnFilePathChanged, 288 event->mask & (IN_CREATE | IN_MOVED_TO),
286 event->wd, 289 event->mask & IN_ISDIR);
287 child,
288 event->mask & (IN_CREATE | IN_MOVED_TO),
289 event->mask & IN_ISDIR));
290 } 290 }
291 } 291 }
292 292
293 FilePathWatcherImpl::FilePathWatcherImpl() 293 FilePathWatcherImpl::FilePathWatcherImpl()
294 : delegate_(NULL) { 294 : delegate_(NULL) {
295 } 295 }
296 296
297 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, 297 void FilePathWatcherImpl::OnFilePathChanged(
298 const FilePath::StringType& child, 298 InotifyReader::Watch fired_watch,
299 bool created, 299 const FilePath::StringType& child,
300 bool is_directory) { 300 bool created,
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 301 bool is_directory) {
302
303 if (!message_loop()->BelongsToCurrentThread()) {
304 // Switch to message_loop_ to access watches_ safely.
305 message_loop()->PostTask(FROM_HERE,
306 NewRunnableMethod(this,
307 &FilePathWatcherImpl::OnFilePathChanged,
308 fired_watch,
309 child,
310 created,
311 is_directory));
312 return;
313 }
314
315 DCHECK(MessageLoopForIO::current());
302 316
303 // Find the entry in |watches_| that corresponds to |fired_watch|. 317 // Find the entry in |watches_| that corresponds to |fired_watch|.
304 WatchVector::const_iterator watch_entry(watches_.begin()); 318 WatchVector::const_iterator watch_entry(watches_.begin());
305 for ( ; watch_entry != watches_.end(); ++watch_entry) { 319 for ( ; watch_entry != watches_.end(); ++watch_entry) {
306 if (fired_watch == watch_entry->watch_) 320 if (fired_watch == watch_entry->watch_)
307 break; 321 break;
308 } 322 }
309 323
310 // If this notification is from a previous generation of watches or the watch 324 // If this notification is from a previous generation of watches or the watch
311 // has been cancelled (|watches_| is empty then), bail out. 325 // has been cancelled (|watches_| is empty then), bail out.
(...skipping 22 matching lines...) Expand all
334 // - One of the parent directories appears. The event corresponding to the 348 // - One of the parent directories appears. The event corresponding to the
335 // target appearing might have been missed in this case, so recheck. 349 // target appearing might have been missed in this case, so recheck.
336 if (target_changed || 350 if (target_changed ||
337 (change_on_target_path && !created) || 351 (change_on_target_path && !created) ||
338 (change_on_target_path && file_util::PathExists(target_))) { 352 (change_on_target_path && file_util::PathExists(target_))) {
339 delegate_->OnFilePathChanged(target_); 353 delegate_->OnFilePathChanged(target_);
340 } 354 }
341 } 355 }
342 356
343 bool FilePathWatcherImpl::Watch(const FilePath& path, 357 bool FilePathWatcherImpl::Watch(const FilePath& path,
344 FilePathWatcher::Delegate* delegate) { 358 FilePathWatcher::Delegate* delegate,
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 359 base::MessageLoopProxy*) {
346 DCHECK(target_.empty()); 360 DCHECK(target_.empty());
361 DCHECK(MessageLoopForIO::current());
347 362
363 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread());
348 delegate_ = delegate; 364 delegate_ = delegate;
349 target_ = path; 365 target_ = path;
350 std::vector<FilePath::StringType> comps; 366 std::vector<FilePath::StringType> comps;
351 target_.GetComponents(&comps); 367 target_.GetComponents(&comps);
352 DCHECK(!comps.empty()); 368 DCHECK(!comps.empty());
353 for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin()); 369 for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin());
354 comp != comps.end(); ++comp) { 370 comp != comps.end(); ++comp) {
355 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp)); 371 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
356 } 372 }
357 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, 373 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
358 FilePath::StringType())); 374 FilePath::StringType()));
359 return UpdateWatches(); 375 return UpdateWatches();
360 } 376 }
361 377
362 void FilePathWatcherImpl::Cancel() { 378 void FilePathWatcherImpl::Cancel() {
363 // Switch to the file thread if necessary so we can access |watches_|. 379 if (!message_loop().get()) {
364 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 380 // Watch was never called, so exit.
365 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 381 return;
382 }
383
384 // Switch to the message_loop_ if necessary so we can access |watches_|.
385 if (!message_loop()->BelongsToCurrentThread()) {
386 message_loop()->PostTask(FROM_HERE,
366 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel)); 387 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
367 return; 388 return;
368 } 389 }
369 390
370 for (WatchVector::iterator watch_entry(watches_.begin()); 391 for (WatchVector::iterator watch_entry(watches_.begin());
371 watch_entry != watches_.end(); ++watch_entry) { 392 watch_entry != watches_.end(); ++watch_entry) {
372 if (watch_entry->watch_ != InotifyReader::kInvalidWatch) 393 if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
373 g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this); 394 g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this);
374 } 395 }
375 watches_.clear(); 396 watches_.clear();
376 delegate_ = NULL; 397 delegate_ = NULL;
377 target_.clear(); 398 target_.clear();
378 } 399 }
379 400
380 bool FilePathWatcherImpl::UpdateWatches() { 401 bool FilePathWatcherImpl::UpdateWatches() {
381 // Ensure this runs on the file thread exclusively in order to avoid 402 // Ensure this runs on the message_loop_ exclusively in order to avoid
382 // concurrency issues. 403 // concurrency issues.
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 404 DCHECK(message_loop()->BelongsToCurrentThread());
384 405
385 // Walk the list of watches and update them as we go. 406 // Walk the list of watches and update them as we go.
386 FilePath path(FILE_PATH_LITERAL("/")); 407 FilePath path(FILE_PATH_LITERAL("/"));
387 bool path_valid = true; 408 bool path_valid = true;
388 for (WatchVector::iterator watch_entry(watches_.begin()); 409 for (WatchVector::iterator watch_entry(watches_.begin());
389 watch_entry != watches_.end(); ++watch_entry) { 410 watch_entry != watches_.end(); ++watch_entry) {
390 InotifyReader::Watch old_watch = watch_entry->watch_; 411 InotifyReader::Watch old_watch = watch_entry->watch_;
391 if (path_valid) { 412 if (path_valid) {
392 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this); 413 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
393 if (watch_entry->watch_ == InotifyReader::kInvalidWatch) { 414 if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
(...skipping 10 matching lines...) Expand all
404 } 425 }
405 426
406 return true; 427 return true;
407 } 428 }
408 429
409 } // namespace 430 } // namespace
410 431
411 FilePathWatcher::FilePathWatcher() { 432 FilePathWatcher::FilePathWatcher() {
412 impl_ = new FilePathWatcherImpl(); 433 impl_ = new FilePathWatcherImpl();
413 } 434 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698